[tint][ir] Rename names going from IR to Program.

When converting from IR to Program, re-write any name which may conflict
with a WGSL keyword, reserved word, type name or enum name.

Bug: 42250952
Change-Id: I4c9c925ef25d506e697b7e3e61261f5ab3662c05
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/232894
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/wgsl/common/BUILD.bazel b/src/tint/lang/wgsl/common/BUILD.bazel
index 192bd28..2cea2a8 100644
--- a/src/tint/lang/wgsl/common/BUILD.bazel
+++ b/src/tint/lang/wgsl/common/BUILD.bazel
@@ -40,9 +40,11 @@
   name = "common",
   srcs = [
     "common.cc",
+    "reserved_words.cc",
   ],
   hdrs = [
     "allowed_features.h",
+    "reserved_words.h",
   ],
   deps = [
     "//src/tint/lang/wgsl",
diff --git a/src/tint/lang/wgsl/common/BUILD.cmake b/src/tint/lang/wgsl/common/BUILD.cmake
index bc0e4cf..2a2784c 100644
--- a/src/tint/lang/wgsl/common/BUILD.cmake
+++ b/src/tint/lang/wgsl/common/BUILD.cmake
@@ -41,6 +41,8 @@
 tint_add_target(tint_lang_wgsl_common lib
   lang/wgsl/common/allowed_features.h
   lang/wgsl/common/common.cc
+  lang/wgsl/common/reserved_words.cc
+  lang/wgsl/common/reserved_words.h
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_common lib
diff --git a/src/tint/lang/wgsl/common/BUILD.gn b/src/tint/lang/wgsl/common/BUILD.gn
index 3981b0b..f2fb1d9 100644
--- a/src/tint/lang/wgsl/common/BUILD.gn
+++ b/src/tint/lang/wgsl/common/BUILD.gn
@@ -47,6 +47,8 @@
   sources = [
     "allowed_features.h",
     "common.cc",
+    "reserved_words.cc",
+    "reserved_words.h",
   ]
   deps = [
     "${dawn_root}/src/utils:utils",
diff --git a/src/tint/lang/wgsl/common/reserved_words.cc b/src/tint/lang/wgsl/common/reserved_words.cc
new file mode 100644
index 0000000..d41c757
--- /dev/null
+++ b/src/tint/lang/wgsl/common/reserved_words.cc
@@ -0,0 +1,67 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/common/reserved_words.h"
+
+namespace tint::wgsl {
+
+bool IsReserved(std::string_view s) {
+    return s == "NULL" || s == "Self" || s == "abstract" || s == "active" || s == "alignas" ||
+           s == "alignof" || s == "as" || s == "asm" || s == "asm_fragment" || s == "async" ||
+           s == "attribute" || s == "auto" || s == "await" || s == "become" || s == "cast" ||
+           s == "catch" || s == "class" || s == "co_await" || s == "co_return" || s == "co_yield" ||
+           s == "coherent" || s == "column_major" || s == "common" || s == "compile" ||
+           s == "compile_fragment" || s == "concept" || s == "const_cast" || s == "consteval" ||
+           s == "constexpr" || s == "constinit" || s == "crate" || s == "debugger" ||
+           s == "decltype" || s == "delete" || s == "demote" || s == "demote_to_helper" ||
+           s == "do" || s == "dynamic_cast" || s == "enum" || s == "explicit" || s == "export" ||
+           s == "extends" || s == "extern" || s == "external" || s == "fallthrough" ||
+           s == "filter" || s == "final" || s == "finally" || s == "friend" || s == "from" ||
+           s == "fxgroup" || s == "get" || s == "goto" || s == "groupshared" || s == "highp" ||
+           s == "impl" || s == "implements" || s == "import" || s == "inline" ||
+           s == "instanceof" || s == "interface" || s == "layout" || s == "lowp" || s == "macro" ||
+           s == "macro_rules" || s == "match" || s == "mediump" || s == "meta" || s == "mod" ||
+           s == "module" || s == "move" || s == "mut" || s == "mutable" || s == "namespace" ||
+           s == "new" || s == "nil" || s == "noexcept" || s == "noinline" ||
+           s == "nointerpolation" || s == "non_coherent" || s == "noncoherent" ||
+           s == "noperspective" || s == "null" || s == "nullptr" || s == "of" || s == "operator" ||
+           s == "package" || s == "packoffset" || s == "partition" || s == "pass" || s == "patch" ||
+           s == "pixelfragment" || s == "precise" || s == "precision" || s == "premerge" ||
+           s == "priv" || s == "protected" || s == "pub" || s == "public" || s == "readonly" ||
+           s == "ref" || s == "regardless" || s == "register" || s == "reinterpret_cast" ||
+           s == "require" || s == "resource" || s == "restrict" || s == "self" || s == "set" ||
+           s == "shared" || s == "sizeof" || s == "smooth" || s == "snorm" || s == "static" ||
+           s == "static_assert" || s == "static_cast" || s == "std" || s == "subroutine" ||
+           s == "super" || s == "target" || s == "template" || s == "this" || s == "thread_local" ||
+           s == "throw" || s == "trait" || s == "try" || s == "type" || s == "typedef" ||
+           s == "typeid" || s == "typename" || s == "typeof" || s == "union" || s == "unless" ||
+           s == "unorm" || s == "unsafe" || s == "unsized" || s == "use" || s == "using" ||
+           s == "varying" || s == "virtual" || s == "volatile" || s == "wgsl" || s == "where" ||
+           s == "with" || s == "writeonly" || s == "yield";
+}
+
+}  // namespace tint::wgsl
diff --git a/src/tint/lang/wgsl/common/reserved_words.h b/src/tint/lang/wgsl/common/reserved_words.h
new file mode 100644
index 0000000..900dbf4
--- /dev/null
+++ b/src/tint/lang/wgsl/common/reserved_words.h
@@ -0,0 +1,40 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_COMMON_RESERVED_WORDS_H_
+#define SRC_TINT_LANG_WGSL_COMMON_RESERVED_WORDS_H_
+
+#include <string_view>
+
+namespace tint::wgsl {
+
+// https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
+bool IsReserved(std::string_view s);
+
+}  // namespace tint::wgsl
+
+#endif  // SRC_TINT_LANG_WGSL_COMMON_RESERVED_WORDS_H_
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index 1b56eb1..a6bed34 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -55,6 +55,7 @@
 #include "src/tint/lang/wgsl/ast/var.h"
 #include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
 #include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
+#include "src/tint/lang/wgsl/common/reserved_words.h"
 #include "src/tint/lang/wgsl/reader/parser/classify_template_args.h"
 #include "src/tint/lang/wgsl/reader/parser/lexer.h"
 #include "src/tint/utils/containers/reverse.h"
@@ -86,45 +87,6 @@
 /// parser on error.
 constexpr size_t const kMaxResynchronizeLookahead = 32;
 
-// https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
-//
-// Must be called with an identifier token.
-bool is_reserved(const Token& t) {
-    auto s = t.to_str_view();
-    return s == "NULL" || s == "Self" || s == "abstract" || s == "active" || s == "alignas" ||
-           s == "alignof" || s == "as" || s == "asm" || s == "asm_fragment" || s == "async" ||
-           s == "attribute" || s == "auto" || s == "await" || s == "become" || s == "cast" ||
-           s == "catch" || s == "class" || s == "co_await" || s == "co_return" || s == "co_yield" ||
-           s == "coherent" || s == "column_major" || s == "common" || s == "compile" ||
-           s == "compile_fragment" || s == "concept" || s == "const_cast" || s == "consteval" ||
-           s == "constexpr" || s == "constinit" || s == "crate" || s == "debugger" ||
-           s == "decltype" || s == "delete" || s == "demote" || s == "demote_to_helper" ||
-           s == "do" || s == "dynamic_cast" || s == "enum" || s == "explicit" || s == "export" ||
-           s == "extends" || s == "extern" || s == "external" || s == "filter" || s == "final" ||
-           s == "finally" || s == "friend" || s == "from" || s == "fxgroup" || s == "get" ||
-           s == "goto" || s == "groupshared" || s == "highp" || s == "impl" || s == "implements" ||
-           s == "import" || s == "inline" || s == "instanceof" || s == "interface" ||
-           s == "layout" || s == "lowp" || s == "macro" || s == "macro_rules" || s == "match" ||
-           s == "mediump" || s == "meta" || s == "mod" || s == "module" || s == "move" ||
-           s == "mut" || s == "mutable" || s == "namespace" || s == "new" || s == "nil" ||
-           s == "noexcept" || s == "noinline" || s == "nointerpolation" || s == "non_coherent" ||
-           s == "noncoherent" || s == "noperspective" || s == "null" || s == "nullptr" ||
-           s == "of" || s == "operator" || s == "package" || s == "packoffset" ||
-           s == "partition" || s == "pass" || s == "patch" || s == "pixelfragment" ||
-           s == "precise" || s == "precision" || s == "premerge" || s == "priv" ||
-           s == "protected" || s == "pub" || s == "public" || s == "readonly" || s == "ref" ||
-           s == "regardless" || s == "register" || s == "reinterpret_cast" || s == "require" ||
-           s == "resource" || s == "restrict" || s == "self" || s == "set" || s == "shared" ||
-           s == "sizeof" || s == "smooth" || s == "snorm" || s == "static" ||
-           s == "static_assert" || s == "static_cast" || s == "std" || s == "subroutine" ||
-           s == "super" || s == "target" || s == "template" || s == "this" || s == "thread_local" ||
-           s == "throw" || s == "trait" || s == "try" || s == "type" || s == "typedef" ||
-           s == "typeid" || s == "typename" || s == "typeof" || s == "union" || s == "unless" ||
-           s == "unorm" || s == "unsafe" || s == "unsized" || s == "use" || s == "using" ||
-           s == "varying" || s == "virtual" || s == "volatile" || s == "wgsl" || s == "where" ||
-           s == "with" || s == "writeonly" || s == "yield";
-}
-
 /// Enter-exit counters for block token types.
 /// Used by sync_to() to skip over closing block tokens that were opened during
 /// the forward scan.
@@ -3408,7 +3370,7 @@
         synchronized_ = true;
         next();
 
-        if (is_reserved(t)) {
+        if (IsReserved(t.to_str_view())) {
             return AddError(t.source(), "'" + t.to_str() + "' is a reserved keyword");
         }
 
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 50ebb10..7baddd0 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -83,6 +83,7 @@
 #include "src/tint/lang/core/type/texture.h"
 #include "src/tint/lang/core/type/type.h"
 #include "src/tint/lang/wgsl/ast/type.h"
+#include "src/tint/lang/wgsl/common/reserved_words.h"
 #include "src/tint/lang/wgsl/ir/builtin_call.h"
 #include "src/tint/lang/wgsl/ir/unary.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
@@ -1158,15 +1159,63 @@
     // Bindings
     ////////////////////////////////////////////////////////////////////////////////////////////////
 
+    bool IsKeyword(std::string_view s) {
+        return s == "alias" || s == "break" || s == "case" || s == "const" || s == "const_assert" ||
+               s == "continue" || s == "continuing" || s == "default" || s == "diagnostic" ||
+               s == "discard" || s == "else" || s == "enable" || s == "false" || s == "fn" ||
+               s == "for" || s == "if" || s == "let" || s == "loop" || s == "override" ||
+               s == "requires" || s == "return" || s == "struct" || s == "switch" || s == "true" ||
+               s == "var" || s == "while";
+    }
+
+    bool IsEnumName(std::string_view s) {
+        return s == "read" || s == "write" || s == "read_write" || s == "function" ||
+               s == "private" || s == "workgroup" || s == "uniform" || s == "storage" ||
+               s == "rgba8unorm" || s == "rgba8snorm" || s == "rgba8uint" || s == "rgba8sint" ||
+               s == "rgba16uint" || s == "rgba16sint" || s == "rgba16float" || s == "r32uint" ||
+               s == "r32sint" || s == "r32float" || s == "rg32uint" || s == "rg32sint" ||
+               s == "rg32float" || s == "rgba32uint" || s == "rgba32sint" || s == "rgba32float" ||
+               s == "bgra8unorm";
+    }
+
+    bool IsTypeName(std::string_view s) {
+        return s == "bool" || s == "void" || s == "i32" || s == "u32" || s == "f32" || s == "f16" ||
+               s == "vec" || s == "vec2" || s == "vec3" || s == "vec4" || s == "vec2f" ||
+               s == "vec3f" || s == "vec4f" || s == "vec2h" || s == "vec3h" || s == "vec4h" ||
+               s == "vec2i" || s == "vec3i" || s == "vec4i" || s == "vec2u" || s == "vec3u" ||
+               s == "vec4u" || s == "mat2x2" || s == "mat2x3" || s == "mat2x4" || s == "mat3x2" ||
+               s == "mat3x3" || s == "mat3x4" || s == "mat4x2" || s == "mat4x3" || s == "mat4x4" ||
+               s == "mat2x2f" || s == "mat2x3f" || s == "mat2x4f" || s == "mat3x2f" ||
+               s == "mat3x3f" || s == "mat3x4f" || s == "mat4x2f" || s == "mat4x3f" ||
+               s == "mat4x4f" || s == "mat2x2h" || s == "mat2x3h" || s == "mat2x4h" ||
+               s == "mat3x2h" || s == "mat3x3h" || s == "mat3x4h" || s == "mat4x2h" ||
+               s == "mat4x3h" || s == "mat4x4h" || s == "atomic" || s == "array" || s == "ptr" ||
+               s == "texture_1d" || s == "texture_2d" || s == "texture_2d_array" ||
+               s == "texture_3d" || s == "texture_cube" || s == "texture_cube_array" ||
+               s == "texture_multisampled_2d" || s == "texture_depth_multisampled_2d" ||
+               s == "texture_external" || s == "texture_storage_1d" || s == "texture_storage_2d" ||
+               s == "texture_storage_2d_array" || s == "texture_storage_3d" ||
+               s == "texture_depth_2d" || s == "texture_depth_2d_array" ||
+               s == "texture_depth_cube" || s == "texture_depth_cube_array" || s == "sampler" ||
+               s == "sampler_comparison";
+    }
+
+    bool IsWGSLSafe(std::string_view name) {
+        return !IsReserved(name) && !IsKeyword(name) && !IsEnumName(name) && !IsTypeName(name);
+    }
+
     /// @returns the AST name for the given value, creating and returning a new name on the first
     /// call.
     Symbol NameFor(const core::ir::Value* value, std::string_view suggested = {}) {
         return names_.GetOrAdd(value, [&] {
             if (!suggested.empty()) {
-                return b.Symbols().Register(suggested);
-            }
-            if (auto sym = mod.NameOf(value)) {
-                return b.Symbols().Register(sym.NameView());
+                if (IsWGSLSafe(suggested)) {
+                    return b.Symbols().Register(suggested);
+                }
+            } else if (auto sym = mod.NameOf(value)) {
+                if (IsWGSLSafe(sym.NameView())) {
+                    return b.Symbols().Register(sym.NameView());
+                }
             }
             return b.Symbols().New("v");
         });
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index abb5f31..9227f10 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -319,6 +319,598 @@
 )");
 }
 
+TEST_F(IRToProgramTest, EnumWords) {
+    auto* fn = b.Function("f", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+
+    b.Append(fn->Block(), [&] {
+        Var("read", true);
+        Var("write", true);
+        Var("read_write", true);
+        Var("function", true);
+        Var("private", true);
+        Var("workgroup", true);
+        Var("uniform", true);
+        Var("storage", true);
+        Var("rgba8unorm", true);
+        Var("rgba8snorm", true);
+        Var("rgba8uint", true);
+        Var("rgba8sint", true);
+        Var("rgba16uint", true);
+        Var("rgba16sint", true);
+        Var("rgba16float", true);
+        Var("r32uint", true);
+        Var("r32sint", true);
+        Var("r32float", true);
+        Var("rg32uint", true);
+        Var("rg32sint", true);
+        Var("rg32float", true);
+        Var("rgba32uint", true);
+        Var("rgba32sint", true);
+        Var("rgba32float", true);
+        Var("bgra8unorm", true);
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+@fragment
+fn f() {
+  var v : bool = true;
+  var v_1 : bool = true;
+  var v_2 : bool = true;
+  var v_3 : bool = true;
+  var v_4 : bool = true;
+  var v_5 : bool = true;
+  var v_6 : bool = true;
+  var v_7 : bool = true;
+  var v_8 : bool = true;
+  var v_9 : bool = true;
+  var v_10 : bool = true;
+  var v_11 : bool = true;
+  var v_12 : bool = true;
+  var v_13 : bool = true;
+  var v_14 : bool = true;
+  var v_15 : bool = true;
+  var v_16 : bool = true;
+  var v_17 : bool = true;
+  var v_18 : bool = true;
+  var v_19 : bool = true;
+  var v_20 : bool = true;
+  var v_21 : bool = true;
+  var v_22 : bool = true;
+  var v_23 : bool = true;
+  var v_24 : bool = true;
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeWords) {
+    auto* fn = b.Function("f", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+
+    b.Append(fn->Block(), [&] {
+        Var("bool", true);
+        Var("void", true);
+        Var("i32", true);
+        Var("u32", true);
+        Var("f32", true);
+        Var("f16", true);
+        Var("vec", true);
+        Var("vec2", true);
+        Var("vec3", true);
+        Var("vec4", true);
+        Var("vec2f", true);
+        Var("vec3f", true);
+        Var("vec4f", true);
+        Var("vec2h", true);
+        Var("vec3h", true);
+        Var("vec4h", true);
+        Var("vec2i", true);
+        Var("vec3i", true);
+        Var("vec4i", true);
+        Var("vec2u", true);
+        Var("vec3u", true);
+        Var("vec4u", true);
+        Var("mat2x2", true);
+        Var("mat2x3", true);
+        Var("mat2x4", true);
+        Var("mat3x2", true);
+        Var("mat3x3", true);
+        Var("mat3x4", true);
+        Var("mat4x2", true);
+        Var("mat4x3", true);
+        Var("mat4x4", true);
+        Var("mat2x2f", true);
+        Var("mat2x3f", true);
+        Var("mat2x4f", true);
+        Var("mat3x2f", true);
+        Var("mat3x3f", true);
+        Var("mat3x4f", true);
+        Var("mat4x2f", true);
+        Var("mat4x3f", true);
+        Var("mat4x4f", true);
+        Var("mat2x2h", true);
+        Var("mat2x3h", true);
+        Var("mat2x4h", true);
+        Var("mat3x2h", true);
+        Var("mat3x3h", true);
+        Var("mat3x4h", true);
+        Var("mat4x2h", true);
+        Var("mat4x3h", true);
+        Var("mat4x4h", true);
+        Var("atomic", true);
+        Var("array", true);
+        Var("ptr", true);
+        Var("texture_1d", true);
+        Var("texture_2d", true);
+        Var("texture_2d_array", true);
+        Var("texture_3d", true);
+        Var("texture_cube", true);
+        Var("texture_cube_array", true);
+        Var("texture_multisampled_2d", true);
+        Var("texture_depth_multisampled_2d", true);
+        Var("texture_external", true);
+        Var("texture_storage_1d", true);
+        Var("texture_storage_2d", true);
+        Var("texture_storage_2d_array", true);
+        Var("texture_storage_3d", true);
+        Var("texture_depth_2d", true);
+        Var("texture_depth_2d_array", true);
+        Var("texture_depth_cube", true);
+        Var("texture_depth_cube_array", true);
+        Var("sampler", true);
+        Var("sampler_comparison", true);
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+@fragment
+fn f() {
+  var v : bool = true;
+  var v_1 : bool = true;
+  var v_2 : bool = true;
+  var v_3 : bool = true;
+  var v_4 : bool = true;
+  var v_5 : bool = true;
+  var v_6 : bool = true;
+  var v_7 : bool = true;
+  var v_8 : bool = true;
+  var v_9 : bool = true;
+  var v_10 : bool = true;
+  var v_11 : bool = true;
+  var v_12 : bool = true;
+  var v_13 : bool = true;
+  var v_14 : bool = true;
+  var v_15 : bool = true;
+  var v_16 : bool = true;
+  var v_17 : bool = true;
+  var v_18 : bool = true;
+  var v_19 : bool = true;
+  var v_20 : bool = true;
+  var v_21 : bool = true;
+  var v_22 : bool = true;
+  var v_23 : bool = true;
+  var v_24 : bool = true;
+  var v_25 : bool = true;
+  var v_26 : bool = true;
+  var v_27 : bool = true;
+  var v_28 : bool = true;
+  var v_29 : bool = true;
+  var v_30 : bool = true;
+  var v_31 : bool = true;
+  var v_32 : bool = true;
+  var v_33 : bool = true;
+  var v_34 : bool = true;
+  var v_35 : bool = true;
+  var v_36 : bool = true;
+  var v_37 : bool = true;
+  var v_38 : bool = true;
+  var v_39 : bool = true;
+  var v_40 : bool = true;
+  var v_41 : bool = true;
+  var v_42 : bool = true;
+  var v_43 : bool = true;
+  var v_44 : bool = true;
+  var v_45 : bool = true;
+  var v_46 : bool = true;
+  var v_47 : bool = true;
+  var v_48 : bool = true;
+  var v_49 : bool = true;
+  var v_50 : bool = true;
+  var v_51 : bool = true;
+  var v_52 : bool = true;
+  var v_53 : bool = true;
+  var v_54 : bool = true;
+  var v_55 : bool = true;
+  var v_56 : bool = true;
+  var v_57 : bool = true;
+  var v_58 : bool = true;
+  var v_59 : bool = true;
+  var v_60 : bool = true;
+  var v_61 : bool = true;
+  var v_62 : bool = true;
+  var v_63 : bool = true;
+  var v_64 : bool = true;
+  var v_65 : bool = true;
+  var v_66 : bool = true;
+  var v_67 : bool = true;
+  var v_68 : bool = true;
+  var v_69 : bool = true;
+  var v_70 : bool = true;
+}
+)");
+}
+
+TEST_F(IRToProgramTest, Keywords) {
+    auto* fn = b.Function("f", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+
+    b.Append(fn->Block(), [&] {
+        Var("alias", true);
+        Var("break", true);
+        Var("case", true);
+        Var("const", true);
+        Var("const_assert", true);
+        Var("continue", true);
+        Var("continuing", true);
+        Var("default", true);
+        Var("diagnostic", true);
+        Var("discard", true);
+        Var("else", true);
+        Var("enable", true);
+        Var("false", true);
+        Var("fn", true);
+        Var("for", true);
+        Var("if", true);
+        Var("let", true);
+        Var("loop", true);
+        Var("override", true);
+        Var("requires", true);
+        Var("return", true);
+        Var("struct", true);
+        Var("switch", true);
+        Var("true", true);
+        Var("var", true);
+        Var("while", true);
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+@fragment
+fn f() {
+  var v : bool = true;
+  var v_1 : bool = true;
+  var v_2 : bool = true;
+  var v_3 : bool = true;
+  var v_4 : bool = true;
+  var v_5 : bool = true;
+  var v_6 : bool = true;
+  var v_7 : bool = true;
+  var v_8 : bool = true;
+  var v_9 : bool = true;
+  var v_10 : bool = true;
+  var v_11 : bool = true;
+  var v_12 : bool = true;
+  var v_13 : bool = true;
+  var v_14 : bool = true;
+  var v_15 : bool = true;
+  var v_16 : bool = true;
+  var v_17 : bool = true;
+  var v_18 : bool = true;
+  var v_19 : bool = true;
+  var v_20 : bool = true;
+  var v_21 : bool = true;
+  var v_22 : bool = true;
+  var v_23 : bool = true;
+  var v_24 : bool = true;
+  var v_25 : bool = true;
+}
+)");
+}
+
+TEST_F(IRToProgramTest, ReservedWords) {
+    auto* fn = b.Function("f", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+
+    b.Append(fn->Block(), [&] {
+        Var("NULL", true);
+        Var("Self", true);
+        Var("abstract", true);
+        Var("active", true);
+        Var("alignas", true);
+        Var("alignof", true);
+        Var("as", true);
+        Var("asm", true);
+        Var("asm_fragment", true);
+        Var("async", true);
+        Var("attribute", true);
+        Var("auto", true);
+        Var("await", true);
+        Var("become", true);
+        Var("cast", true);
+        Var("catch", true);
+        Var("class", true);
+        Var("co_await", true);
+        Var("co_return", true);
+        Var("co_yield", true);
+        Var("coherent", true);
+        Var("column_major", true);
+        Var("common", true);
+        Var("compile", true);
+        Var("compile_fragment", true);
+        Var("concept", true);
+        Var("const_cast", true);
+        Var("consteval", true);
+        Var("constexpr", true);
+        Var("constinit", true);
+        Var("crate", true);
+        Var("debugger", true);
+        Var("decltype", true);
+        Var("delete", true);
+        Var("demote", true);
+        Var("demote_to_helper", true);
+        Var("do", true);
+        Var("dynamic_cast", true);
+        Var("enum", true);
+        Var("explicit", true);
+        Var("export", true);
+        Var("extends", true);
+        Var("extern", true);
+        Var("external", true);
+        Var("fallthrough", true);
+        Var("filter", true);
+        Var("final", true);
+        Var("finally", true);
+        Var("friend", true);
+        Var("from", true);
+        Var("fxgroup", true);
+        Var("get", true);
+        Var("goto", true);
+        Var("groupshared", true);
+        Var("highp", true);
+        Var("impl", true);
+        Var("implements", true);
+        Var("import", true);
+        Var("inline", true);
+        Var("instanceof", true);
+        Var("interface", true);
+        Var("layout", true);
+        Var("lowp", true);
+        Var("macro", true);
+        Var("macro_rules", true);
+        Var("match", true);
+        Var("mediump", true);
+        Var("meta", true);
+        Var("mod", true);
+        Var("module", true);
+        Var("move", true);
+        Var("mut", true);
+        Var("mutable", true);
+        Var("namespace", true);
+        Var("new", true);
+        Var("nil", true);
+        Var("noexcept", true);
+        Var("noinline", true);
+        Var("nointerpolation", true);
+        Var("non_coherent", true);
+        Var("noncoherent", true);
+        Var("noperspective", true);
+        Var("null", true);
+        Var("nullptr", true);
+        Var("of", true);
+        Var("operator", true);
+        Var("package", true);
+        Var("packoffset", true);
+        Var("partition", true);
+        Var("pass", true);
+        Var("patch", true);
+        Var("pixelfragment", true);
+        Var("precise", true);
+        Var("precision", true);
+        Var("premerge", true);
+        Var("priv", true);
+        Var("protected", true);
+        Var("pub", true);
+        Var("public", true);
+        Var("readonly", true);
+        Var("ref", true);
+        Var("regardless", true);
+        Var("register", true);
+        Var("reinterpret_cast", true);
+        Var("require", true);
+        Var("resource", true);
+        Var("restrict", true);
+        Var("self", true);
+        Var("set", true);
+        Var("shared", true);
+        Var("sizeof", true);
+        Var("smooth", true);
+        Var("snorm", true);
+        Var("static", true);
+        Var("static_assert", true);
+        Var("static_cast", true);
+        Var("std", true);
+        Var("subroutine", true);
+        Var("super", true);
+        Var("target", true);
+        Var("template", true);
+        Var("this", true);
+        Var("thread_local", true);
+        Var("throw", true);
+        Var("trait", true);
+        Var("try", true);
+        Var("type", true);
+        Var("typedef", true);
+        Var("typeid", true);
+        Var("typename", true);
+        Var("typeof", true);
+        Var("union", true);
+        Var("unless", true);
+        Var("unorm", true);
+        Var("unsafe", true);
+        Var("unsized", true);
+        Var("use", true);
+        Var("using", true);
+        Var("varying", true);
+        Var("virtual", true);
+        Var("volatile", true);
+        Var("wgsl", true);
+        Var("where", true);
+        Var("with", true);
+        Var("writeonly", true);
+        Var("yield", true);
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+@fragment
+fn f() {
+  var v : bool = true;
+  var v_1 : bool = true;
+  var v_2 : bool = true;
+  var v_3 : bool = true;
+  var v_4 : bool = true;
+  var v_5 : bool = true;
+  var v_6 : bool = true;
+  var v_7 : bool = true;
+  var v_8 : bool = true;
+  var v_9 : bool = true;
+  var v_10 : bool = true;
+  var v_11 : bool = true;
+  var v_12 : bool = true;
+  var v_13 : bool = true;
+  var v_14 : bool = true;
+  var v_15 : bool = true;
+  var v_16 : bool = true;
+  var v_17 : bool = true;
+  var v_18 : bool = true;
+  var v_19 : bool = true;
+  var v_20 : bool = true;
+  var v_21 : bool = true;
+  var v_22 : bool = true;
+  var v_23 : bool = true;
+  var v_24 : bool = true;
+  var v_25 : bool = true;
+  var v_26 : bool = true;
+  var v_27 : bool = true;
+  var v_28 : bool = true;
+  var v_29 : bool = true;
+  var v_30 : bool = true;
+  var v_31 : bool = true;
+  var v_32 : bool = true;
+  var v_33 : bool = true;
+  var v_34 : bool = true;
+  var v_35 : bool = true;
+  var v_36 : bool = true;
+  var v_37 : bool = true;
+  var v_38 : bool = true;
+  var v_39 : bool = true;
+  var v_40 : bool = true;
+  var v_41 : bool = true;
+  var v_42 : bool = true;
+  var v_43 : bool = true;
+  var v_44 : bool = true;
+  var v_45 : bool = true;
+  var v_46 : bool = true;
+  var v_47 : bool = true;
+  var v_48 : bool = true;
+  var v_49 : bool = true;
+  var v_50 : bool = true;
+  var v_51 : bool = true;
+  var v_52 : bool = true;
+  var v_53 : bool = true;
+  var v_54 : bool = true;
+  var v_55 : bool = true;
+  var v_56 : bool = true;
+  var v_57 : bool = true;
+  var v_58 : bool = true;
+  var v_59 : bool = true;
+  var v_60 : bool = true;
+  var v_61 : bool = true;
+  var v_62 : bool = true;
+  var v_63 : bool = true;
+  var v_64 : bool = true;
+  var v_65 : bool = true;
+  var v_66 : bool = true;
+  var v_67 : bool = true;
+  var v_68 : bool = true;
+  var v_69 : bool = true;
+  var v_70 : bool = true;
+  var v_71 : bool = true;
+  var v_72 : bool = true;
+  var v_73 : bool = true;
+  var v_74 : bool = true;
+  var v_75 : bool = true;
+  var v_76 : bool = true;
+  var v_77 : bool = true;
+  var v_78 : bool = true;
+  var v_79 : bool = true;
+  var v_80 : bool = true;
+  var v_81 : bool = true;
+  var v_82 : bool = true;
+  var v_83 : bool = true;
+  var v_84 : bool = true;
+  var v_85 : bool = true;
+  var v_86 : bool = true;
+  var v_87 : bool = true;
+  var v_88 : bool = true;
+  var v_89 : bool = true;
+  var v_90 : bool = true;
+  var v_91 : bool = true;
+  var v_92 : bool = true;
+  var v_93 : bool = true;
+  var v_94 : bool = true;
+  var v_95 : bool = true;
+  var v_96 : bool = true;
+  var v_97 : bool = true;
+  var v_98 : bool = true;
+  var v_99 : bool = true;
+  var v_100 : bool = true;
+  var v_101 : bool = true;
+  var v_102 : bool = true;
+  var v_103 : bool = true;
+  var v_104 : bool = true;
+  var v_105 : bool = true;
+  var v_106 : bool = true;
+  var v_107 : bool = true;
+  var v_108 : bool = true;
+  var v_109 : bool = true;
+  var v_110 : bool = true;
+  var v_111 : bool = true;
+  var v_112 : bool = true;
+  var v_113 : bool = true;
+  var v_114 : bool = true;
+  var v_115 : bool = true;
+  var v_116 : bool = true;
+  var v_117 : bool = true;
+  var v_118 : bool = true;
+  var v_119 : bool = true;
+  var v_120 : bool = true;
+  var v_121 : bool = true;
+  var v_122 : bool = true;
+  var v_123 : bool = true;
+  var v_124 : bool = true;
+  var v_125 : bool = true;
+  var v_126 : bool = true;
+  var v_127 : bool = true;
+  var v_128 : bool = true;
+  var v_129 : bool = true;
+  var v_130 : bool = true;
+  var v_131 : bool = true;
+  var v_132 : bool = true;
+  var v_133 : bool = true;
+  var v_134 : bool = true;
+  var v_135 : bool = true;
+  var v_136 : bool = true;
+  var v_137 : bool = true;
+  var v_138 : bool = true;
+  var v_139 : bool = true;
+  var v_140 : bool = true;
+  var v_141 : bool = true;
+  var v_142 : bool = true;
+  var v_143 : bool = true;
+  var v_144 : bool = true;
+  var v_145 : bool = true;
+}
+)");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Unary ops
 ////////////////////////////////////////////////////////////////////////////////