[ir] Handle `let` in RenameConflicts

Let instructions were not getting renamed, leading to conflicts in
generated code.

Bug: 42251016
Change-Id: I38b2c4432806452158979e3688783d61ebfa7298
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/196358
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/transform/rename_conflicts.cc b/src/tint/lang/core/ir/transform/rename_conflicts.cc
index fa32ced..f24cf87 100644
--- a/src/tint/lang/core/ir/transform/rename_conflicts.cc
+++ b/src/tint/lang/core/ir/transform/rename_conflicts.cc
@@ -32,6 +32,7 @@
 #include "src/tint/lang/core/ir/core_builtin_call.h"
 #include "src/tint/lang/core/ir/function.h"
 #include "src/tint/lang/core/ir/instruction.h"
+#include "src/tint/lang/core/ir/let.h"
 #include "src/tint/lang/core/ir/loop.h"
 #include "src/tint/lang/core/ir/module.h"
 #include "src/tint/lang/core/ir/multi_in_block.h"
@@ -103,7 +104,7 @@
     /// Stack of scopes
     Vector<Scope, 8> scopes{};
 
-    /// Registers all the WGSL module-scope declarations in the root-scope.
+    /// Registers all the module-scope declarations in the root-scope.
     /// Duplicate declarations with the same name will renamed.
     void RegisterModuleScopeDecls() {
         // Declare all the user types
@@ -188,6 +189,10 @@
                 // Ensure the var's type is resolvable
                 EnsureResolvable(inst->Result(0)->Type());
             },
+            [&](core::ir::Let*) {
+                // Ensure the let's type is resolvable
+                EnsureResolvable(inst->Result(0)->Type());
+            },
             [&](core::ir::Construct*) {
                 // Ensure the type of a type constructor is resolvable
                 EnsureResolvable(inst->Result(0)->Type());
diff --git a/src/tint/lang/core/ir/transform/rename_conflicts_test.cc b/src/tint/lang/core/ir/transform/rename_conflicts_test.cc
index 7e4a983..bd4cb60 100644
--- a/src/tint/lang/core/ir/transform/rename_conflicts_test.cc
+++ b/src/tint/lang/core/ir/transform/rename_conflicts_test.cc
@@ -392,6 +392,62 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(IRToProgramRenameConflictsTest, Conflict_FnLet_ShadowedBy_IfVar) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* outer = b.Var(ty.ptr<function, i32>());
+        b.ir.SetName(outer, "v");
+
+        auto* if_ = b.If(true);
+        b.Append(if_->True(), [&] {
+            auto* inner = b.Let("v", 42_i);
+            auto* load_outer = b.Load(outer);
+            b.Return(fn, b.Add(ty.i32(), load_outer, inner));
+        });
+
+        b.Unreachable();
+    });
+
+    auto* src = R"(
+%f = func():i32 {
+  $B1: {
+    %v:ptr<function, i32, read_write> = var
+    if true [t: $B2] {  # if_1
+      $B2: {  # true
+        %v_1:i32 = let 42i  # %v_1: 'v'
+        %4:i32 = load %v
+        %5:i32 = add %4, %v_1
+        ret %5
+      }
+    }
+    unreachable
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 {
+  $B1: {
+    %v:ptr<function, i32, read_write> = var
+    if true [t: $B2] {  # if_1
+      $B2: {  # true
+        %v_1:i32 = let 42i
+        %4:i32 = load %v
+        %5:i32 = add %4, %v_1
+        ret %5
+      }
+    }
+    unreachable
+  }
+}
+)";
+
+    Run();
+
+    EXPECT_EQ(expect, str());
+}
+
 TEST_F(IRToProgramRenameConflictsTest, NoModify_LoopInitVar_ShadowedBy_LoopBodyVar) {
     auto* fn = b.Function("f", ty.i32());
     b.Append(fn->Block(), [&] {
diff --git a/test/tint/shadowing/struct/let.wgsl.expected.ir.msl b/test/tint/shadowing/struct/let.wgsl.expected.ir.msl
index de13c82..faba801 100644
--- a/test/tint/shadowing/struct/let.wgsl.expected.ir.msl
+++ b/test/tint/shadowing/struct/let.wgsl.expected.ir.msl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #include <metal_stdlib>
 using namespace metal;
 
@@ -10,24 +8,6 @@
 void f() {
   a const a_1 = a{};
   a const b = a_1;
-  a const a = a{};
-  a const b_1 = a;
+  a const a_2 = a{};
+  a const b_1 = a_2;
 }
-program_source:11:16: error: expected ';' at end of declaration
-  a const a = a{};
-               ^
-               ;
-program_source:12:4: error: expected ';' after expression
-  a const b_1 = a;
-   ^
-   ;
-program_source:12:11: error: C++ requires a type specifier for all declarations
-  a const b_1 = a;
-    ~~~~~ ^
-program_source:11:15: warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized]
-  a const a = a{};
-          ~   ^
-program_source:12:3: warning: expression result unused [-Wunused-value]
-  a const b_1 = a;
-  ^
-
diff --git a/test/tint/shadowing/struct/param.wgsl.expected.ir.msl b/test/tint/shadowing/struct/param.wgsl.expected.ir.msl
index 82f3eed..6f928c8 100644
--- a/test/tint/shadowing/struct/param.wgsl.expected.ir.msl
+++ b/test/tint/shadowing/struct/param.wgsl.expected.ir.msl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #include <metal_stdlib>
 using namespace metal;
 
@@ -7,17 +5,6 @@
   int a;
 };
 
-void f(a a) {
-  a const b = a;
+void f(a a_1) {
+  a const b = a_1;
 }
-program_source:9:4: error: expected ';' after expression
-  a const b = a;
-   ^
-   ;
-program_source:9:11: error: C++ requires a type specifier for all declarations
-  a const b = a;
-    ~~~~~ ^
-program_source:9:3: warning: expression result unused [-Wunused-value]
-  a const b = a;
-  ^
-