tint: Deprecated module-scope 'let' for 'const'

Enable the parsing of 'const'.
Warn on use of module-scope 'let', and automatically replace with 'const'.

Fixed: tint:1580
Change-Id: I214aabca80686dc6b60ae21a7a57fbfb4898ea83
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93786
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/docs/tint/origin-trial-changes.md b/docs/tint/origin-trial-changes.md
index 3935fdc..3c78be9 100644
--- a/docs/tint/origin-trial-changes.md
+++ b/docs/tint/origin-trial-changes.md
@@ -10,6 +10,8 @@
 ### Breaking changes
 
 * The `smoothStep()` builtin has been removed (use `smoothstep` instead). [tint:1483](crbug.com/tint/1483)
+* Module-scope `let` has been replaced with module-scope `const`. [tint:1580](crbug.com/tint/1584)
+  * Note: Module-scope `const` does not support structure types. Use `var<private>` if you need a module-scope structure type.
 
 ### Deprecated Features
 
diff --git a/src/tint/ast/module_clone_test.cc b/src/tint/ast/module_clone_test.cc
index bd96b26..544e6bf 100644
--- a/src/tint/ast/module_clone_test.cc
+++ b/src/tint/ast/module_clone_test.cc
@@ -37,8 +37,8 @@
   m1 : array<u32, 6>,
 };
 
-let c0 : i32 = 10;
-let c1 : bool = true;
+const c0 : i32 = 10;
+const c1 : bool = true;
 
 type t0 = array<vec4<f32>>;
 type t1 = array<vec4<f32>>;
@@ -71,6 +71,8 @@
   var l4 : S1;
   var l5 : u32 = l4.m1[5];
   let l6 : ptr<private, u32> = &g0;
+  const l7 = 123;
+  const l8 : i32 = 123;
   loop {
     l0 = (p1 + 2);
     if (((l0 % 4) == 0)) {
@@ -104,7 +106,7 @@
   f1(1.0, 2);
 }
 
-let declaration_order_check_0 : i32 = 1;
+const declaration_order_check_0 : i32 = 1;
 
 type declaration_order_check_1 = f32;
 
@@ -112,7 +114,7 @@
 
 type declaration_order_check_3 = f32;
 
-let declaration_order_check_4 : i32 = 1;
+const declaration_order_check_4 : i32 = 1;
 
 )");
 
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 1828391..5bccb5f 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -1527,41 +1527,6 @@
 
     /// @param name the variable name
     /// @param type the variable type
-    /// @param constructor constructor expression
-    /// @param attributes optional variable attributes
-    /// @returns an `ast::Let` constructed by calling Let() with the arguments of `args`, which is
-    /// automatically registered as a global variable with the ast::Module.
-    template <typename NAME>
-    const ast::Let* GlobalLet(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 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::Let` 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::Let* GlobalLet(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 name the variable name
-    /// @param type the variable type
     /// @param constructor optional constructor expression
     /// @param attributes optional variable attributes
     /// @returns an `ast::Override` which is automatically registered as a global variable with the
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index 35360e4..deaa17c 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -47,9 +47,6 @@
 namespace tint::reader::wgsl {
 namespace {
 
-// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
-bool const_enabled = false;
-
 template <typename T>
 using Expect = ParserImpl::Expect<T>;
 
@@ -248,11 +245,6 @@
 
 ParserImpl::~ParserImpl() = default;
 
-// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
-void ParserImpl::EnableConst() {
-    const_enabled = true;
-}
-
 ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
                                                    std::string_view err,
                                                    std::string_view use) {
@@ -579,11 +571,12 @@
     bool is_const = false;
     bool is_overridable = false;
     const char* use = nullptr;
-    if (match(Token::Type::kLet)) {
-        use = "'let' declaration";
-    } else if (const_enabled && match(Token::Type::kConst)) {
+    Source source;
+    if (match(Token::Type::kConst)) {
         use = "'const' declaration";
-        is_const = true;
+    } else if (match(Token::Type::kLet, &source)) {
+        use = "'let' declaration";
+        deprecated(source, "module-scope 'let' has been replaced with 'const'");
     } else if (match(Token::Type::kOverride)) {
         use = "'override' declaration";
         is_overridable = true;
@@ -632,11 +625,11 @@
                                      initializer,                              // constructor
                                      std::move(attrs));                        // attributes
     }
-    return create<ast::Let>(decl->source,                             // source
-                            builder_.Symbols().Register(decl->name),  // symbol
-                            decl->type,                               // type
-                            initializer,                              // constructor
-                            std::move(attrs));                        // attributes
+    return create<ast::Const>(decl->source,                             // source
+                              builder_.Symbols().Register(decl->name),  // symbol
+                              decl->type,                               // type
+                              initializer,                              // constructor
+                              std::move(attrs));                        // attributes
 }
 
 // variable_decl
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index 4ae4eef..5857454 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -72,11 +72,6 @@
     };
 
   public:
-    /// A temporary bodge to enable unit-testing of 'const' variable types while still under active
-    /// development.
-    // TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
-    static void EnableConst();
-
     /// 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
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 3273413..48969a5 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -456,11 +456,12 @@
 }
 
 TEST_F(ParserImplErrorTest, FunctionMissingOpenLine) {
-    EXPECT(R"(let bar : vec2<f32> = vec2<f32>(1., 2.);
+    EXPECT(
+        R"(const bar : vec2<f32> = vec2<f32>(1., 2.);
   var a : f32 = bar[0];
   return;
 })",
-           R"(test.wgsl:3:3 error: statement found outside of function body
+        R"(test.wgsl:3:3 error: statement found outside of function body
   return;
   ^^^^^^
 )");
@@ -550,32 +551,52 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclLetInvalidIdentifier) {
-    EXPECT("let ^ : i32 = 1;",
-           R"(test.wgsl:1:5 error: expected identifier for 'let' declaration
+    EXPECT(
+        "let ^ : i32 = 1;",
+        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let ^ : i32 = 1;
+^^^
+
+test.wgsl:1:5 error: expected identifier for 'let' declaration
 let ^ : i32 = 1;
     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclLetMissingSemicolon) {
-    EXPECT("let i : i32 = 1",
-           R"(test.wgsl:1:16 error: expected ';' for 'let' declaration
+    EXPECT(
+        "let i : i32 = 1",
+        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : i32 = 1
+^^^
+
+test.wgsl:1:16 error: expected ';' for 'const' declaration
 let i : i32 = 1
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclLetMissingLParen) {
-    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:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>;
+^^^
+
+test.wgsl:1:30 error: expected '(' for type constructor
 let i : vec2<i32> = vec2<i32>;
                              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclLetMissingRParen) {
-    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:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>(1., 2.;
+^^^
+
+test.wgsl:1:37 error: expected ')' for type constructor
 let i : vec2<i32> = vec2<i32>(1., 2.;
                                     ^
 )");
@@ -583,50 +604,37 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclLetBadConstLiteral) {
     EXPECT("let i : vec2<i32> = vec2<i32>(!);",
-           R"(test.wgsl:1:32 error: unable to parse right side of ! expression
+           R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>(!);
+^^^
+
+test.wgsl:1:32 error: unable to parse right side of ! expression
 let i : vec2<i32> = vec2<i32>(!);
                                ^
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclLetExprMaxDepth) {
-    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 << "^^^";
-        }
-    }
-    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, GlobalDeclLetExprMissingLParen) {
-    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:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32> 1, 2);
+^^^
+
+test.wgsl:1:31 error: expected '(' for type constructor
 let i : vec2<i32> = vec2<i32> 1, 2);
                               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingRParen) {
-    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:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+let i : vec2<i32> = vec2<i32>(1, 2;
+^^^
+
+test.wgsl:1:35 error: expected ')' for type constructor
 let i : vec2<i32> = vec2<i32>(1, 2;
                                   ^
 )");
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 21c0078..bfa678e 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
@@ -27,20 +27,20 @@
     EXPECT_FALSE(p->has_error()) << p->error();
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
-    auto* let = e.value->As<ast::Let>();
-    ASSERT_NE(let, nullptr);
+    auto* const_ = e.value->As<ast::Const>();
+    ASSERT_NE(const_, nullptr);
 
-    EXPECT_EQ(let->symbol, p->builder().Symbols().Get("a"));
-    ASSERT_NE(let->type, nullptr);
-    EXPECT_TRUE(let->type->Is<ast::F32>());
+    EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_NE(const_->type, nullptr);
+    EXPECT_TRUE(const_->type->Is<ast::F32>());
 
-    EXPECT_EQ(let->source.range.begin.line, 1u);
-    EXPECT_EQ(let->source.range.begin.column, 5u);
-    EXPECT_EQ(let->source.range.end.line, 1u);
-    EXPECT_EQ(let->source.range.end.column, 6u);
+    EXPECT_EQ(const_->source.range.begin.line, 1u);
+    EXPECT_EQ(const_->source.range.begin.column, 5u);
+    EXPECT_EQ(const_->source.range.end.line, 1u);
+    EXPECT_EQ(const_->source.range.end.column, 6u);
 
-    ASSERT_NE(let->constructor, nullptr);
-    EXPECT_TRUE(let->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(const_->constructor, nullptr);
+    EXPECT_TRUE(const_->constructor->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, GlobalLetDecl_Inferred) {
@@ -52,19 +52,19 @@
     EXPECT_FALSE(p->has_error()) << p->error();
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
-    auto* let = e.value->As<ast::Let>();
-    ASSERT_NE(let, nullptr);
+    auto* const_ = e.value->As<ast::Const>();
+    ASSERT_NE(const_, nullptr);
 
-    EXPECT_EQ(let->symbol, p->builder().Symbols().Get("a"));
-    EXPECT_EQ(let->type, nullptr);
+    EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(const_->type, nullptr);
 
-    EXPECT_EQ(let->source.range.begin.line, 1u);
-    EXPECT_EQ(let->source.range.begin.column, 5u);
-    EXPECT_EQ(let->source.range.end.line, 1u);
-    EXPECT_EQ(let->source.range.end.column, 6u);
+    EXPECT_EQ(const_->source.range.begin.line, 1u);
+    EXPECT_EQ(const_->source.range.begin.column, 5u);
+    EXPECT_EQ(const_->source.range.end.line, 1u);
+    EXPECT_EQ(const_->source.range.end.column, 6u);
 
-    ASSERT_NE(let->constructor, nullptr);
-    EXPECT_TRUE(let->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(const_->constructor, nullptr);
+    EXPECT_TRUE(const_->constructor->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, GlobalLetDecl_InvalidExpression) {
@@ -77,7 +77,10 @@
     EXPECT_TRUE(e.errored);
     EXPECT_FALSE(e.matched);
     EXPECT_EQ(e.value, nullptr);
-    EXPECT_EQ(p->error(), "1:15: missing initializer for 'let' declaration");
+    EXPECT_EQ(
+        p->error(),
+        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:15: missing initializer for 'let' declaration)");
 }
 
 TEST_F(ParserImplTest, GlobalLetDecl_MissingExpression) {
@@ -90,7 +93,10 @@
     EXPECT_TRUE(e.errored);
     EXPECT_FALSE(e.matched);
     EXPECT_EQ(e.value, nullptr);
-    EXPECT_EQ(p->error(), "1:14: missing initializer for 'let' declaration");
+    EXPECT_EQ(
+        p->error(),
+        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:14: missing initializer for 'let' declaration)");
 }
 
 TEST_F(ParserImplTest, GlobalConstDecl) {
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 3b48b5a..5abe58f 100644
--- a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -72,21 +72,30 @@
     auto p = parser("let a : vec2<i32>;");
     p->global_decl();
     ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:18: expected '=' for 'let' declaration");
+    EXPECT_EQ(
+        p->error(),
+        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:18: expected '=' for 'let' declaration)");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalLet_Invalid) {
     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");
+    EXPECT_EQ(
+        p->error(),
+        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:19: expected '=' for 'let' declaration)");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingSemicolon) {
     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");
+    EXPECT_EQ(
+        p->error(),
+        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
+1:36: expected ';' for 'const' declaration)");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConst) {
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 65fae3c..cb61eed 100644
--- a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
@@ -25,13 +25,6 @@
     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");
-}
 TEST_P(ParserImplReservedKeywordTest, ModuleConst) {
     auto name = GetParam();
     auto p = parser("const " + name + " : i32 = 1;");
diff --git a/src/tint/resolver/array_accessor_test.cc b/src/tint/resolver/array_accessor_test.cc
index 6aee5e5..be49546 100644
--- a/src/tint/resolver/array_accessor_test.cc
+++ b/src/tint/resolver/array_accessor_test.cc
@@ -79,17 +79,6 @@
     EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Let) {
-    GlobalLet("my_let", ty.mat2x3<f32>(), Construct(ty.mat2x3<f32>()));
-    auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
-    auto* acc = IndexAccessor("my_let", Expr(Source{{12, 34}}, idx));
-    WrapInFunction(Decl(idx), acc);
-
-    EXPECT_TRUE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "");
-}
-
 TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic) {
     GlobalConst("my_const", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
     auto* idx = Var("idx", ty.u32(), Expr(3_u));
@@ -100,22 +89,6 @@
     EXPECT_EQ(r()->error(), "");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic_Let) {
-    GlobalLet("my_let", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
-    auto* idx = Var("idx", ty.u32(), Expr(3_u));
-    auto* acc = IndexAccessor("my_let", Expr(Source{{12, 34}}, idx));
-    WrapInFunction(Decl(idx), acc);
-
-    EXPECT_TRUE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "");
-
-    auto idx_sem = Sem().Get(acc);
-    ASSERT_NE(idx_sem, nullptr);
-    EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
-    EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
-}
-
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
     GlobalConst("my_const", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
     auto* idx = Var("idy", ty.u32(), Expr(2_u));
@@ -126,22 +99,6 @@
     EXPECT_EQ(r()->error(), "");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic_Let) {
-    GlobalLet("my_let", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
-    auto* idx = Var("idy", ty.u32(), Expr(2_u));
-    auto* acc = IndexAccessor(IndexAccessor("my_let", Expr(Source{{12, 34}}, idx)), 1_i);
-    WrapInFunction(Decl(idx), acc);
-
-    EXPECT_TRUE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "");
-
-    auto idx_sem = Sem().Get(acc);
-    ASSERT_NE(idx_sem, nullptr);
-    EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
-    EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
-}
-
 TEST_F(ResolverIndexAccessorTest, Matrix) {
     GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
 
@@ -215,21 +172,6 @@
     EXPECT_TRUE(r()->Resolve());
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Let) {
-    GlobalLet("my_let", ty.vec3<f32>(), Construct(ty.vec3<f32>()));
-    auto* idx = Var("idx", ty.i32(), Expr(2_i));
-    auto* acc = IndexAccessor("my_let", Expr(Source{{12, 34}}, idx));
-    WrapInFunction(Decl(idx), acc);
-
-    EXPECT_TRUE(r()->Resolve());
-
-    auto idx_sem = Sem().Get(acc);
-    ASSERT_NE(idx_sem, nullptr);
-    EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
-    EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
-}
-
 TEST_F(ResolverIndexAccessorTest, Vector) {
     GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
@@ -332,24 +274,6 @@
     EXPECT_TRUE(TypeOf(acc)->Is<sem::F32>());
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverIndexAccessorTest, Array_Let) {
-    GlobalLet("my_let", ty.array<f32, 3>(), array<f32, 3>());
-
-    auto* acc = IndexAccessor("my_let", 2_i);
-    WrapInFunction(acc);
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-
-    ASSERT_NE(TypeOf(acc), nullptr);
-    EXPECT_TRUE(TypeOf(acc)->Is<sem::F32>());
-
-    auto idx_sem = Sem().Get(acc);
-    ASSERT_NE(idx_sem, nullptr);
-    EXPECT_EQ(idx_sem->Index()->Declaration(), acc->index);
-    EXPECT_EQ(idx_sem->Object()->Declaration(), acc->object);
-}
-
 TEST_F(ResolverIndexAccessorTest, Array_Dynamic_I32) {
     // let a : array<f32, 3> = 0;
     // var idx : i32 = 0;
diff --git a/src/tint/resolver/assignment_validation_test.cc b/src/tint/resolver/assignment_validation_test.cc
index 5c91a76..1ae9895 100644
--- a/src/tint/resolver/assignment_validation_test.cc
+++ b/src/tint/resolver/assignment_validation_test.cc
@@ -79,26 +79,6 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Let_Pass) {
-    // let len = 4u;
-    // {
-    //   var a : array<f32, 4u>;
-    //   var b : array<f32, len>;
-    //   a = b;
-    // }
-
-    GlobalLet("len", nullptr, Expr(4_u));
-
-    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);
-
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-}
-
 TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Fail) {
     // const len = 5u;
     // {
@@ -120,28 +100,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'array<f32, 5>' to 'array<f32, 4>'");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Let_Fail) {
-    // let len = 5u;
-    // {
-    //   var a : array<f32, 4u>;
-    //   var b : array<f32, len>;
-    //   a = b;
-    // }
-
-    GlobalLet("len", nullptr, Expr(5_u));
-
-    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);
-
-    ASSERT_FALSE(r()->Resolve());
-
-    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'array<f32, 5>' to 'array<f32, 4>'");
-}
-
 TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypesInBlockStatement_Pass) {
     // {
     //  var a : i32 = 2i;
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index d54ff0e..c462717 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -787,23 +787,6 @@
                   "12:34 error: attribute is not valid for module-scope 'const' declaration");
     }
 }
-
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_P(ConstantAttributeTest, IsValid_Let) {
-    auto& params = GetParam();
-
-    GlobalLet("a", ty.f32(), Expr(1.23_f), createAttributes(Source{{12, 34}}, *this, params.kind));
-
-    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 module-scope 'let' declaration");
-    }
-}
 INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
                          ConstantAttributeTest,
                          testing::Values(TestParams{AttributeKind::kAlign, false},
@@ -836,22 +819,6 @@
 12:34 note: first attribute declared here)");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ConstantAttributeTest, DuplicateAttribute_Let) {
-    GlobalLet("a", ty.f32(), Expr(1.23_f),
-              ast::AttributeList{
-                  create<ast::IdAttribute>(Source{{12, 34}}, 0),
-                  create<ast::IdAttribute>(Source{{56, 78}}, 1),
-              });
-
-    WrapInFunction();
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(56:78 error: duplicate id attribute
-12:34 note: first attribute declared here)");
-}
-
 using OverrideAttributeTest = TestWithParams;
 TEST_P(OverrideAttributeTest, IsValid) {
     auto& params = GetParam();
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index c29aac6..72c5596 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -93,15 +93,6 @@
               R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a 'const')");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalLet) {
-    GlobalLet(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 'let')");
-}
-
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVar) {
     GlobalVar(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), ast::StorageClass::kPrivate);
 
@@ -307,40 +298,6 @@
     err << "12:34 error: the " << param.name << " argument must be a const_expression";
     EXPECT_EQ(r()->error(), err.str());
 }
-
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalLet) {
-    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 module-scope let 'G' with the offset value
-    GlobalLet("G", nullptr, expr({}, *this));
-
-    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);
-
-    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)});
-
-    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,
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index ac5117c..b7ffa79 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -54,7 +54,6 @@
 /// kinds of symbol declarations.
 enum class SymbolDeclKind {
     GlobalVar,
-    GlobalLet,
     GlobalConst,
     Alias,
     Struct,
@@ -67,10 +66,10 @@
 };
 
 static constexpr SymbolDeclKind kAllSymbolDeclKinds[] = {
-    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalLet,      SymbolDeclKind::GlobalConst,
-    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[] = {
@@ -79,14 +78,14 @@
 };
 
 static constexpr SymbolDeclKind kValueDeclKinds[] = {
-    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalLet,      SymbolDeclKind::GlobalConst,
-    SymbolDeclKind::Parameter,      SymbolDeclKind::LocalVar,       SymbolDeclKind::LocalLet,
-    SymbolDeclKind::NestedLocalVar, SymbolDeclKind::NestedLocalLet,
+    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalConst, SymbolDeclKind::Parameter,
+    SymbolDeclKind::LocalVar,       SymbolDeclKind::LocalLet,    SymbolDeclKind::NestedLocalVar,
+    SymbolDeclKind::NestedLocalLet,
 };
 
 static constexpr SymbolDeclKind kGlobalDeclKinds[] = {
-    SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalLet, SymbolDeclKind::GlobalConst,
-    SymbolDeclKind::Alias,     SymbolDeclKind::Struct,    SymbolDeclKind::Function,
+    SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalConst, SymbolDeclKind::Alias,
+    SymbolDeclKind::Struct,    SymbolDeclKind::Function,
 };
 
 static constexpr SymbolDeclKind kLocalDeclKinds[] = {
@@ -96,7 +95,6 @@
 
 static constexpr SymbolDeclKind kGlobalValueDeclKinds[] = {
     SymbolDeclKind::GlobalVar,
-    SymbolDeclKind::GlobalLet,
     SymbolDeclKind::GlobalConst,
 };
 
@@ -115,12 +113,6 @@
     GlobalVarSampledTexElemType,
     GlobalVarMultisampledTexElemType,
     GlobalVarValue,
-    GlobalLetType,
-    GlobalLetArrayElemType,
-    GlobalLetArraySizeValue,
-    GlobalLetVectorElemType,
-    GlobalLetMatrixElemType,
-    GlobalLetValue,
     GlobalConstType,
     GlobalConstArrayElemType,
     GlobalConstArraySizeValue,
@@ -154,11 +146,6 @@
     SymbolUseKind::GlobalVarMatrixElemType,
     SymbolUseKind::GlobalVarSampledTexElemType,
     SymbolUseKind::GlobalVarMultisampledTexElemType,
-    SymbolUseKind::GlobalLetType,
-    SymbolUseKind::GlobalLetArrayElemType,
-    SymbolUseKind::GlobalLetArraySizeValue,
-    SymbolUseKind::GlobalLetVectorElemType,
-    SymbolUseKind::GlobalLetMatrixElemType,
     SymbolUseKind::GlobalConstType,
     SymbolUseKind::GlobalConstArrayElemType,
     SymbolUseKind::GlobalConstArraySizeValue,
@@ -178,10 +165,10 @@
 };
 
 static constexpr SymbolUseKind kValueUseKinds[] = {
-    SymbolUseKind::GlobalVarValue,      SymbolUseKind::GlobalLetValue,
-    SymbolUseKind::GlobalConstValue,    SymbolUseKind::LocalVarValue,
-    SymbolUseKind::LocalLetValue,       SymbolUseKind::NestedLocalVarValue,
-    SymbolUseKind::NestedLocalLetValue, SymbolUseKind::WorkgroupSizeValue,
+    SymbolUseKind::GlobalVarValue,      SymbolUseKind::GlobalConstValue,
+    SymbolUseKind::LocalVarValue,       SymbolUseKind::LocalLetValue,
+    SymbolUseKind::NestedLocalVarValue, SymbolUseKind::NestedLocalLetValue,
+    SymbolUseKind::WorkgroupSizeValue,
 };
 
 static constexpr SymbolUseKind kFuncUseKinds[] = {
@@ -194,8 +181,6 @@
     switch (kind) {
         case SymbolDeclKind::GlobalVar:
             return out << "global var";
-        case SymbolDeclKind::GlobalLet:
-            return out << "global let";
         case SymbolDeclKind::GlobalConst:
             return out << "global const";
         case SymbolDeclKind::Alias:
@@ -238,18 +223,6 @@
             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::GlobalConstType:
             return out << "global const type";
         case SymbolUseKind::GlobalConstValue:
@@ -309,10 +282,6 @@
         case SymbolUseKind::GlobalVarMatrixElemType:
         case SymbolUseKind::GlobalVarSampledTexElemType:
         case SymbolUseKind::GlobalVarMultisampledTexElemType:
-        case SymbolUseKind::GlobalLetType:
-        case SymbolUseKind::GlobalLetArrayElemType:
-        case SymbolUseKind::GlobalLetVectorElemType:
-        case SymbolUseKind::GlobalLetMatrixElemType:
         case SymbolUseKind::GlobalConstType:
         case SymbolUseKind::GlobalConstArrayElemType:
         case SymbolUseKind::GlobalConstVectorElemType:
@@ -330,8 +299,6 @@
             return "type";
         case SymbolUseKind::GlobalVarValue:
         case SymbolUseKind::GlobalVarArraySizeValue:
-        case SymbolUseKind::GlobalLetValue:
-        case SymbolUseKind::GlobalLetArraySizeValue:
         case SymbolUseKind::GlobalConstValue:
         case SymbolUseKind::GlobalConstArraySizeValue:
         case SymbolUseKind::LocalVarValue:
@@ -353,7 +320,6 @@
 int ScopeDepth(SymbolDeclKind kind) {
     switch (kind) {
         case SymbolDeclKind::GlobalVar:
-        case SymbolDeclKind::GlobalLet:
         case SymbolDeclKind::GlobalConst:
         case SymbolDeclKind::Alias:
         case SymbolDeclKind::Struct:
@@ -383,12 +349,6 @@
         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::GlobalConstType:
         case SymbolUseKind::GlobalConstValue:
         case SymbolUseKind::GlobalConstArrayElemType:
@@ -466,8 +426,6 @@
     switch (kind) {
         case SymbolDeclKind::GlobalVar:
             return b.GlobalVar(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
-        case SymbolDeclKind::GlobalLet:
-            return b.GlobalLet(source, symbol, b.ty.i32(), b.Expr(1_i));
         case SymbolDeclKind::GlobalConst:
             return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1_i));
         case SymbolDeclKind::Alias:
@@ -548,36 +506,6 @@
             b.GlobalVar(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
             return node;
         }
-        case SymbolUseKind::GlobalLetType: {
-            auto* node = b.ty.type_name(source, symbol);
-            b.GlobalLet(b.Sym(), node, b.Expr(1_i));
-            return node;
-        }
-        case SymbolUseKind::GlobalLetArrayElemType: {
-            auto* node = b.ty.type_name(source, symbol);
-            b.GlobalLet(b.Sym(), b.ty.array(node, 4_i), b.Expr(1_i));
-            return node;
-        }
-        case SymbolUseKind::GlobalLetArraySizeValue: {
-            auto* node = b.Expr(source, symbol);
-            b.GlobalLet(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.GlobalLet(b.Sym(), b.ty.vec3(node), b.Expr(1_i));
-            return node;
-        }
-        case SymbolUseKind::GlobalLetMatrixElemType: {
-            auto* node = b.ty.type_name(source, symbol);
-            b.GlobalLet(b.Sym(), b.ty.mat3x4(node), b.Expr(1_i));
-            return node;
-        }
-        case SymbolUseKind::GlobalLetValue: {
-            auto* node = b.Expr(source, symbol);
-            b.GlobalLet(b.Sym(), b.ty.i32(), node);
-            return node;
-        }
         case SymbolUseKind::GlobalConstType: {
             auto* node = b.ty.type_name(source, symbol);
             b.GlobalConst(b.Sym(), node, b.Expr(1_i));
@@ -849,14 +777,6 @@
 12:34 note: var 'SYMBOL' references var 'SYMBOL' here)");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalLet) {
-    const Symbol symbol = Sym("SYMBOL");
-    GlobalLet(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, GlobalConst) {
     const Symbol symbol = Sym("SYMBOL");
     GlobalConst(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i));
@@ -998,18 +918,6 @@
 56:78 note: const 'V' references const 'V' here)");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Direct) {
-    // let V : i32 = V;
-
-    GlobalLet(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'
-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;
@@ -1044,32 +952,13 @@
 2:10 note: const 'X' references const 'Y' here)");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Indirect) {
-    // 1: let Y : i32 = Z;
-    // 2: let X : i32 = Y;
-    // 3: let Z : i32 = X;
-
-    GlobalLet(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
-    GlobalLet(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
-    GlobalLet(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'
-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: const C : S = Z;
-    // 7: let L : S = C;
+    // 6: const L : S = Z;
 
     Func(Source{{1, 1}}, "F", {}, ty.type_name(Source{{1, 5}}, "R"),
          {Return(Expr(Source{{1, 10}}, "Z"))});
@@ -1077,18 +966,16 @@
     Structure(Source{{3, 1}}, "S", {Member("a", ty.type_name(Source{{3, 10}}, "A"))});
     GlobalVar(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}}, "C", ty.type_name(Source{{5, 5}}, "S"), Expr(Source{{5, 10}}, "Z"));
-    GlobalLet(Source{{7, 1}}, "L", ty.type_name(Source{{5, 5}}, "S"), Expr(Source{{5, 10}}, "C"));
+    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'
 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' -> 'C' -> 'Z'
-4:10 note: var 'Z' references let 'L' here
-5:10 note: let 'L' references const 'C' here
-5:10 note: const 'C' references var 'Z' here)");
+4:1 error: cyclic dependency found: 'Z' -> 'L' -> 'Z'
+4:10 note: var 'Z' references const 'L' here
+5:10 note: const 'L' references var 'Z' here)");
 }
 
 }  // namespace recursive_tests
@@ -1339,7 +1226,6 @@
     Structure(Sym(), {Member(Sym(), T)});
     GlobalVar(Sym(), T, V);
     GlobalConst(Sym(), T, V);
-    GlobalLet(Sym(), T, V);
     Func(Sym(),              //
          {Param(Sym(), T)},  //
          T,                  // Return type
@@ -1408,9 +1294,8 @@
     // Check that the nullptr of the var / const / let type doesn't make things explode
     GlobalVar("a", nullptr, Expr(1_i));
     GlobalConst("b", nullptr, Expr(1_i));
-    GlobalLet("c", nullptr, Expr(1_i));
-    WrapInFunction(Var("d", nullptr, Expr(1_i)),  //
-                   Let("e", nullptr, Expr(1_i)));
+    WrapInFunction(Var("c", nullptr, Expr(1_i)),  //
+                   Let("d", nullptr, Expr(1_i)));
     Build();
 }
 
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index 3326d11..39d05d9 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -451,31 +451,6 @@
     EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_y));
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_LetU32) {
-    // let x = 4u;
-    // let x = 8u;
-    // @compute @workgroup_size(x, y, 16u)
-    // fn main() {}
-    auto* x = GlobalLet("x", ty.u32(), Expr(4_u));
-    auto* y = GlobalLet("y", ty.u32(), Expr(8_u));
-    auto* func = Func("main", {}, ty.void_(), {},
-                      {Stage(ast::PipelineStage::kCompute), WorkgroupSize("x", "y", 16_u)});
-
-    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);
-
-    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));
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_I32) {
     // @compute @workgroup_size(1i, 2i, 3i)
     // fn main() {}
@@ -553,20 +528,6 @@
               "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Let_TypeMismatch) {
-    // let x = 64u;
-    // @compute @workgroup_size(1i, x)
-    // fn main() {}
-    GlobalLet("x", ty.u32(), Expr(64_u));
-    Func("main", {}, ty.void_(), {},
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, 1_i, "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");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch2) {
     // const x = 64u;
     // const y = 32i;
@@ -582,22 +543,6 @@
               "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Let_TypeMismatch2) {
-    // let x = 64u;
-    // let y = 32i;
-    // @compute @workgroup_size(x, y)
-    // fn main() {}
-    GlobalLet("x", ty.u32(), Expr(64_u));
-    GlobalLet("y", ty.i32(), Expr(32_i));
-    Func("main", {}, ty.void_(), {},
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, "x", "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");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Mismatch_ConstU32) {
     // const x = 4u;
     // const x = 8u;
@@ -613,22 +558,6 @@
               "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Mismatch_LetU32) {
-    // let x = 4u;
-    // let x = 8u;
-    // @compute @workgroup_size(x, y, 16i)
-    // fn main() {}
-    GlobalLet("x", ty.u32(), Expr(4_u));
-    GlobalLet("y", ty.u32(), Expr(8_u));
-    Func("main", {}, ty.void_(), {},
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Source{{12, 34}}, "x", "y", 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");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_BadType) {
     // @compute @workgroup_size(64.0)
     // fn main() {}
@@ -678,21 +607,6 @@
               "overridable of type abstract-integer, i32 or u32");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Let_BadType) {
-    // let x = 64.0;
-    // @compute @workgroup_size(x)
-    // fn main() {}
-    GlobalLet("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 a literal, constant, or "
-              "overridable of type abstract-integer, i32 or u32");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Negative) {
     // const x = -2i;
     // @compute @workgroup_size(x)
@@ -705,19 +619,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Let_Negative) {
-    // let x = -2i;
-    // @compute @workgroup_size(x)
-    // fn main() {}
-    GlobalLet("x", ty.i32(), Expr(-2_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");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Zero) {
     // const x = 0i;
     // @compute @workgroup_size(x)
@@ -730,19 +631,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Let_Zero) {
-    // let x = 0i;
-    // @compute @workgroup_size(x)
-    // fn main() {}
-    GlobalLet("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");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_NestedZeroValueConstructor) {
     // const x = i32(i32(i32()));
     // @compute @workgroup_size(x)
@@ -755,19 +643,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Let_NestedZeroValueConstructor) {
-    // let x = i32(i32(i32()));
-    // @compute @workgroup_size(x)
-    // fn main() {}
-    GlobalLet("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");
-}
-
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
     // var<private> x = 64i;
     // @compute @workgroup_size(x)
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index 56a22da..a183b20 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -89,21 +89,6 @@
     EXPECT_EQ(TypeOf(a), expected_type);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_P(ResolverInferredTypeParamTest, GlobalLet_Pass) {
-    auto& params = GetParam();
-
-    auto* expected_type = params.create_expected_type(*this);
-
-    // let a = <type constructor>;
-    auto* ctor_expr = params.create_value(*this, 0);
-    auto* var = GlobalLet("a", nullptr, ctor_expr);
-    WrapInFunction();
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-    EXPECT_EQ(TypeOf(var), expected_type);
-}
-
 TEST_P(ResolverInferredTypeParamTest, GlobalVar_Pass) {
     auto& params = GetParam();
 
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 8cb4264..6794921 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -365,13 +365,13 @@
 
     sem::Variable* sem = nullptr;
     if (is_global) {
-        sem = builder_->create<sem::GlobalVariable>(
-            v, ty, ast::StorageClass::kNone, ast::Access::kUndefined,
-            rhs ? rhs->ConstantValue() : sem::Constant{}, sem::BindingPoint{});
+        sem = builder_->create<sem::GlobalVariable>(v, ty, ast::StorageClass::kNone,
+                                                    ast::Access::kUndefined, sem::Constant{},
+                                                    sem::BindingPoint{});
     } else {
         sem = builder_->create<sem::LocalVariable>(v, ty, ast::StorageClass::kNone,
                                                    ast::Access::kUndefined, current_statement_,
-                                                   rhs ? rhs->ConstantValue() : sem::Constant{});
+                                                   sem::Constant{});
     }
 
     sem->SetConstructor(rhs);
@@ -467,16 +467,6 @@
         return nullptr;
     }
 
-    // TODO(crbug.com/tint/1580): Temporary seatbelt to used to ensure that a `let` cannot be used
-    // to initialize a 'const'. Once we fully implement `const`, and remove constant evaluation from
-    // 'let', this can be removed.
-    if (auto* user = rhs->UnwrapMaterialize()->As<sem::VariableUser>();
-        user && user->Variable()->Is<sem::LocalVariable>() &&
-        user->Variable()->Declaration()->Is<ast::Let>()) {
-        AddError("'const' initializer must be constant expression", c->constructor->source);
-        return nullptr;
-    }
-
     if (!validator_.VariableInitializer(c, ast::StorageClass::kNone, ty, rhs)) {
         return nullptr;
     }
@@ -931,7 +921,7 @@
         if (auto* user = args[i]->As<sem::VariableUser>()) {
             // We have an variable of a module-scope constant.
             auto* decl = user->Variable()->Declaration();
-            if (!decl->IsAnyOf<ast::Let, ast::Const, ast::Override>()) {
+            if (!decl->IsAnyOf<ast::Const, ast::Override>()) {
                 AddError(kErrBadExpr, values[i]->source);
                 return false;
             }
@@ -1313,6 +1303,12 @@
             return nullptr;
         }
         auto expr_val = EvaluateConstantValue(decl, expr->Type());
+        if (!expr_val) {
+            TINT_ICE(Resolver, builder_->Diagnostics())
+                << decl->source << "EvaluateConstantValue(" << decl->TypeInfo().name
+                << ") returned invalid value";
+            return nullptr;
+        }
         auto materialized_val = ConvertValue(std::move(expr_val), target_ty, decl->source);
         if (!materialized_val) {
             return nullptr;
@@ -2229,17 +2225,6 @@
             return nullptr;
         }
 
-        // TODO(crbug.com/tint/1580): Temporary seatbelt to used to ensure that a function-scope
-        // `let` cannot be used to propagate a constant expression to an array size. Once we
-        // implement `const`, this can be removed.
-        if (auto* user = count_sem->UnwrapMaterialize()->As<sem::VariableUser>();
-            user && user->Variable()->Is<sem::LocalVariable>() &&
-            user->Variable()->Declaration()->Is<ast::Let>()) {
-            AddError("array size must evaluate to a constant integer expression",
-                     count_expr->source);
-            return nullptr;
-        }
-
         auto count_val = count_sem->ConstantValue();
         if (!count_val) {
             AddError("array size must evaluate to a constant integer expression",
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index f4de30c..2f0992c 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -463,22 +463,6 @@
     EXPECT_EQ(ary->Count(), 10u);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTest, ArraySize_UnsignedLet) {
-    // let size = 10u;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(10_u));
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
-
-    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);
-}
-
 TEST_F(ResolverTest, ArraySize_SignedConst) {
     // const size = 0;
     // var<private> a : array<f32, size>;
@@ -494,22 +478,6 @@
     EXPECT_EQ(ary->Count(), 10u);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTest, ArraySize_SignedLet) {
-    // let size = 0;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(10_i));
-    auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
-
-    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);
-}
-
 TEST_F(ResolverTest, Expr_Bitcast) {
     GlobalVar("name", ty.f32(), ast::StorageClass::kPrivate);
 
@@ -662,22 +630,6 @@
     EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTest, Expr_Identifier_GlobalLet) {
-    auto* my_var = GlobalLet("my_var", ty.f32(), Construct(ty.f32()));
-
-    auto* ident = Expr("my_var");
-    WrapInFunction(ident);
-
-    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);
-}
-
 TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
     auto* my_var_a = Expr("my_var");
     auto* var = Let("my_var", ty.f32(), Construct(ty.f32()));
@@ -1023,35 +975,6 @@
     EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTest, Function_WorkgroupSize_ViaLet) {
-    // let width = 16i;
-    // let height = 8i;
-    // let depth = 2i;
-    // @compute @workgroup_size(width, height, depth)
-    // fn main() {}
-    GlobalLet("width", ty.i32(), Expr(16_i));
-    GlobalLet("height", ty.i32(), Expr(8_i));
-    GlobalLet("depth", ty.i32(), Expr(2_i));
-    auto* func = Func("main", {}, ty.void_(), {},
-                      {
-                          Stage(ast::PipelineStage::kCompute),
-                          WorkgroupSize("width", "height", "depth"),
-                      });
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-
-    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);
-}
-
 TEST_F(ResolverTest, Function_WorkgroupSize_ViaConst_NestedInitializer) {
     // const width = i32(i32(i32(8i)));
     // const height = i32(i32(i32(4i)));
@@ -1080,35 +1003,6 @@
     EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTest, Function_WorkgroupSize_ViaLet_NestedInitializer) {
-    // let width = i32(i32(i32(8i)));
-    // let height = i32(i32(i32(4i)));
-    // @compute @workgroup_size(width, height)
-    // fn main() {}
-    GlobalLet("width", ty.i32(),
-              Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 8_i))));
-    GlobalLet("height", ty.i32(),
-              Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 4_i))));
-    auto* func = Func("main", {}, ty.void_(), {},
-                      {
-                          Stage(ast::PipelineStage::kCompute),
-                          WorkgroupSize("width", "height"),
-                      });
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-
-    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);
-}
-
 TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts) {
     // @id(0) override width = 16i;
     // @id(1) override height = 8i;
@@ -1191,33 +1085,6 @@
     EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTest, Function_WorkgroupSize_Mixed_Let) {
-    // @id(1) override height = 2i;
-    // let depth = 3i;
-    // @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", {}, ty.void_(), {},
-                      {
-                          Stage(ast::PipelineStage::kCompute),
-                          WorkgroupSize(8_i, "height", "depth"),
-                      });
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-
-    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);
-}
-
 TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
     auto* st =
         Structure("S", {Member("first_member", ty.i32()), Member("second_member", ty.f32())});
diff --git a/src/tint/resolver/source_variable_test.cc b/src/tint/resolver/source_variable_test.cc
index fbcbba9..2648e93 100644
--- a/src/tint/resolver/source_variable_test.cc
+++ b/src/tint/resolver/source_variable_test.cc
@@ -103,18 +103,6 @@
     EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverSourceVariableTest, GlobalLet) {
-    auto* a = GlobalLet("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);
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index 62597c4..602cb6e 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -94,13 +94,6 @@
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeValidationTest, GlobalLetNoStorageClass_Pass) {
-    // let global_let: f32;
-    GlobalLet(Source{{12, 34}}, "global_let", ty.f32(), Construct(ty.f32()));
-
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
 TEST_F(ResolverTypeValidationTest, GlobalVariableUnique_Pass) {
     // var global_var0 : f32 = 0.1;
     // var global_var1 : i32 = 0;
@@ -211,15 +204,6 @@
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLet_Pass) {
-    // let size = 4u;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(4_u));
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Pass) {
     // const size = 4i;
     // var<private> a : array<f32, size>;
@@ -228,15 +212,6 @@
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_SignedLet_Pass) {
-    // let size = 4i;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(4_i));
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Zero) {
     // var<private> a : array<f32, 0>;
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)), ast::StorageClass::kPrivate);
@@ -274,16 +249,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLet_Zero) {
-    // let size = 0u;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(0_u));
-    GlobalVar("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 (0) must be greater than 0");
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Zero) {
     // const size = 0i;
     // var<private> a : array<f32, size>;
@@ -293,16 +258,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_SignedLet_Zero) {
-    // let size = 0i;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(0_i));
-    GlobalVar("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 (0) must be greater than 0");
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Negative) {
     // const size = -10i;
     // var<private> a : array<f32, size>;
@@ -312,16 +267,6 @@
     EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_SignedLet_Negative) {
-    // let size = -10i;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(-10_i));
-    GlobalVar("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 (-10) must be greater than 0");
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
     // var<private> a : array<f32, 10.0>;
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)), ast::StorageClass::kPrivate);
@@ -352,18 +297,6 @@
               "'f32'");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_FloatLet) {
-    // let size = 10.0;
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Expr(10_f));
-    GlobalVar("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 evaluate to a constant integer expression, but is type "
-              "'f32'");
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_IVecConst) {
     // const size = vec2<i32>(100, 100);
     // var<private> a : array<f32, size>;
@@ -375,18 +308,6 @@
               "'vec2<i32>'");
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverTypeValidationTest, ArraySize_IVecLet) {
-    // let size = vec2<i32>(100, 100);
-    // var<private> a : array<f32, size>;
-    GlobalLet("size", nullptr, Construct(ty.vec2<i32>(), 100_i, 100_i));
-    GlobalVar("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 evaluate to a constant integer expression, but is type "
-              "'vec2<i32>'");
-}
-
 TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
     // var<private> a : array<f32, 0x40000000u>;
     GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), 0x40000000_u), ast::StorageClass::kPrivate);
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index cc2f520..b335c27 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -84,7 +84,7 @@
         kTrue,
         kFalse,
         kLiteral,
-        kModuleLet,
+        kModuleConst,
         kPipelineOverridable,
         kFuncLetUniformRhs,
         kFuncVarUniform,
@@ -137,8 +137,8 @@
                 return "false";
             case kLiteral:
                 return "7 == 7";
-            case kModuleLet:
-                return "module_let == 0";
+            case kModuleConst:
+                return "module_const == 0";
             case kPipelineOverridable:
                 return "pipeline_overridable == 0";
             case kFuncLetUniformRhs:
@@ -231,7 +231,7 @@
             CASE(kTrue);
             CASE(kFalse);
             CASE(kLiteral);
-            CASE(kModuleLet);
+            CASE(kModuleConst);
             CASE(kPipelineOverridable);
             CASE(kFuncLetUniformRhs);
             CASE(kFuncVarUniform);
@@ -290,7 +290,7 @@
 @group(1) @binding(2) var s : sampler;
 @group(1) @binding(3) var sc : sampler_comparison;
 
-let module_let : i32 = 42;
+const module_const : i32 = 42;
 @id(42) override pipeline_overridable : i32;
 
 fn user_no_restriction() {}
diff --git a/src/tint/resolver/variable_test.cc b/src/tint/resolver/variable_test.cc
index 4039fc0..f5622c7 100644
--- a/src/tint/resolver/variable_test.cc
+++ b/src/tint/resolver/variable_test.cc
@@ -277,30 +277,6 @@
     EXPECT_EQ(user_v->Variable(), global);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalLet) {
-    // let a : i32 = 1i;
-    //
-    // fn X() {
-    //   var a = (a == 123);
-    // }
-
-    auto* g = GlobalLet("a", ty.i32(), Expr(1_i));
-    auto* v = Var("a", nullptr, Expr("a"));
-    Func("F", {}, ty.void_(), {Decl(v)});
-
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-
-    auto* global = Sem().Get(g);
-    auto* local = Sem().Get<sem::LocalVariable>(v);
-    ASSERT_NE(local, nullptr);
-    EXPECT_EQ(local->Shadows(), global);
-
-    auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
-    ASSERT_NE(user_v, nullptr);
-    EXPECT_EQ(user_v->Variable(), global);
-}
-
 TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalVar) {
     // fn F() {
     //   var a : i32 = 1i; // x
@@ -618,30 +594,6 @@
     EXPECT_EQ(user->Variable(), global);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalLet) {
-    // let a : i32 = 1i;
-    //
-    // fn F() {
-    //   let a = a;
-    // }
-
-    auto* g = GlobalLet("a", ty.i32(), Expr(1_i));
-    auto* l = Let("a", nullptr, Expr("a"));
-    Func("F", {}, ty.void_(), {Decl(l)});
-
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-
-    auto* global = Sem().Get(g);
-    auto* local = Sem().Get<sem::LocalVariable>(l);
-    ASSERT_NE(local, nullptr);
-    EXPECT_EQ(local->Shadows(), global);
-
-    auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
-    ASSERT_NE(user, nullptr);
-    EXPECT_EQ(user->Variable(), global);
-}
-
 TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalVar) {
     // fn F() {
     //   var a : i32 = 1i;
@@ -848,26 +800,6 @@
     EXPECT_EQ(user->Variable(), global);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverVariableTest, LocalConst_ShadowsGlobalLet) {
-    // let a : i32 = 1i;
-    //
-    // fn F() {
-    //   const a = 1i;
-    // }
-
-    auto* g = GlobalLet("a", ty.i32(), Expr(1_i));
-    auto* c = Const("a", nullptr, Expr("a"));
-    Func("F", {}, ty.void_(), {Decl(c)});
-
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-
-    auto* global = Sem().Get(g);
-    auto* local = Sem().Get<sem::LocalVariable>(c);
-    ASSERT_NE(local, nullptr);
-    EXPECT_EQ(local->Shadows(), global);
-}
-
 TEST_F(ResolverVariableTest, LocalConst_ShadowsLocalVar) {
     // fn F() {
     //   var a = 1i;
@@ -1368,28 +1300,6 @@
     EXPECT_EQ(param->Shadows(), global);
 }
 
-// TODO(crbug.com/tint/1580): Remove when module-scope 'let' is removed
-TEST_F(ResolverVariableTest, Param_ShadowsGlobalLet) {
-    // let a : i32 = 1i;
-    //
-    // fn F(a : bool) {
-    // }
-
-    auto* g = GlobalLet("a", ty.i32(), Expr(1_i));
-    auto* p = Param("a", ty.bool_());
-    Func("F", {p}, ty.void_(), {});
-
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-
-    auto* global = Sem().Get(g);
-    auto* param = Sem().Get<sem::Parameter>(p);
-
-    ASSERT_NE(global, nullptr);
-    ASSERT_NE(param, nullptr);
-
-    EXPECT_EQ(param->Shadows(), global);
-}
-
 TEST_F(ResolverVariableTest, Param_ShadowsAlias) {
     // type a = i32;
     //
diff --git a/src/tint/test_main.cc b/src/tint/test_main.cc
index 0114d4b..ca68271 100644
--- a/src/tint/test_main.cc
+++ b/src/tint/test_main.cc
@@ -15,11 +15,6 @@
 #include "gmock/gmock.h"
 #include "src/tint/program.h"
 
-// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
-#if TINT_BUILD_WGSL_READER
-#include "src/tint/reader/wgsl/parser_impl.h"
-#endif
-
 #if TINT_BUILD_SPV_READER
 #include "src/tint/reader/spirv/parser_impl_test_helper.h"
 #endif
@@ -59,11 +54,6 @@
 int main(int argc, char** argv) {
     testing::InitGoogleMock(&argc, argv);
 
-// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
-#if TINT_BUILD_WGSL_READER
-    tint::reader::wgsl::ParserImpl::EnableConst();
-#endif
-
 #if TINT_BUILD_WGSL_WRITER
     tint::Program::printer = [](const tint::Program* program) {
         auto result = tint::writer::wgsl::Generate(program, {});
diff --git a/src/tint/transform/loop_to_for_loop_test.cc b/src/tint/transform/loop_to_for_loop_test.cc
index e3d7ecc..24e0e15 100644
--- a/src/tint/transform/loop_to_for_loop_test.cc
+++ b/src/tint/transform/loop_to_for_loop_test.cc
@@ -151,7 +151,7 @@
 )";
 
     auto* expect = R"(
-let N = 16u;
+const N = 16u;
 
 fn f() {
   var i : u32 = 0u;
diff --git a/src/tint/transform/promote_initializers_to_let_test.cc b/src/tint/transform/promote_initializers_to_let_test.cc
index addb6dd..d4d9fb2 100644
--- a/src/tint/transform/promote_initializers_to_let_test.cc
+++ b/src/tint/transform/promote_initializers_to_let_test.cc
@@ -1099,20 +1099,16 @@
 
 TEST_F(PromoteInitializersToLetTest, NoChangeOnVarDecl) {
     auto* src = R"(
-struct S {
-  a : i32,
-  b : f32,
-  c : i32,
-}
+type F = f32;
 
 fn f() {
   var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
-  var local_str = S(1, 2.0, 3);
+  var local_str = F(3.0);
 }
 
-let module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+const module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
 
-let module_str : S = S(1, 2.0, 3);
+const module_str : F = F(2.0);
 )";
 
     auto* expect = src;
@@ -1127,18 +1123,14 @@
     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);
+  var local_str = F(3.0);
 }
 
-let module_str : S = S(1, 2.0, 3);
+const module_str : F = F(2.0);
 
-struct S {
-  a : i32,
-  b : f32,
-  c : i32,
-}
+type F = f32;
 
-let module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+const module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
 )";
 
     auto* expect = src;
diff --git a/src/tint/transform/robustness_test.cc b/src/tint/transform/robustness_test.cc
index fb0e5a4..8dab595 100644
--- a/src/tint/transform/robustness_test.cc
+++ b/src/tint/transform/robustness_test.cc
@@ -21,7 +21,7 @@
 
 using RobustnessTest = TransformTest;
 
-TEST_F(RobustnessTest, Array_Idx_Clamp) {
+TEST_F(RobustnessTest, Array_Let_Idx_Clamp) {
     auto* src = R"(
 var<private> a : array<f32, 3>;
 
@@ -35,7 +35,7 @@
     auto* expect = R"(
 var<private> a : array<f32, 3>;
 
-let c : u32 = 1u;
+const c : u32 = 1u;
 
 fn f() {
   let b : f32 = a[1u];
@@ -47,7 +47,33 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(RobustnessTest, Array_Idx_Clamp_OutOfOrder) {
+TEST_F(RobustnessTest, Array_Const_Idx_Clamp) {
+    auto* src = R"(
+var<private> a : array<f32, 3>;
+
+const c : u32 = 1u;
+
+fn f() {
+  let b : f32 = a[c];
+}
+)";
+
+    auto* expect = R"(
+var<private> a : array<f32, 3>;
+
+const c : u32 = 1u;
+
+fn f() {
+  let b : f32 = a[1u];
+}
+)";
+
+    auto got = Run<Robustness>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RobustnessTest, Array_Let_Idx_Clamp_OutOfOrder) {
     auto* src = R"(
 fn f() {
   let b : f32 = a[c];
@@ -63,7 +89,33 @@
   let b : f32 = a[1u];
 }
 
-let c : u32 = 1u;
+const c : u32 = 1u;
+
+var<private> a : array<f32, 3>;
+)";
+
+    auto got = Run<Robustness>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RobustnessTest, Array_Const_Idx_Clamp_OutOfOrder) {
+    auto* src = R"(
+fn f() {
+  let b : f32 = a[c];
+}
+
+const c : u32 = 1u;
+
+var<private> a : array<f32, 3>;
+)";
+
+    auto* expect = R"(
+fn f() {
+  let b : f32 = a[1u];
+}
+
+const c : u32 = 1u;
 
 var<private> a : array<f32, 3>;
 )";
@@ -1392,7 +1444,7 @@
 
 @group(0) @binding(0) var<storage, read> s : S;
 
-let c : u32 = 1u;
+const c : u32 = 1u;
 
 fn f() {
   let b : f32 = s.b[c];
@@ -1409,7 +1461,7 @@
 
 @group(0) @binding(0) var<storage, read> s : S;
 
-let c : u32 = 1u;
+const c : u32 = 1u;
 
 fn f() {
   let b : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
diff --git a/src/tint/transform/single_entry_point_test.cc b/src/tint/transform/single_entry_point_test.cc
index 8445f61..020bd65 100644
--- a/src/tint/transform/single_entry_point_test.cc
+++ b/src/tint/transform/single_entry_point_test.cc
@@ -186,13 +186,13 @@
 
 TEST_F(SingleEntryPointTest, GlobalConstants) {
     auto* src = R"(
-let a : f32 = 1.0;
+const a : f32 = 1.0;
 
-let b : f32 = 1.0;
+const b : f32 = 1.0;
 
-let c : f32 = 1.0;
+const c : f32 = 1.0;
 
-let d : f32 = 1.0;
+const d : f32 = 1.0;
 
 @vertex
 fn vert_main() -> @builtin(position) vec4<f32> {
@@ -217,7 +217,7 @@
 )";
 
     auto* expect = R"(
-let c : f32 = 1.0;
+const c : f32 = 1.0;
 
 @compute @workgroup_size(1)
 fn comp_main1() {
@@ -243,6 +243,32 @@
 }
 )";
 
+    auto* expect = R"(
+const size : i32 = 1;
+
+@compute @workgroup_size(size)
+fn main() {
+}
+)";
+
+    SingleEntryPoint::Config cfg("main");
+
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(SingleEntryPointTest, WorkgroupSizeConstPreserved) {
+    auto* src = R"(
+const size : i32 = 1;
+
+@compute @workgroup_size(size)
+fn main() {
+}
+)";
+
     auto* expect = src;
 
     SingleEntryPoint::Config cfg("main");
diff --git a/src/tint/transform/unshadow_test.cc b/src/tint/transform/unshadow_test.cc
index 271626a..f5a8102 100644
--- a/src/tint/transform/unshadow_test.cc
+++ b/src/tint/transform/unshadow_test.cc
@@ -402,7 +402,7 @@
 )";
 
     auto* expect = R"(
-let a : i32 = 1;
+const a : i32 = 1;
 
 fn X() {
   var a_1 = (a == 123);
@@ -452,7 +452,7 @@
   const a_3 = 321;
 }
 
-let a : i32 = 1;
+const a : i32 = 1;
 )";
 
     auto got = Run<Unshadow>(src);
@@ -473,7 +473,7 @@
 }
 
 fn Z() {
-  const a = a;
+  const a = 321;
 }
 )";
 
@@ -489,7 +489,7 @@
 }
 
 fn Z() {
-  const a_3 = a;
+  const a_3 = 321;
 }
 )";
 
@@ -741,7 +741,7 @@
 )";
 
     auto* expect = R"(
-let a : i32 = 1;
+const a : i32 = 1;
 
 fn F(a_1 : bool) {
 }
@@ -764,7 +764,7 @@
 fn F(a_1 : bool) {
 }
 
-let a : i32 = 1;
+const a : i32 = 1;
 )";
 
     auto got = Run<Unshadow>(src);
diff --git a/src/tint/transform/var_for_dynamic_index_test.cc b/src/tint/transform/var_for_dynamic_index_test.cc
index ca767c9..05c19b3 100644
--- a/src/tint/transform/var_for_dynamic_index_test.cc
+++ b/src/tint/transform/var_for_dynamic_index_test.cc
@@ -484,7 +484,8 @@
 fn f() {
   let p = array<i32, 4>(1, 2, 3, 4);
   let c = 1;
-  let x = p[c];
+  var var_for_index = p;
+  let x = var_for_index[c];
 }
 )";
 
@@ -501,7 +502,8 @@
 fn f() {
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
   let c = 1;
-  let x = p[c];
+  var var_for_index = p;
+  let x = var_for_index[c];
 }
 )";
 
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 4ed14f1..3935fe39 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -1771,14 +1771,8 @@
 
 bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
     if (auto* sem = builder_.Sem().Get(expr)) {
-        if (auto* user = sem->As<sem::VariableUser>();
-            !user || !user->Variable()->Declaration()->Is<ast::Let>()) {
-            // Disable constant inlining if the constant expression is from a 'let' declaration.
-            // TODO(crbug.com/tint/1580): Once 'const' is implemented, 'let' will no longer resolve
-            // to a shader-creation time constant value, and this can be removed.
-            if (auto constant = sem->ConstantValue()) {
-                return EmitConstant(out, constant);
-            }
+        if (auto constant = sem->ConstantValue()) {
+            return EmitConstant(out, constant);
         }
     }
     return Switch(
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index b283302..a25d023 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -805,31 +805,6 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Let) {
-    GlobalLet("width", ty.i32(), Construct(ty.i32(), 2_i));
-    GlobalLet("height", ty.i32(), Construct(ty.i32(), 3_i));
-    GlobalLet("depth", ty.i32(), Construct(ty.i32(), 4_i));
-    Func("main", {}, ty.void_(), {},
-         {
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize("width", "height", "depth"),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate()) << gen.error();
-    EXPECT_EQ(gen.result(), R"(#version 310 es
-
-const int width = 2;
-const int height = 3;
-const int depth = 4;
-layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;
-void main() {
-  return;
-}
-)");
-}
-
 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));
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index defbb3e..fd502d1 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -2614,14 +2614,8 @@
 
 bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
     if (auto* sem = builder_.Sem().Get(expr)) {
-        if (auto* user = sem->As<sem::VariableUser>();
-            !user || !user->Variable()->Declaration()->Is<ast::Let>()) {
-            // Disable constant inlining if the constant expression is from a 'let' declaration.
-            // TODO(crbug.com/tint/1580): Once 'const' is implemented, 'let' will no longer resolve
-            // to a shader-creation time constant value, and this can be removed.
-            if (auto constant = sem->ConstantValue()) {
-                return EmitConstant(out, constant);
-            }
+        if (auto constant = sem->ConstantValue()) {
+            return EmitConstant(out, constant);
         }
     }
     return Switch(
@@ -2852,7 +2846,6 @@
                     return false;
             }
         },
-        [&](const ast::Let* let) { return EmitProgramConstVariable(let); },
         [&](const ast::Override* override) { return EmitOverride(override); },
         [&](const ast::Const*) {
             return true;  // Constants are embedded at their use
@@ -4057,25 +4050,6 @@
     return true;
 }
 
-bool GeneratorImpl::EmitProgramConstVariable(const ast::Let* let) {
-    auto* sem = builder_.Sem().Get(let);
-    auto* type = sem->Type();
-
-    auto out = line();
-    out << "static const ";
-    if (!EmitTypeAndName(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
-                         builder_.Symbols().NameFor(let->symbol))) {
-        return false;
-    }
-    out << " = ";
-    if (!EmitExpression(out, let->constructor)) {
-        return false;
-    }
-    out << ";";
-
-    return true;
-}
-
 bool GeneratorImpl::EmitOverride(const ast::Override* override) {
     auto* sem = builder_.Sem().Get(override);
     auto* type = sem->Type();
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index f082f77..8960548 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -460,10 +460,6 @@
     /// @param let the variable to generate
     /// @returns true if the variable was emitted
     bool EmitLet(const ast::Let* let);
-    /// Handles generating a module-scope 'let' declaration
-    /// @param let the 'let' to emit
-    /// @returns true if the variable was emitted
-    bool EmitProgramConstVariable(const ast::Let* let);
     /// Handles generating a module-scope 'override' declaration
     /// @param override the 'override' to emit
     /// @returns true if the variable was emitted
diff --git a/src/tint/writer/hlsl/generator_impl_assign_test.cc b/src/tint/writer/hlsl/generator_impl_assign_test.cc
index 7982e6b..57e65a9 100644
--- a/src/tint/writer/hlsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_assign_test.cc
@@ -54,11 +54,15 @@
 
     ASSERT_TRUE(gen.Generate());
     EXPECT_EQ(gen.result(),
-              R"(void fn() {
+              R"(void set_float3(inout float3 vec, int idx, float val) {
+  vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;
+}
+
+void fn() {
   float3 lhs = float3(0.0f, 0.0f, 0.0f);
   float rhs = 0.0f;
   const uint index = 0u;
-  lhs[index] = rhs;
+  set_float3(lhs, index, rhs);
 }
 )");
 }
@@ -123,11 +127,20 @@
 
     ASSERT_TRUE(gen.Generate());
     EXPECT_EQ(gen.result(),
-              R"(void fn() {
+              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;
+    case 2: mat[2] = val; break;
+    case 3: mat[3] = val; break;
+  }
+}
+
+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;
-  lhs[index] = rhs;
+  set_vector_float4x2(lhs, index, rhs);
 }
 )");
 }
@@ -197,11 +210,28 @@
 
     ASSERT_TRUE(gen.Generate());
     EXPECT_EQ(gen.result(),
-              R"(void fn() {
+              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];
+      break;
+    case 1:
+      mat[1] = (row.xx == int2(0, 1)) ? val.xx : mat[1];
+      break;
+    case 2:
+      mat[2] = (row.xx == int2(0, 1)) ? val.xx : mat[2];
+      break;
+    case 3:
+      mat[3] = (row.xx == int2(0, 1)) ? val.xx : mat[3];
+      break;
+  }
+}
+
+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;
-  lhs[index][index] = rhs;
+  set_scalar_float4x2(lhs, index, index, rhs);
 }
 )");
 }
diff --git a/src/tint/writer/hlsl/generator_impl_function_test.cc b/src/tint/writer/hlsl/generator_impl_function_test.cc
index 4e8e721..b0e1495 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -705,30 +705,6 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Let) {
-    GlobalLet("width", ty.i32(), Construct(ty.i32(), 2_i));
-    GlobalLet("height", ty.i32(), Construct(ty.i32(), 3_i));
-    GlobalLet("depth", ty.i32(), Construct(ty.i32(), 4_i));
-    Func("main", {}, ty.void_(), {},
-         {
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize("width", "height", "depth"),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate()) << gen.error();
-    EXPECT_EQ(gen.result(), R"(static const int width = 2;
-static const int height = 3;
-static const int depth = 4;
-
-[numthreads(2, 3, 4)]
-void main() {
-  return;
-}
-)");
-}
-
 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));
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 f858499..3a988a0 100644
--- a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -22,16 +22,6 @@
 
 using HlslGeneratorImplTest_ModuleConstant = TestHelper;
 
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalLet) {
-    auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
-    WrapInFunction(Decl(var));
-
-    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");
-}
-
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AInt) {
     auto* var = GlobalConst("G", nullptr, Expr(1_a));
     Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index ccdcb1d..c649090 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -253,10 +253,6 @@
             [&](const ast::Alias*) {
                 return true;  // folded away by the writer
             },
-            [&](const ast::Let* let) {
-                TINT_DEFER(line());
-                return EmitProgramConstVariable(let);
-            },
             [&](const ast::Const*) {
                 return true;  // Constants are embedded at their use
             },
@@ -3030,28 +3026,6 @@
     return true;
 }
 
-bool GeneratorImpl::EmitProgramConstVariable(const ast::Let* let) {
-    auto* global = program_->Sem().Get<sem::GlobalVariable>(let);
-    auto* type = global->Type();
-
-    auto out = line();
-    out << "constant ";
-    if (!EmitType(out, type, program_->Symbols().NameFor(let->symbol))) {
-        return false;
-    }
-    out << " " << program_->Symbols().NameFor(let->symbol);
-
-    if (let->constructor != nullptr) {
-        out << " = ";
-        if (!EmitExpression(out, let->constructor)) {
-            return false;
-        }
-    }
-    out << ";";
-
-    return true;
-}
-
 bool GeneratorImpl::EmitOverride(const ast::Override* override) {
     auto* global = program_->Sem().Get<sem::GlobalVariable>(override);
     auto* type = global->Type();
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index f0d4e8c..ed0c35b 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -368,10 +368,6 @@
     /// @param let the variable to generate
     /// @returns true if the variable was emitted
     bool EmitLet(const ast::Let* let);
-    /// Handles generating a module-scope 'let' declaration
-    /// @param let the 'let' to emit
-    /// @returns true if the variable was emitted
-    bool EmitProgramConstVariable(const ast::Let* let);
     /// Handles generating a module-scope 'override' declaration
     /// @param override the 'override' to emit
     /// @returns true if the variable was emitted
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 155f703..c204686 100644
--- a/src/tint/writer/msl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/msl/generator_impl_module_constant_test.cc
@@ -22,16 +22,6 @@
 
 using MslGeneratorImplTest = TestHelper;
 
-TEST_F(MslGeneratorImplTest, Emit_GlobalLet) {
-    auto* var = GlobalLet("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-    EXPECT_EQ(gen.result(),
-              "constant tint_array<float, 3> pos = tint_array<float, 3>{1.0f, 2.0f, 3.0f};\n");
-}
-
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_AInt) {
     auto* var = GlobalConst("G", nullptr, Expr(1_a));
     Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 10d65a4..be33426 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -771,15 +771,7 @@
 
     uint32_t init_id = 0;
     if (auto* ctor = v->constructor) {
-        if (!v->Is<ast::Override>()) {
-            auto* ctor_sem = builder_.Sem().Get(ctor);
-            if (auto constant = ctor_sem->ConstantValue()) {
-                init_id = GenerateConstantIfNeeded(std::move(constant));
-            }
-        }
-        if (init_id == 0) {
-            init_id = GenerateConstructorExpression(v, v->constructor);
-        }
+        init_id = GenerateConstructorExpression(v, ctor);
         if (init_id == 0) {
             return false;
         }
@@ -817,7 +809,7 @@
         }
     }
 
-    if (v->IsAnyOf<ast::Let, ast::Override>()) {
+    if (v->Is<ast::Override>()) {
         push_debug(spv::Op::OpName,
                    {Operand(init_id), Operand(builder_.Symbols().NameFor(v->symbol))});
 
diff --git a/src/tint/writer/spirv/builder_accessor_expression_test.cc b/src/tint/writer/spirv/builder_accessor_expression_test.cc
index 7c8236b..8996b8d 100644
--- a/src/tint/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_accessor_expression_test.cc
@@ -42,12 +42,13 @@
 %8 = OpConstant %6 2
 %9 = OpConstant %6 3
 %10 = OpConstantComposite %5 %7 %8 %9
-%12 = OpTypePointer Function %6
-%13 = OpConstantNull %6
+%13 = OpTypePointer Function %6
+%14 = OpConstantNull %6
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%11 = OpVariable %12 Function %13
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%12 = OpVariable %13 Function %14
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %11 %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%11 = OpCompositeExtract %6 %10 1
+OpStore %12 %11
 OpReturn
 )");
 
@@ -303,13 +304,18 @@
 %16 = OpConstant %7 6
 %17 = OpConstantComposite %6 %14 %15 %16
 %18 = OpConstantComposite %5 %13 %17
-%20 = OpTypePointer Function %7
-%21 = OpConstantNull %7
+%19 = OpTypeInt 32 1
+%20 = OpConstant %19 1
+%22 = OpConstant %19 2
+%25 = OpTypePointer Function %7
+%26 = OpConstantNull %7
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%19 = OpVariable %20 Function %21
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(OpStore %19 %16
+              R"(%21 = OpCompositeExtract %6 %18 1
+%23 = OpCompositeExtract %7 %21 2
+OpStore %24 %23
 OpReturn
 )");
 
@@ -601,12 +607,16 @@
 %14 = OpConstantComposite %6 %13 %13
 %15 = OpConstantComposite %6 %11 %13
 %16 = OpConstantComposite %5 %12 %14 %15
-%18 = OpTypePointer Function %7
+%17 = OpConstant %8 1
+%19 = OpConstantNull %8
+%22 = OpTypePointer Function %7
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%17 = OpVariable %18 Function %10
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%21 = OpVariable %22 Function %10
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(OpStore %17 %13
+              R"(%18 = OpCompositeExtract %6 %16 1
+%20 = OpCompositeExtract %7 %18 0
+OpStore %21 %20
 OpReturn
 )");
 
@@ -756,12 +766,15 @@
 %12 = OpConstant %7 4
 %13 = OpConstantComposite %6 %11 %12
 %14 = OpConstantComposite %5 %10 %13
-%16 = OpTypePointer Function %6
-%17 = OpConstantNull %6
+%15 = OpTypeInt 32 1
+%16 = OpConstant %15 1
+%19 = OpTypePointer Function %6
+%20 = OpConstantNull %6
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%15 = OpVariable %16 Function %17
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%18 = OpVariable %19 Function %20
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %13
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%17 = OpCompositeExtract %6 %14 1
+OpStore %18 %17
 OpReturn
 )");
 
diff --git a/src/tint/writer/spirv/builder_constructor_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
index c1b95df..d8cb809 100644
--- a/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -1073,21 +1073,6 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_F32_With_F32) {
-    auto* ctor = Construct<f32>(2_f);
-    GlobalLet("g", ty.f32(), ctor);
-
-    spirv::Builder& b = SanitizeAndBuild();
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
-%2 = OpConstant %1 2
-%4 = OpTypeVoid
-%3 = OpTypeFunction %4
-)");
-    Validate(b);
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F32_With_F32) {
     auto* ctor = Construct<f32>(2_f);
     GlobalConst("g", ty.f32(), ctor);
@@ -1126,21 +1111,6 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_U32_With_F32) {
-    auto* ctor = Construct<u32>(1.5_f);
-    GlobalLet("g", ty.u32(), ctor);
-
-    spirv::Builder& b = SanitizeAndBuild();
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
-%2 = OpConstant %1 1
-%4 = OpTypeVoid
-%3 = OpTypeFunction %4
-)");
-    Validate(b);
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F32) {
     auto* ctor = Construct<u32>(1.5_f);
     GlobalConst("g", ty.u32(), ctor);
@@ -1179,22 +1149,6 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec2_With_F32) {
-    auto* cast = vec2<f32>(2_f);
-    auto* g = GlobalLet("g", ty.vec2<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F32) {
     auto* cast = vec2<f32>(2_f);
     GlobalConst("g", ty.vec2<f32>(), cast);
@@ -1234,24 +1188,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec2_With_Vec2) {
-    auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
-    GlobalLet("a", ty.vec2<f32>(), cast);
-
-    spirv::Builder& b = SanitizeAndBuild();
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
-)");
-
-    Validate(b);
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_Vec2) {
     auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec2<f32>(), cast);
@@ -1295,24 +1231,6 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec3_With_Vec3) {
-    auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
-    GlobalLet("a", ty.vec3<f32>(), cast);
-
-    spirv::Builder& b = SanitizeAndBuild();
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
-)");
-
-    Validate(b);
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec3) {
     auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1356,24 +1274,6 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_Vec4) {
-    auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
-    GlobalLet("a", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = SanitizeAndBuild();
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-%6 = OpTypeVoid
-%5 = OpTypeFunction %6
-)");
-
-    Validate(b);
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec4) {
     auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1416,22 +1316,6 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec3_With_F32) {
-    auto* cast = vec3<f32>(2_f);
-    auto* g = GlobalLet("g", ty.vec3<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32) {
     auto* cast = vec3<f32>(2_f);
     GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1471,22 +1355,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec3_With_F32_Vec2) {
-    auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
-    auto* g = GlobalLet("g", ty.vec3<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32_Vec2) {
     auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1526,22 +1394,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec3_With_Vec2_F32) {
-    auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
-    auto* g = GlobalLet("g", ty.vec3<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F32) {
     auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1581,22 +1433,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_F32) {
-    auto* cast = vec4<f32>(2_f);
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32) {
     auto* cast = vec4<f32>(2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1636,22 +1472,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_F32_F32_Vec2) {
-    auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_F32_Vec2) {
     auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1691,22 +1511,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_F32_Vec2_F32) {
-    auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec2_F32) {
     auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1746,22 +1550,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_Vec2_F32_F32) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F32_F32) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1801,22 +1589,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_Vec2_Vec2) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_Vec2) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1856,22 +1628,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_F32_Vec3) {
-    auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec3) {
     auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1911,22 +1667,6 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec4_With_Vec3_F32) {
-    auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
-    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpConstant %2 2
-%4 = OpConstantComposite %1 %3 %3 %3 %3
-)");
-}
-
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F32) {
     auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
diff --git a/src/tint/writer/spirv/builder_function_attribute_test.cc b/src/tint/writer/spirv/builder_function_attribute_test.cc
index 7bec69e..c309813 100644
--- a/src/tint/writer/spirv/builder_function_attribute_test.cc
+++ b/src/tint/writer/spirv/builder_function_attribute_test.cc
@@ -131,24 +131,6 @@
 )");
 }
 
-TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Let) {
-    GlobalLet("width", ty.i32(), Construct(ty.i32(), 2_i));
-    GlobalLet("height", ty.i32(), Construct(ty.i32(), 3_i));
-    GlobalLet("depth", ty.i32(), Construct(ty.i32(), 4_i));
-    auto* func = Func("main", {}, ty.void_(), {},
-                      {
-                          WorkgroupSize("width", "height", "depth"),
-                          Stage(ast::PipelineStage::kCompute),
-                      });
-
-    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
-)");
-}
-
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
     GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
     GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
@@ -197,33 +179,6 @@
 )");
 }
 
-TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndLet) {
-    Override("height", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
-    GlobalLet("depth", ty.i32(), Construct(ty.i32(), 3_i));
-    auto* func = Func("main", {}, ty.void_(), {},
-                      {
-                          WorkgroupSize(4_i, "height", "depth"),
-                          Stage(ast::PipelineStage::kCompute),
-                      });
-
-    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
-%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
-OpDecorate %3 BuiltIn WorkgroupSize
-)");
-}
-
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
     Override("height", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
     GlobalConst("depth", ty.i32(), Construct(ty.i32(), 3_i));
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index 8f0b481..9e9913c 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -61,26 +61,6 @@
 )");
 }
 
-TEST_F(BuilderTest, GlobalLet) {
-    auto* init = vec3<f32>(1_f, 1_f, 3_f);
-
-    auto* v = GlobalLet("l", ty.vec3<f32>(), init);
-
-    spirv::Builder& b = Build();
-
-    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-    ASSERT_FALSE(b.has_error()) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %5 "l"
-)");
-    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
-)");
-}
-
 TEST_F(BuilderTest, GlobalConst) {
     // const c = 42;
     // var v = c;
@@ -106,25 +86,6 @@
     Validate(b);
 }
 
-TEST_F(BuilderTest, GlobalLet_Vec_Constructor) {
-    auto* init = vec3<f32>(1_f, 2_f, 3_f);
-
-    auto* v = GlobalLet("l", ty.vec3<f32>(), init);
-
-    spirv::Builder& b = Build();
-
-    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-    ASSERT_FALSE(b.has_error()) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 1
-%4 = OpConstant %2 2
-%5 = OpConstant %2 3
-%6 = OpConstantComposite %1 %3 %4 %5
-)");
-}
-
 TEST_F(BuilderTest, GlobalConst_Vec_Constructor) {
     // const c = vec3<f32>(1f, 2f, 3f);
     // var v = c;
@@ -212,25 +173,6 @@
     Validate(b);
 }
 
-TEST_F(BuilderTest, GlobalLet_Nested_Vec_Constructor) {
-    auto* init = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
-
-    auto* v = GlobalLet("l", ty.vec3<f32>(), init);
-
-    spirv::Builder& b = Build();
-
-    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-    ASSERT_FALSE(b.has_error()) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 3
-%3 = OpConstant %2 1
-%4 = OpConstant %2 2
-%5 = OpConstant %2 3
-%6 = OpConstantComposite %1 %3 %4 %5
-)");
-}
-
 TEST_F(BuilderTest, GlobalConst_Nested_Vec_Constructor) {
     // const c = vec3<f32>(vec2<f32>(1f, 2f), 3f));
     // var v = c;
diff --git a/src/tint/writer/wgsl/generator_impl_function_test.cc b/src/tint/writer/wgsl/generator_impl_function_test.cc
index f21e71b..17439c7 100644
--- a/src/tint/writer/wgsl/generator_impl_function_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_function_test.cc
@@ -78,7 +78,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIdent) {
-    GlobalLet("height", ty.i32(), Expr(2_i));
+    GlobalConst("height", ty.i32(), Expr(2_i));
     auto* func = Func("my_func", {}, ty.void_(), {Return()},
                       {
                           Stage(ast::PipelineStage::kCompute),
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 19ff7d7..78b5d52 100644
--- a/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
@@ -131,21 +131,6 @@
     EXPECT_EQ(gen.result(), "  @group(0) @binding(0) var t : texture_1d<f32>;\n");
 }
 
-TEST_F(WgslGeneratorImplTest, Emit_GlobalLet) {
-    GlobalLet("explicit", ty.f32(), Expr(1_f));
-    GlobalLet("inferred", nullptr, Expr(1_f));
-
-    GeneratorImpl& gen = Build();
-
-    gen.increment_indent();
-
-    ASSERT_TRUE(gen.Generate()) << gen.error();
-    EXPECT_EQ(gen.result(), R"(  let explicit : f32 = 1.0f;
-
-  let inferred = 1.0f;
-)");
-}
-
 TEST_F(WgslGeneratorImplTest, Emit_GlobalConst) {
     GlobalConst("explicit", ty.f32(), Expr(1_f));
     GlobalConst("inferred", nullptr, Expr(1_f));
diff --git a/test/tint/access/let/matrix.wgsl.expected.glsl b/test/tint/access/let/matrix.wgsl.expected.glsl
index 6f4717b..0add115 100644
--- a/test/tint/access/let/matrix.wgsl.expected.glsl
+++ b/test/tint/access/let/matrix.wgsl.expected.glsl
@@ -2,8 +2,8 @@
 
 void tint_symbol() {
   mat3 m = mat3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));
-  vec3 v = vec3(4.0f, 5.0f, 6.0f);
-  float f = 5.0f;
+  vec3 v = m[1];
+  float f = v[1];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/access/let/matrix.wgsl.expected.hlsl b/test/tint/access/let/matrix.wgsl.expected.hlsl
index 4dcc54e..38129cf 100644
--- a/test/tint/access/let/matrix.wgsl.expected.hlsl
+++ b/test/tint/access/let/matrix.wgsl.expected.hlsl
@@ -1,7 +1,7 @@
 [numthreads(1, 1, 1)]
 void main() {
   const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  const float3 v = float3(4.0f, 5.0f, 6.0f);
-  const float f = 5.0f;
+  const float3 v = m[1];
+  const float f = v[1];
   return;
 }
diff --git a/test/tint/access/let/matrix.wgsl.expected.msl b/test/tint/access/let/matrix.wgsl.expected.msl
index a1b3e45..f8f945d 100644
--- a/test/tint/access/let/matrix.wgsl.expected.msl
+++ b/test/tint/access/let/matrix.wgsl.expected.msl
@@ -3,8 +3,8 @@
 using namespace metal;
 kernel void tint_symbol() {
   float3x3 const m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  float3 const v = float3(4.0f, 5.0f, 6.0f);
-  float const f = 5.0f;
+  float3 const v = m[1];
+  float const f = v[1];
   return;
 }
 
diff --git a/test/tint/access/let/matrix.wgsl.expected.spvasm b/test/tint/access/let/matrix.wgsl.expected.spvasm
index 47263bf..cbc5aca 100644
--- a/test/tint/access/let/matrix.wgsl.expected.spvasm
+++ b/test/tint/access/let/matrix.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 25
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -26,7 +26,11 @@
     %float_9 = OpConstant %float 9
          %19 = OpConstantComposite %v3float %float_7 %float_8 %float_9
          %20 = OpConstantComposite %mat3v3float %11 %15 %19
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
        %main = OpFunction %void None %1
           %4 = OpLabel
+         %23 = OpCompositeExtract %v3float %20 1
+         %24 = OpCompositeExtract %float %23 1
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/array/size.wgsl b/test/tint/array/size.wgsl
index f9135ad..4b2ec37 100644
--- a/test/tint/array/size.wgsl
+++ b/test/tint/array/size.wgsl
@@ -1,5 +1,5 @@
-let slen = 4;
-let ulen = 4u;
+const slen = 4;
+const ulen = 4u;
 
 @fragment
 fn main() {
diff --git a/test/tint/array/size.wgsl.expected.glsl b/test/tint/array/size.wgsl.expected.glsl
index 762d5c8..132511d 100644
--- a/test/tint/array/size.wgsl.expected.glsl
+++ b/test/tint/array/size.wgsl.expected.glsl
@@ -1,8 +1,6 @@
 #version 310 es
 precision mediump float;
 
-const int slen = 4;
-const uint ulen = 4u;
 void tint_symbol() {
   float signed_literal[4] = float[4](0.0f, 0.0f, 0.0f, 0.0f);
   float unsigned_literal[4] = float[4](0.0f, 0.0f, 0.0f, 0.0f);
diff --git a/test/tint/array/size.wgsl.expected.hlsl b/test/tint/array/size.wgsl.expected.hlsl
index e5fdbd3..4753dde 100644
--- a/test/tint/array/size.wgsl.expected.hlsl
+++ b/test/tint/array/size.wgsl.expected.hlsl
@@ -1,6 +1,3 @@
-static const int slen = 4;
-static const uint ulen = 4u;
-
 void main() {
   float signed_literal[4] = (float[4])0;
   float unsigned_literal[4] = (float[4])0;
diff --git a/test/tint/array/size.wgsl.expected.msl b/test/tint/array/size.wgsl.expected.msl
index 27994b2..f72c5aa 100644
--- a/test/tint/array/size.wgsl.expected.msl
+++ b/test/tint/array/size.wgsl.expected.msl
@@ -14,10 +14,6 @@
     T elements[N];
 };
 
-constant int slen = 4;
-
-constant uint ulen = 4u;
-
 fragment void tint_symbol() {
   tint_array<float, 4> signed_literal = {};
   tint_array<float, 4> unsigned_literal = {};
diff --git a/test/tint/array/size.wgsl.expected.spvasm b/test/tint/array/size.wgsl.expected.spvasm
index ada562b..ac1a0c9 100644
--- a/test/tint/array/size.wgsl.expected.spvasm
+++ b/test/tint/array/size.wgsl.expected.spvasm
@@ -1,39 +1,35 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 19
+; Bound: 17
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint Fragment %main "main"
                OpExecutionMode %main OriginUpperLeft
-               OpName %slen "slen"
-               OpName %ulen "ulen"
                OpName %main "main"
                OpName %signed_literal "signed_literal"
                OpName %unsigned_literal "unsigned_literal"
                OpName %signed_constant "signed_constant"
                OpName %unsigned_constant "unsigned_constant"
-               OpDecorate %_arr_float_ulen ArrayStride 4
-        %int = OpTypeInt 32 1
-       %slen = OpConstant %int 4
-       %uint = OpTypeInt 32 0
-       %ulen = OpConstant %uint 4
+               OpDecorate %_arr_float_uint_4 ArrayStride 4
        %void = OpTypeVoid
-          %5 = OpTypeFunction %void
+          %1 = OpTypeFunction %void
       %float = OpTypeFloat 32
-%_arr_float_ulen = OpTypeArray %float %ulen
-%_ptr_Function__arr_float_ulen = OpTypePointer Function %_arr_float_ulen
-         %13 = OpConstantNull %_arr_float_ulen
-       %main = OpFunction %void None %5
-          %8 = OpLabel
-%signed_literal = OpVariable %_ptr_Function__arr_float_ulen Function %13
-%unsigned_literal = OpVariable %_ptr_Function__arr_float_ulen Function %13
-%signed_constant = OpVariable %_ptr_Function__arr_float_ulen Function %13
-%unsigned_constant = OpVariable %_ptr_Function__arr_float_ulen Function %13
-         %17 = OpLoad %_arr_float_ulen %unsigned_constant
-               OpStore %signed_literal %17
-         %18 = OpLoad %_arr_float_ulen %unsigned_literal
-               OpStore %signed_constant %18
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_float_uint_4 = OpTypeArray %float %uint_4
+%_ptr_Function__arr_float_uint_4 = OpTypePointer Function %_arr_float_uint_4
+         %11 = OpConstantNull %_arr_float_uint_4
+       %main = OpFunction %void None %1
+          %4 = OpLabel
+%signed_literal = OpVariable %_ptr_Function__arr_float_uint_4 Function %11
+%unsigned_literal = OpVariable %_ptr_Function__arr_float_uint_4 Function %11
+%signed_constant = OpVariable %_ptr_Function__arr_float_uint_4 Function %11
+%unsigned_constant = OpVariable %_ptr_Function__arr_float_uint_4 Function %11
+         %15 = OpLoad %_arr_float_uint_4 %unsigned_constant
+               OpStore %signed_literal %15
+         %16 = OpLoad %_arr_float_uint_4 %unsigned_literal
+               OpStore %signed_constant %16
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/array/size.wgsl.expected.wgsl b/test/tint/array/size.wgsl.expected.wgsl
index 7b6efc6..a82c377 100644
--- a/test/tint/array/size.wgsl.expected.wgsl
+++ b/test/tint/array/size.wgsl.expected.wgsl
@@ -1,6 +1,6 @@
-let slen = 4;
+const slen = 4;
 
-let ulen = 4u;
+const ulen = 4u;
 
 @fragment
 fn main() {
diff --git a/test/tint/array/type_constructor.wgsl.expected.glsl b/test/tint/array/type_constructor.wgsl.expected.glsl
index a9c5edf..82b9843 100644
--- a/test/tint/array/type_constructor.wgsl.expected.glsl
+++ b/test/tint/array/type_constructor.wgsl.expected.glsl
@@ -4,35 +4,35 @@
   int x = 42;
   int empty[4] = int[4](0, 0, 0, 0);
   int nonempty[4] = int[4](1, 2, 3, 4);
-  int nonempty_with_expr[4] = int[4](1, x, (x + 1), 4);
+  int nonempty_with_expr[4] = int[4](1, x, (x + 1), nonempty[3]);
   int nested_empty[2][3][4] = int[2][3][4](int[3][4](int[4](0, 0, 0, 0), int[4](0, 0, 0, 0), int[4](0, 0, 0, 0)), int[3][4](int[4](0, 0, 0, 0), int[4](0, 0, 0, 0), int[4](0, 0, 0, 0)));
   int tint_symbol_1[4] = int[4](1, 2, 3, 4);
   int tint_symbol_2[4] = int[4](5, 6, 7, 8);
   int tint_symbol_3[4] = int[4](9, 10, 11, 12);
-  int tint_symbol_4[3][4] = int[3][4](int[4](1, 2, 3, 4), int[4](5, 6, 7, 8), int[4](9, 10, 11, 12));
+  int tint_symbol_4[3][4] = int[3][4](tint_symbol_1, tint_symbol_2, tint_symbol_3);
   int tint_symbol_5[4] = int[4](13, 14, 15, 16);
   int tint_symbol_6[4] = int[4](17, 18, 19, 20);
   int tint_symbol_7[4] = int[4](21, 22, 23, 24);
-  int tint_symbol_8[3][4] = int[3][4](int[4](13, 14, 15, 16), int[4](17, 18, 19, 20), int[4](21, 22, 23, 24));
-  int nested_nonempty[2][3][4] = int[2][3][4](int[3][4](int[4](1, 2, 3, 4), int[4](5, 6, 7, 8), int[4](9, 10, 11, 12)), int[3][4](int[4](13, 14, 15, 16), int[4](17, 18, 19, 20), int[4](21, 22, 23, 24)));
+  int tint_symbol_8[3][4] = int[3][4](tint_symbol_5, tint_symbol_6, tint_symbol_7);
+  int nested_nonempty[2][3][4] = int[2][3][4](tint_symbol_4, tint_symbol_8);
   int tint_symbol_9[4] = int[4](1, 2, x, (x + 1));
-  int tint_symbol_10[4] = int[4](5, 6, 3, (4 + 1));
+  int tint_symbol_10[4] = int[4](5, 6, nonempty[2], (nonempty[3] + 1));
   int tint_symbol_11[3][4] = int[3][4](tint_symbol_9, tint_symbol_10, nonempty);
-  int nested_nonempty_with_expr[2][3][4] = int[2][3][4](tint_symbol_11, int[3][4](int[4](13, 14, 15, 16), int[4](17, 18, 19, 20), int[4](21, 22, 23, 24)));
+  int nested_nonempty_with_expr[2][3][4] = int[2][3][4](tint_symbol_11, nested_nonempty[1]);
   int tint_symbol_12[4] = int[4](0, 0, 0, 0);
-  int subexpr_empty = 0;
+  int subexpr_empty = tint_symbol_12[1];
   int tint_symbol_13[4] = int[4](1, 2, 3, 4);
-  int subexpr_nonempty = 3;
-  int tint_symbol_14[4] = int[4](1, x, (x + 1), 4);
+  int subexpr_nonempty = tint_symbol_13[2];
+  int tint_symbol_14[4] = int[4](1, x, (x + 1), nonempty[3]);
   int subexpr_nonempty_with_expr = tint_symbol_14[2];
   int tint_symbol_15[2][4] = int[2][4](int[4](0, 0, 0, 0), int[4](0, 0, 0, 0));
-  int subexpr_nested_empty[4] = int[4](0, 0, 0, 0);
+  int subexpr_nested_empty[4] = tint_symbol_15[1];
   int tint_symbol_16[4] = int[4](1, 2, 3, 4);
   int tint_symbol_17[4] = int[4](5, 6, 7, 8);
-  int tint_symbol_18[2][4] = int[2][4](int[4](1, 2, 3, 4), int[4](5, 6, 7, 8));
-  int subexpr_nested_nonempty[4] = int[4](5, 6, 7, 8);
-  int tint_symbol_19[4] = int[4](1, x, (x + 1), 4);
-  int tint_symbol_20[2][4] = int[2][4](tint_symbol_19, int[4](21, 22, 23, 24));
+  int tint_symbol_18[2][4] = int[2][4](tint_symbol_16, tint_symbol_17);
+  int subexpr_nested_nonempty[4] = tint_symbol_18[1];
+  int tint_symbol_19[4] = int[4](1, x, (x + 1), nonempty[3]);
+  int tint_symbol_20[2][4] = int[2][4](tint_symbol_19, nested_nonempty[1][2]);
   int subexpr_nested_nonempty_with_expr[4] = tint_symbol_20[1];
 }
 
diff --git a/test/tint/array/type_constructor.wgsl.expected.hlsl b/test/tint/array/type_constructor.wgsl.expected.hlsl
index 64829e1..8640324 100644
--- a/test/tint/array/type_constructor.wgsl.expected.hlsl
+++ b/test/tint/array/type_constructor.wgsl.expected.hlsl
@@ -3,35 +3,35 @@
   const int x = 42;
   const int empty[4] = (int[4])0;
   const int nonempty[4] = {1, 2, 3, 4};
-  const int nonempty_with_expr[4] = {1, x, (x + 1), 4};
+  const int nonempty_with_expr[4] = {1, x, (x + 1), nonempty[3]};
   const int nested_empty[2][3][4] = (int[2][3][4])0;
   const int tint_symbol[4] = {1, 2, 3, 4};
   const int tint_symbol_1[4] = {5, 6, 7, 8};
   const int tint_symbol_2[4] = {9, 10, 11, 12};
-  const int tint_symbol_3[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
+  const int tint_symbol_3[3][4] = {tint_symbol, tint_symbol_1, tint_symbol_2};
   const int tint_symbol_4[4] = {13, 14, 15, 16};
   const int tint_symbol_5[4] = {17, 18, 19, 20};
   const int tint_symbol_6[4] = {21, 22, 23, 24};
-  const int tint_symbol_7[3][4] = {{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}};
-  const int nested_nonempty[2][3][4] = {{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, {{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}};
+  const int tint_symbol_7[3][4] = {tint_symbol_4, tint_symbol_5, tint_symbol_6};
+  const int nested_nonempty[2][3][4] = {tint_symbol_3, tint_symbol_7};
   const int tint_symbol_8[4] = {1, 2, x, (x + 1)};
-  const int tint_symbol_9[4] = {5, 6, 3, (4 + 1)};
+  const int tint_symbol_9[4] = {5, 6, nonempty[2], (nonempty[3] + 1)};
   const int tint_symbol_10[3][4] = {tint_symbol_8, tint_symbol_9, nonempty};
-  const int nested_nonempty_with_expr[2][3][4] = {tint_symbol_10, {{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}};
+  const int nested_nonempty_with_expr[2][3][4] = {tint_symbol_10, nested_nonempty[1]};
   const int tint_symbol_11[4] = (int[4])0;
-  const int subexpr_empty = 0;
+  const int subexpr_empty = tint_symbol_11[1];
   const int tint_symbol_12[4] = {1, 2, 3, 4};
-  const int subexpr_nonempty = 3;
-  const int tint_symbol_13[4] = {1, x, (x + 1), 4};
+  const int subexpr_nonempty = tint_symbol_12[2];
+  const int tint_symbol_13[4] = {1, x, (x + 1), nonempty[3]};
   const int subexpr_nonempty_with_expr = tint_symbol_13[2];
   const int tint_symbol_14[2][4] = (int[2][4])0;
-  const int subexpr_nested_empty[4] = (int[4])0;
+  const int subexpr_nested_empty[4] = tint_symbol_14[1];
   const int tint_symbol_15[4] = {1, 2, 3, 4};
   const int tint_symbol_16[4] = {5, 6, 7, 8};
-  const int tint_symbol_17[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
-  const int subexpr_nested_nonempty[4] = {5, 6, 7, 8};
-  const int tint_symbol_18[4] = {1, x, (x + 1), 4};
-  const int tint_symbol_19[2][4] = {tint_symbol_18, {21, 22, 23, 24}};
+  const int tint_symbol_17[2][4] = {tint_symbol_15, tint_symbol_16};
+  const int subexpr_nested_nonempty[4] = tint_symbol_17[1];
+  const int tint_symbol_18[4] = {1, x, (x + 1), nonempty[3]};
+  const int tint_symbol_19[2][4] = {tint_symbol_18, nested_nonempty[1][2]};
   const int subexpr_nested_nonempty_with_expr[4] = tint_symbol_19[1];
   return;
 }
diff --git a/test/tint/array/type_constructor.wgsl.expected.msl b/test/tint/array/type_constructor.wgsl.expected.msl
index 54c3dfd..d2ca398 100644
--- a/test/tint/array/type_constructor.wgsl.expected.msl
+++ b/test/tint/array/type_constructor.wgsl.expected.msl
@@ -18,35 +18,35 @@
   int const x = 42;
   tint_array<int, 4> const empty = tint_array<int, 4>{};
   tint_array<int, 4> const nonempty = tint_array<int, 4>{1, 2, 3, 4};
-  tint_array<int, 4> const nonempty_with_expr = tint_array<int, 4>{1, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1))), 4};
+  tint_array<int, 4> const nonempty_with_expr = tint_array<int, 4>{1, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1))), nonempty[3]};
   tint_array<tint_array<tint_array<int, 4>, 3>, 2> const nested_empty = tint_array<tint_array<tint_array<int, 4>, 3>, 2>{};
   tint_array<int, 4> const tint_symbol_1 = tint_array<int, 4>{1, 2, 3, 4};
   tint_array<int, 4> const tint_symbol_2 = tint_array<int, 4>{5, 6, 7, 8};
   tint_array<int, 4> const tint_symbol_3 = tint_array<int, 4>{9, 10, 11, 12};
-  tint_array<tint_array<int, 4>, 3> const tint_symbol_4 = tint_array<tint_array<int, 4>, 3>{tint_array<int, 4>{1, 2, 3, 4}, tint_array<int, 4>{5, 6, 7, 8}, tint_array<int, 4>{9, 10, 11, 12}};
+  tint_array<tint_array<int, 4>, 3> const tint_symbol_4 = tint_array<tint_array<int, 4>, 3>{tint_symbol_1, tint_symbol_2, tint_symbol_3};
   tint_array<int, 4> const tint_symbol_5 = tint_array<int, 4>{13, 14, 15, 16};
   tint_array<int, 4> const tint_symbol_6 = tint_array<int, 4>{17, 18, 19, 20};
   tint_array<int, 4> const tint_symbol_7 = tint_array<int, 4>{21, 22, 23, 24};
-  tint_array<tint_array<int, 4>, 3> const tint_symbol_8 = tint_array<tint_array<int, 4>, 3>{tint_array<int, 4>{13, 14, 15, 16}, tint_array<int, 4>{17, 18, 19, 20}, tint_array<int, 4>{21, 22, 23, 24}};
-  tint_array<tint_array<tint_array<int, 4>, 3>, 2> const nested_nonempty = tint_array<tint_array<tint_array<int, 4>, 3>, 2>{tint_array<tint_array<int, 4>, 3>{tint_array<int, 4>{1, 2, 3, 4}, tint_array<int, 4>{5, 6, 7, 8}, tint_array<int, 4>{9, 10, 11, 12}}, tint_array<tint_array<int, 4>, 3>{tint_array<int, 4>{13, 14, 15, 16}, tint_array<int, 4>{17, 18, 19, 20}, tint_array<int, 4>{21, 22, 23, 24}}};
+  tint_array<tint_array<int, 4>, 3> const tint_symbol_8 = tint_array<tint_array<int, 4>, 3>{tint_symbol_5, tint_symbol_6, tint_symbol_7};
+  tint_array<tint_array<tint_array<int, 4>, 3>, 2> const nested_nonempty = tint_array<tint_array<tint_array<int, 4>, 3>, 2>{tint_symbol_4, tint_symbol_8};
   tint_array<int, 4> const tint_symbol_9 = tint_array<int, 4>{1, 2, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1)))};
-  tint_array<int, 4> const tint_symbol_10 = tint_array<int, 4>{5, 6, 3, as_type<int>((as_type<uint>(4) + as_type<uint>(1)))};
+  tint_array<int, 4> const tint_symbol_10 = tint_array<int, 4>{5, 6, nonempty[2], as_type<int>((as_type<uint>(nonempty[3]) + as_type<uint>(1)))};
   tint_array<tint_array<int, 4>, 3> const tint_symbol_11 = tint_array<tint_array<int, 4>, 3>{tint_symbol_9, tint_symbol_10, nonempty};
-  tint_array<tint_array<tint_array<int, 4>, 3>, 2> const nested_nonempty_with_expr = tint_array<tint_array<tint_array<int, 4>, 3>, 2>{tint_symbol_11, tint_array<tint_array<int, 4>, 3>{tint_array<int, 4>{13, 14, 15, 16}, tint_array<int, 4>{17, 18, 19, 20}, tint_array<int, 4>{21, 22, 23, 24}}};
+  tint_array<tint_array<tint_array<int, 4>, 3>, 2> const nested_nonempty_with_expr = tint_array<tint_array<tint_array<int, 4>, 3>, 2>{tint_symbol_11, nested_nonempty[1]};
   tint_array<int, 4> const tint_symbol_12 = tint_array<int, 4>{};
-  int const subexpr_empty = 0;
+  int const subexpr_empty = tint_symbol_12[1];
   tint_array<int, 4> const tint_symbol_13 = tint_array<int, 4>{1, 2, 3, 4};
-  int const subexpr_nonempty = 3;
-  tint_array<int, 4> const tint_symbol_14 = tint_array<int, 4>{1, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1))), 4};
+  int const subexpr_nonempty = tint_symbol_13[2];
+  tint_array<int, 4> const tint_symbol_14 = tint_array<int, 4>{1, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1))), nonempty[3]};
   int const subexpr_nonempty_with_expr = tint_symbol_14[2];
   tint_array<tint_array<int, 4>, 2> const tint_symbol_15 = tint_array<tint_array<int, 4>, 2>{};
-  tint_array<int, 4> const subexpr_nested_empty = tint_array<int, 4>{};
+  tint_array<int, 4> const subexpr_nested_empty = tint_symbol_15[1];
   tint_array<int, 4> const tint_symbol_16 = tint_array<int, 4>{1, 2, 3, 4};
   tint_array<int, 4> const tint_symbol_17 = tint_array<int, 4>{5, 6, 7, 8};
-  tint_array<tint_array<int, 4>, 2> const tint_symbol_18 = tint_array<tint_array<int, 4>, 2>{tint_array<int, 4>{1, 2, 3, 4}, tint_array<int, 4>{5, 6, 7, 8}};
-  tint_array<int, 4> const subexpr_nested_nonempty = tint_array<int, 4>{5, 6, 7, 8};
-  tint_array<int, 4> const tint_symbol_19 = tint_array<int, 4>{1, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1))), 4};
-  tint_array<tint_array<int, 4>, 2> const tint_symbol_20 = tint_array<tint_array<int, 4>, 2>{tint_symbol_19, tint_array<int, 4>{21, 22, 23, 24}};
+  tint_array<tint_array<int, 4>, 2> const tint_symbol_18 = tint_array<tint_array<int, 4>, 2>{tint_symbol_16, tint_symbol_17};
+  tint_array<int, 4> const subexpr_nested_nonempty = tint_symbol_18[1];
+  tint_array<int, 4> const tint_symbol_19 = tint_array<int, 4>{1, x, as_type<int>((as_type<uint>(x) + as_type<uint>(1))), nonempty[3]};
+  tint_array<tint_array<int, 4>, 2> const tint_symbol_20 = tint_array<tint_array<int, 4>, 2>{tint_symbol_19, nested_nonempty[1][2]};
   tint_array<int, 4> const subexpr_nested_nonempty_with_expr = tint_symbol_20[1];
   return;
 }
diff --git a/test/tint/array/type_constructor.wgsl.expected.spvasm b/test/tint/array/type_constructor.wgsl.expected.spvasm
index 7c39af8..5d4084d 100644
--- a/test/tint/array/type_constructor.wgsl.expected.spvasm
+++ b/test/tint/array/type_constructor.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 66
+; Bound: 74
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -29,53 +29,61 @@
 %_arr__arr_int_uint_4_uint_3 = OpTypeArray %_arr_int_uint_4 %uint_3
      %uint_2 = OpConstant %uint 2
 %_arr__arr__arr_int_uint_4_uint_3_uint_2 = OpTypeArray %_arr__arr_int_uint_4_uint_3 %uint_2
-         %22 = OpConstantNull %_arr__arr__arr_int_uint_4_uint_3_uint_2
+         %23 = OpConstantNull %_arr__arr__arr_int_uint_4_uint_3_uint_2
       %int_5 = OpConstant %int 5
       %int_6 = OpConstant %int 6
       %int_7 = OpConstant %int 7
       %int_8 = OpConstant %int 8
-         %27 = OpConstantComposite %_arr_int_uint_4 %int_5 %int_6 %int_7 %int_8
+         %28 = OpConstantComposite %_arr_int_uint_4 %int_5 %int_6 %int_7 %int_8
       %int_9 = OpConstant %int 9
      %int_10 = OpConstant %int 10
      %int_11 = OpConstant %int 11
      %int_12 = OpConstant %int 12
-         %32 = OpConstantComposite %_arr_int_uint_4 %int_9 %int_10 %int_11 %int_12
-         %33 = OpConstantComposite %_arr__arr_int_uint_4_uint_3 %15 %27 %32
+         %33 = OpConstantComposite %_arr_int_uint_4 %int_9 %int_10 %int_11 %int_12
+         %34 = OpConstantComposite %_arr__arr_int_uint_4_uint_3 %15 %28 %33
      %int_13 = OpConstant %int 13
      %int_14 = OpConstant %int 14
      %int_15 = OpConstant %int 15
      %int_16 = OpConstant %int 16
-         %38 = OpConstantComposite %_arr_int_uint_4 %int_13 %int_14 %int_15 %int_16
+         %39 = OpConstantComposite %_arr_int_uint_4 %int_13 %int_14 %int_15 %int_16
      %int_17 = OpConstant %int 17
      %int_18 = OpConstant %int 18
      %int_19 = OpConstant %int 19
      %int_20 = OpConstant %int 20
-         %43 = OpConstantComposite %_arr_int_uint_4 %int_17 %int_18 %int_19 %int_20
+         %44 = OpConstantComposite %_arr_int_uint_4 %int_17 %int_18 %int_19 %int_20
      %int_21 = OpConstant %int 21
      %int_22 = OpConstant %int 22
      %int_23 = OpConstant %int 23
      %int_24 = OpConstant %int 24
-         %48 = OpConstantComposite %_arr_int_uint_4 %int_21 %int_22 %int_23 %int_24
-         %49 = OpConstantComposite %_arr__arr_int_uint_4_uint_3 %38 %43 %48
-         %50 = OpConstantComposite %_arr__arr__arr_int_uint_4_uint_3_uint_2 %33 %49
-         %57 = OpConstantNull %int
+         %49 = OpConstantComposite %_arr_int_uint_4 %int_21 %int_22 %int_23 %int_24
+         %50 = OpConstantComposite %_arr__arr_int_uint_4_uint_3 %39 %44 %49
+         %51 = OpConstantComposite %_arr__arr__arr_int_uint_4_uint_3_uint_2 %34 %50
+         %61 = OpConstantNull %int
 %_arr__arr_int_uint_4_uint_2 = OpTypeArray %_arr_int_uint_4 %uint_2
        %main = OpFunction %void None %1
           %4 = OpLabel
          %16 = OpIAdd %int %int_42 %int_1
-         %17 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_42 %16 %int_4
-         %51 = OpIAdd %int %int_42 %int_1
-         %52 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_2 %int_42 %51
-         %53 = OpIAdd %int %int_4 %int_1
-         %54 = OpCompositeConstruct %_arr_int_uint_4 %int_5 %int_6 %int_3 %53
-         %55 = OpCompositeConstruct %_arr__arr_int_uint_4_uint_3 %52 %54 %15
-         %56 = OpCompositeConstruct %_arr__arr__arr_int_uint_4_uint_3_uint_2 %55 %49
-         %58 = OpIAdd %int %int_42 %int_1
-         %59 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_42 %58 %int_4
-         %60 = OpCompositeExtract %int %59 2
+         %17 = OpCompositeExtract %int %15 3
+         %18 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_42 %16 %17
+         %52 = OpIAdd %int %int_42 %int_1
+         %53 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_2 %int_42 %52
+         %54 = OpCompositeExtract %int %15 2
+         %55 = OpCompositeExtract %int %15 3
+         %56 = OpIAdd %int %55 %int_1
+         %57 = OpCompositeConstruct %_arr_int_uint_4 %int_5 %int_6 %54 %56
+         %58 = OpCompositeConstruct %_arr__arr_int_uint_4_uint_3 %53 %57 %15
+         %59 = OpCompositeExtract %_arr__arr_int_uint_4_uint_3 %51 1
+         %60 = OpCompositeConstruct %_arr__arr__arr_int_uint_4_uint_3_uint_2 %58 %59
          %62 = OpIAdd %int %int_42 %int_1
-         %63 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_42 %62 %int_4
-         %64 = OpCompositeConstruct %_arr__arr_int_uint_4_uint_2 %63 %48
-         %65 = OpCompositeExtract %_arr_int_uint_4 %64 1
+         %63 = OpCompositeExtract %int %15 3
+         %64 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_42 %62 %63
+         %65 = OpCompositeExtract %int %64 2
+         %67 = OpIAdd %int %int_42 %int_1
+         %68 = OpCompositeExtract %int %15 3
+         %69 = OpCompositeConstruct %_arr_int_uint_4 %int_1 %int_42 %67 %68
+         %70 = OpCompositeExtract %_arr__arr_int_uint_4_uint_3 %51 1
+         %71 = OpCompositeExtract %_arr_int_uint_4 %70 2
+         %72 = OpCompositeConstruct %_arr__arr_int_uint_4_uint_2 %69 %71
+         %73 = OpCompositeExtract %_arr_int_uint_4 %72 1
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/benchmark/bloom-vertical-blur.wgsl b/test/tint/benchmark/bloom-vertical-blur.wgsl
index 3754c10..f95264b 100644
--- a/test/tint/benchmark/bloom-vertical-blur.wgsl
+++ b/test/tint/benchmark/bloom-vertical-blur.wgsl
@@ -1,4 +1,4 @@
-let bloomDir = vec2(0.0, 1.0);
+const bloomDir = vec2(0.0, 1.0);
 
 var<private> offsets : array<f32, 3> = array<f32, 3>(0.0, 1.384615421, 3.230769157);
 
diff --git a/test/tint/benchmark/cluster-lights.wgsl b/test/tint/benchmark/cluster-lights.wgsl
index c6eacc4..d29aab3 100644
--- a/test/tint/benchmark/cluster-lights.wgsl
+++ b/test/tint/benchmark/cluster-lights.wgsl
@@ -53,7 +53,7 @@
 
 @group(0) @binding(3) var<storage, read> globalLights : GlobalLights;
 
-let tileCount = vec3(32u, 18u, 48u);
+const tileCount = vec3(32u, 18u, 48u);
 
 fn linearDepth(depthSample : f32) -> f32 {
   return ((camera.zFar * camera.zNear) / fma(depthSample, (camera.zNear - camera.zFar), camera.zFar));
diff --git a/test/tint/benchmark/shadow-fragment.wgsl b/test/tint/benchmark/shadow-fragment.wgsl
index 29eee86..c2da838 100644
--- a/test/tint/benchmark/shadow-fragment.wgsl
+++ b/test/tint/benchmark/shadow-fragment.wgsl
@@ -21,9 +21,9 @@
   fragNorm : vec3<f32>,
 }
 
-let albedo : vec3<f32> = vec3<f32>(0.899999976, 0.899999976, 0.899999976);
+const albedo : vec3<f32> = vec3<f32>(0.899999976, 0.899999976, 0.899999976);
 
-let ambientFactor : f32 = 0.200000003;
+const ambientFactor : f32 = 0.200000003;
 
 @fragment
 fn main(input : FragmentInput) -> @location(0) vec4<f32> {
diff --git a/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl b/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl
index eb1c0b0..d0f8354 100644
--- a/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl
+++ b/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl
@@ -1,4 +1,4 @@
-let GAMMA = 2.200000048;
+const GAMMA = 2.200000048;
 
 fn linearTosRGB(linear : vec3<f32>) -> vec3<f32> {
   let INV_GAMMA = (1.0 / GAMMA);
@@ -53,7 +53,7 @@
 
 @binding(2) @group(0) var<storage, read> globalLights : GlobalLights;
 
-let tileCount = vec3(32u, 18u, 48u);
+const tileCount = vec3(32u, 18u, 48u);
 
 fn linearDepth(depthSample : f32) -> f32 {
   return ((camera.zFar * camera.zNear) / fma(depthSample, (camera.zNear - camera.zFar), camera.zFar));
@@ -85,7 +85,7 @@
 
 var<private> shadowSampleOffsets : array<vec2<f32>, 16> = array<vec2<f32>, 16>(vec2(-1.5, -1.5), vec2(-1.5, -0.5), vec2(-1.5, 0.5), vec2(-1.5, 1.5), vec2(-0.5, -1.5), vec2(-0.5, -0.5), vec2(-0.5, 0.5), vec2(-0.5, 1.5), vec2(0.5, -1.5), vec2(0.5, -0.5), vec2(0.5, 0.5), vec2(0.5, 1.5), vec2(1.5, -1.5), vec2(1.5, -0.5), vec2(1.5, 0.5), vec2(1.5, 1.5));
 
-let shadowSampleCount = 16u;
+const shadowSampleCount = 16u;
 
 struct ShadowProperties {
   viewport : vec4<f32>,
@@ -249,13 +249,13 @@
   return surface;
 }
 
-let PI = 3.141592741;
+const PI = 3.141592741;
 
-let LightType_Point = 0u;
+const LightType_Point = 0u;
 
-let LightType_Spot = 1u;
+const LightType_Spot = 1u;
 
-let LightType_Directional = 2u;
+const LightType_Directional = 2u;
 
 struct PuctualLight {
   lightType : u32,
diff --git a/test/tint/bug/chromium/1221120.wgsl b/test/tint/bug/chromium/1221120.wgsl
index d36adc1..1781a8c1 100644
--- a/test/tint/bug/chromium/1221120.wgsl
+++ b/test/tint/bug/chromium/1221120.wgsl
@@ -1,2 +1,2 @@
-let
+const
 H=1;
diff --git a/test/tint/bug/chromium/1221120.wgsl.expected.glsl b/test/tint/bug/chromium/1221120.wgsl.expected.glsl
index 5274814..6473d30 100644
--- a/test/tint/bug/chromium/1221120.wgsl.expected.glsl
+++ b/test/tint/bug/chromium/1221120.wgsl.expected.glsl
@@ -4,4 +4,3 @@
 void unused_entry_point() {
   return;
 }
-const int H = 1;
diff --git a/test/tint/bug/chromium/1221120.wgsl.expected.hlsl b/test/tint/bug/chromium/1221120.wgsl.expected.hlsl
index d79e95b..051e8c3 100644
--- a/test/tint/bug/chromium/1221120.wgsl.expected.hlsl
+++ b/test/tint/bug/chromium/1221120.wgsl.expected.hlsl
@@ -3,4 +3,3 @@
   return;
 }
 
-static const int H = 1;
diff --git a/test/tint/bug/chromium/1221120.wgsl.expected.msl b/test/tint/bug/chromium/1221120.wgsl.expected.msl
index 0c40f2b..466ceaa 100644
--- a/test/tint/bug/chromium/1221120.wgsl.expected.msl
+++ b/test/tint/bug/chromium/1221120.wgsl.expected.msl
@@ -1,5 +1,3 @@
 #include <metal_stdlib>
 
 using namespace metal;
-constant int H = 1;
-
diff --git a/test/tint/bug/chromium/1221120.wgsl.expected.spvasm b/test/tint/bug/chromium/1221120.wgsl.expected.spvasm
index 2ab63a4..65bef94 100644
--- a/test/tint/bug/chromium/1221120.wgsl.expected.spvasm
+++ b/test/tint/bug/chromium/1221120.wgsl.expected.spvasm
@@ -1,19 +1,16 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 7
+; Bound: 5
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
-               OpName %H "H"
                OpName %unused_entry_point "unused_entry_point"
-        %int = OpTypeInt 32 1
-          %H = OpConstant %int 1
        %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-%unused_entry_point = OpFunction %void None %3
-          %6 = OpLabel
+          %1 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/chromium/1221120.wgsl.expected.wgsl b/test/tint/bug/chromium/1221120.wgsl.expected.wgsl
index 2e0a5a5..2b66778 100644
--- a/test/tint/bug/chromium/1221120.wgsl.expected.wgsl
+++ b/test/tint/bug/chromium/1221120.wgsl.expected.wgsl
@@ -1 +1 @@
-let H = 1;
+const H = 1;
diff --git a/test/tint/bug/tint/1121.wgsl.expected.glsl b/test/tint/bug/tint/1121.wgsl.expected.glsl
index 5133c72..da9bf0f 100644
--- a/test/tint/bug/tint/1121.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1121.wgsl.expected.glsl
@@ -84,7 +84,7 @@
         for(int x_1 = 0; (x_1 < TILE_COUNT_X); x_1 = (x_1 + 1)) {
           ivec2 tilePixel0Idx = ivec2((x_1 * TILE_SIZE), (y_1 * TILE_SIZE));
           vec2 floorCoord = (((2.0f * vec2(tilePixel0Idx)) / uniforms.fullScreenSize.xy) - vec2(1.0f));
-          vec2 ceilCoord = (((2.0f * vec2((tilePixel0Idx + ivec2(16)))) / uniforms.fullScreenSize.xy) - vec2(1.0f));
+          vec2 ceilCoord = (((2.0f * vec2((tilePixel0Idx + ivec2(TILE_SIZE)))) / uniforms.fullScreenSize.xy) - vec2(1.0f));
           vec2 viewFloorCoord = vec2((((-(viewNear) * floorCoord.x) - (M[2][0] * viewNear)) / M[0][0]), (((-(viewNear) * floorCoord.y) - (M[2][1] * viewNear)) / M[1][1]));
           vec2 viewCeilCoord = vec2((((-(viewNear) * ceilCoord.x) - (M[2][0] * viewNear)) / M[0][0]), (((-(viewNear) * ceilCoord.y) - (M[2][1] * viewNear)) / M[1][1]));
           frustumPlanes[0] = vec4(1.0f, 0.0f, (-(viewFloorCoord.x) / viewNear), 0.0f);
diff --git a/test/tint/bug/tint/1121.wgsl.expected.hlsl b/test/tint/bug/tint/1121.wgsl.expected.hlsl
index 6f609be..bfff463 100644
--- a/test/tint/bug/tint/1121.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/1121.wgsl.expected.hlsl
@@ -58,7 +58,7 @@
         [loop] for(int x_1 = 0; (x_1 < TILE_COUNT_X); x_1 = (x_1 + 1)) {
           int2 tilePixel0Idx = int2((x_1 * TILE_SIZE), (y_1 * TILE_SIZE));
           float2 floorCoord = (((2.0f * float2(tilePixel0Idx)) / asfloat(uniforms[10]).xy) - (1.0f).xx);
-          float2 ceilCoord = (((2.0f * float2((tilePixel0Idx + (16).xx))) / asfloat(uniforms[10]).xy) - (1.0f).xx);
+          float2 ceilCoord = (((2.0f * float2((tilePixel0Idx + int2((TILE_SIZE).xx)))) / asfloat(uniforms[10]).xy) - (1.0f).xx);
           float2 viewFloorCoord = float2((((-(viewNear) * floorCoord.x) - (M[2][0] * viewNear)) / M[0][0]), (((-(viewNear) * floorCoord.y) - (M[2][1] * viewNear)) / M[1][1]));
           float2 viewCeilCoord = float2((((-(viewNear) * ceilCoord.x) - (M[2][0] * viewNear)) / M[0][0]), (((-(viewNear) * ceilCoord.y) - (M[2][1] * viewNear)) / M[1][1]));
           frustumPlanes[0] = float4(1.0f, 0.0f, (-(viewFloorCoord.x) / viewNear), 0.0f);
diff --git a/test/tint/bug/tint/1121.wgsl.expected.msl b/test/tint/bug/tint/1121.wgsl.expected.msl
index 8e2584d..ca262ff 100644
--- a/test/tint/bug/tint/1121.wgsl.expected.msl
+++ b/test/tint/bug/tint/1121.wgsl.expected.msl
@@ -88,7 +88,7 @@
     for(int x_1 = 0; (x_1 < TILE_COUNT_X); x_1 = as_type<int>((as_type<uint>(x_1) + as_type<uint>(1)))) {
       int2 tilePixel0Idx = int2(as_type<int>((as_type<uint>(x_1) * as_type<uint>(TILE_SIZE))), as_type<int>((as_type<uint>(y_1) * as_type<uint>(TILE_SIZE))));
       float2 floorCoord = (((2.0f * float2(tilePixel0Idx)) / float4((*(tint_symbol_3)).fullScreenSize).xy) - float2(1.0f));
-      float2 ceilCoord = (((2.0f * float2(as_type<int2>((as_type<uint2>(tilePixel0Idx) + as_type<uint2>(int2(16)))))) / float4((*(tint_symbol_3)).fullScreenSize).xy) - float2(1.0f));
+      float2 ceilCoord = (((2.0f * float2(as_type<int2>((as_type<uint2>(tilePixel0Idx) + as_type<uint2>(int2(TILE_SIZE)))))) / float4((*(tint_symbol_3)).fullScreenSize).xy) - float2(1.0f));
       float2 viewFloorCoord = float2((((-(viewNear) * floorCoord[0]) - (M[2][0] * viewNear)) / M[0][0]), (((-(viewNear) * floorCoord[1]) - (M[2][1] * viewNear)) / M[1][1]));
       float2 viewCeilCoord = float2((((-(viewNear) * ceilCoord[0]) - (M[2][0] * viewNear)) / M[0][0]), (((-(viewNear) * ceilCoord[1]) - (M[2][1] * viewNear)) / M[1][1]));
       frustumPlanes[0] = float4(1.0f, 0.0f, (-(viewFloorCoord[0]) / viewNear), 0.0f);
diff --git a/test/tint/bug/tint/1121.wgsl.expected.spvasm b/test/tint/bug/tint/1121.wgsl.expected.spvasm
index 97e8eb5..5dc7f31 100644
--- a/test/tint/bug/tint/1121.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1121.wgsl.expected.spvasm
@@ -175,7 +175,6 @@
         %207 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_v2float = OpTypePointer Function %v2float
         %211 = OpConstantNull %v2float
-        %214 = OpConstantComposite %v2int %int_16 %int_16
       %int_1 = OpConstant %int 1
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
 %_ptr_StorageBuffer_uint_0 = OpTypePointer StorageBuffer %uint
@@ -358,6 +357,7 @@
         %208 = OpFSub %v2float %206 %207
                OpStore %floorCoord %208
         %213 = OpLoad %v2int %tilePixel0Idx
+        %214 = OpCompositeConstruct %v2int %int_16 %int_16
         %215 = OpIAdd %v2int %213 %214
         %212 = OpConvertSToF %v2float %215
         %216 = OpVectorTimesScalar %v2float %212 %float_2
diff --git a/test/tint/bug/tint/764.wgsl.expected.glsl b/test/tint/bug/tint/764.wgsl.expected.glsl
index 347d829..02dcf2f 100644
--- a/test/tint/bug/tint/764.wgsl.expected.glsl
+++ b/test/tint/bug/tint/764.wgsl.expected.glsl
@@ -6,7 +6,7 @@
 }
 void f() {
   mat4 m = mat4(vec4(1.0f), vec4(1.0f), vec4(1.0f), vec4(1.0f));
-  vec4 v1 = vec4(1.0f);
-  float a = 1.0f;
+  vec4 v1 = m[0];
+  float a = v1[0];
 }
 
diff --git a/test/tint/bug/tint/764.wgsl.expected.hlsl b/test/tint/bug/tint/764.wgsl.expected.hlsl
index e4e19f7..b67a7dc 100644
--- a/test/tint/bug/tint/764.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/764.wgsl.expected.hlsl
@@ -5,6 +5,6 @@
 
 void f() {
   const float4x4 m = float4x4((1.0f).xxxx, (1.0f).xxxx, (1.0f).xxxx, (1.0f).xxxx);
-  const float4 v1 = (1.0f).xxxx;
-  const float a = 1.0f;
+  const float4 v1 = m[0];
+  const float a = v1[0];
 }
diff --git a/test/tint/bug/tint/764.wgsl.expected.msl b/test/tint/bug/tint/764.wgsl.expected.msl
index aa71892..4dae82f 100644
--- a/test/tint/bug/tint/764.wgsl.expected.msl
+++ b/test/tint/bug/tint/764.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 void f() {
   float4x4 const m = float4x4(float4(1.0f), float4(1.0f), float4(1.0f), float4(1.0f));
-  float4 const v1 = float4(1.0f);
-  float const a = 1.0f;
+  float4 const v1 = m[0];
+  float const a = v1[0];
 }
 
diff --git a/test/tint/bug/tint/764.wgsl.expected.spvasm b/test/tint/bug/tint/764.wgsl.expected.spvasm
index f5a8869..329c64e 100644
--- a/test/tint/bug/tint/764.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/764.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 13
+; Bound: 17
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -17,11 +17,15 @@
     %float_1 = OpConstant %float 1
          %11 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
          %12 = OpConstantComposite %mat4v4float %11 %11 %11 %11
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %void None %1
           %6 = OpLabel
+         %15 = OpCompositeExtract %v4float %12 0
+         %16 = OpCompositeExtract %float %15 0
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/827.wgsl b/test/tint/bug/tint/827.wgsl
index 761b3d8..1e1b4ad 100644
--- a/test/tint/bug/tint/827.wgsl
+++ b/test/tint/bug/tint/827.wgsl
@@ -2,7 +2,7 @@
     values : array<f32>,
 };
 
-let width : u32 = 128u;
+const width : u32 = 128u;
 
 @group(0) @binding(0) var tex : texture_depth_2d;
 @group(0) @binding(1) var<storage, read_write> result : Result;
diff --git a/test/tint/bug/tint/827.wgsl.expected.glsl b/test/tint/bug/tint/827.wgsl.expected.glsl
index 482c7d3..4098e55 100644
--- a/test/tint/bug/tint/827.wgsl.expected.glsl
+++ b/test/tint/bug/tint/827.wgsl.expected.glsl
@@ -1,12 +1,11 @@
 #version 310 es
 
-const uint width = 128u;
 layout(binding = 1, std430) buffer Result_1 {
   float values[];
 } result;
 uniform highp sampler2D tex_1;
 void tint_symbol(uvec3 GlobalInvocationId) {
-  result.values[((GlobalInvocationId.y * width) + GlobalInvocationId.x)] = texelFetch(tex_1, ivec2(int(GlobalInvocationId.x), int(GlobalInvocationId.y)), 0).x;
+  result.values[((GlobalInvocationId.y * 128u) + GlobalInvocationId.x)] = texelFetch(tex_1, ivec2(int(GlobalInvocationId.x), int(GlobalInvocationId.y)), 0).x;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/bug/tint/827.wgsl.expected.hlsl b/test/tint/bug/tint/827.wgsl.expected.hlsl
index bd8458c..f1c9fa5 100644
--- a/test/tint/bug/tint/827.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/827.wgsl.expected.hlsl
@@ -1,5 +1,3 @@
-static const uint width = 128u;
-
 Texture2D tex : register(t0, space0);
 RWByteAddressBuffer result : register(u1, space0);
 
@@ -8,7 +6,7 @@
 };
 
 void main_inner(uint3 GlobalInvocationId) {
-  result.Store((4u * ((GlobalInvocationId.y * width) + GlobalInvocationId.x)), asuint(tex.Load(int3(int(GlobalInvocationId.x), int(GlobalInvocationId.y), 0)).x));
+  result.Store((4u * ((GlobalInvocationId.y * 128u) + GlobalInvocationId.x)), asuint(tex.Load(int3(int(GlobalInvocationId.x), int(GlobalInvocationId.y), 0)).x));
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/bug/tint/827.wgsl.expected.msl b/test/tint/bug/tint/827.wgsl.expected.msl
index d915798..b230160 100644
--- a/test/tint/bug/tint/827.wgsl.expected.msl
+++ b/test/tint/bug/tint/827.wgsl.expected.msl
@@ -18,10 +18,8 @@
   /* 0x0000 */ tint_array<float, 1> values;
 };
 
-constant uint width = 128u;
-
 void tint_symbol_inner(uint3 GlobalInvocationId, device Result* const tint_symbol_1, depth2d<float, access::sample> tint_symbol_2) {
-  (*(tint_symbol_1)).values[((GlobalInvocationId[1] * width) + GlobalInvocationId[0])] = tint_symbol_2.read(uint2(int2(int(GlobalInvocationId[0]), int(GlobalInvocationId[1]))), 0);
+  (*(tint_symbol_1)).values[((GlobalInvocationId[1] * 128u) + GlobalInvocationId[0])] = tint_symbol_2.read(uint2(int2(int(GlobalInvocationId[0]), int(GlobalInvocationId[1]))), 0);
 }
 
 kernel void tint_symbol(device Result* tint_symbol_3 [[buffer(0)]], depth2d<float, access::sample> tint_symbol_4 [[texture(0)]], uint3 GlobalInvocationId [[thread_position_in_grid]]) {
diff --git a/test/tint/bug/tint/827.wgsl.expected.spvasm b/test/tint/bug/tint/827.wgsl.expected.spvasm
index 29e60f6..de11b1b 100644
--- a/test/tint/bug/tint/827.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/827.wgsl.expected.spvasm
@@ -8,7 +8,6 @@
                OpEntryPoint GLCompute %main "main" %GlobalInvocationId_1
                OpExecutionMode %main LocalSize 1 1 1
                OpName %GlobalInvocationId_1 "GlobalInvocationId_1"
-               OpName %width "width"
                OpName %tex "tex"
                OpName %Result "Result"
                OpMemberName %Result 0 "values"
@@ -28,33 +27,33 @@
      %v3uint = OpTypeVector %uint 3
 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
 %GlobalInvocationId_1 = OpVariable %_ptr_Input_v3uint Input
-      %width = OpConstant %uint 128
       %float = OpTypeFloat 32
-          %8 = OpTypeImage %float 2D 0 0 0 1 Unknown
-%_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8
-        %tex = OpVariable %_ptr_UniformConstant_8 UniformConstant
+          %7 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
+        %tex = OpVariable %_ptr_UniformConstant_7 UniformConstant
 %_runtimearr_float = OpTypeRuntimeArray %float
      %Result = OpTypeStruct %_runtimearr_float
 %_ptr_StorageBuffer_Result = OpTypePointer StorageBuffer %Result
      %result = OpVariable %_ptr_StorageBuffer_Result StorageBuffer
        %void = OpTypeVoid
-         %14 = OpTypeFunction %void %v3uint
+         %13 = OpTypeFunction %void %v3uint
      %uint_0 = OpConstant %uint 0
+   %uint_128 = OpConstant %uint 128
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
     %v4float = OpTypeVector %float 4
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
          %37 = OpConstantNull %int
          %38 = OpTypeFunction %void
- %main_inner = OpFunction %void None %14
+ %main_inner = OpFunction %void None %13
 %GlobalInvocationId = OpFunctionParameter %v3uint
-         %18 = OpLabel
-         %20 = OpCompositeExtract %uint %GlobalInvocationId 1
-         %21 = OpIMul %uint %20 %width
+         %17 = OpLabel
+         %19 = OpCompositeExtract %uint %GlobalInvocationId 1
+         %21 = OpIMul %uint %19 %uint_128
          %22 = OpCompositeExtract %uint %GlobalInvocationId 0
          %23 = OpIAdd %uint %21 %22
          %25 = OpAccessChain %_ptr_StorageBuffer_float %result %uint_0 %23
-         %29 = OpLoad %8 %tex
+         %29 = OpLoad %7 %tex
          %33 = OpCompositeExtract %uint %GlobalInvocationId 0
          %32 = OpBitcast %int %33
          %35 = OpCompositeExtract %uint %GlobalInvocationId 1
diff --git a/test/tint/bug/tint/827.wgsl.expected.wgsl b/test/tint/bug/tint/827.wgsl.expected.wgsl
index c54420e..e026916 100644
--- a/test/tint/bug/tint/827.wgsl.expected.wgsl
+++ b/test/tint/bug/tint/827.wgsl.expected.wgsl
@@ -2,7 +2,7 @@
   values : array<f32>,
 }
 
-let width : u32 = 128u;
+const width : u32 = 128u;
 
 @group(0) @binding(0) var tex : texture_depth_2d;
 
diff --git a/test/tint/bug/tint/914.wgsl b/test/tint/bug/tint/914.wgsl
index 9493b2b..6c0d6c3 100644
--- a/test/tint/bug/tint/914.wgsl
+++ b/test/tint/bug/tint/914.wgsl
@@ -38,11 +38,11 @@
     }
 }
 
-let RowPerThread : u32 = 4u;
-let ColPerThread : u32 = 4u;
-let TileAOuter : u32 = 64u;
-let TileBOuter : u32 = 64u;
-let TileInner : u32 = 64u;
+const RowPerThread : u32 = 4u;
+const ColPerThread : u32 = 4u;
+const TileAOuter : u32 = 64u;
+const TileBOuter : u32 = 64u;
+const TileInner : u32 = 64u;
 var<workgroup> mm_Asub : array<array<f32, 64>, 64>;
 var<workgroup> mm_Bsub : array<array<f32, 64>, 64>;
 @compute @workgroup_size(16, 16, 1)
diff --git a/test/tint/bug/tint/914.wgsl.expected.glsl b/test/tint/bug/tint/914.wgsl.expected.glsl
index 5ec38c1..a40e5ce 100644
--- a/test/tint/bug/tint/914.wgsl.expected.glsl
+++ b/test/tint/bug/tint/914.wgsl.expected.glsl
@@ -56,9 +56,6 @@
   }
 }
 
-const uint RowPerThread = 4u;
-const uint ColPerThread = 4u;
-const uint TileInner = 64u;
 shared float mm_Asub[64][64];
 shared float mm_Bsub[64][64];
 void tint_symbol(uvec3 local_id, uvec3 global_id, uint local_invocation_index) {
@@ -71,32 +68,32 @@
     }
   }
   barrier();
-  uint tileRow = (local_id.y * RowPerThread);
-  uint tileCol = (local_id.x * ColPerThread);
-  uint globalRow = (global_id.y * RowPerThread);
-  uint globalCol = (global_id.x * ColPerThread);
-  uint numTiles = (((uniforms.dimInner - 1u) / TileInner) + 1u);
+  uint tileRow = (local_id.y * 4u);
+  uint tileCol = (local_id.x * 4u);
+  uint globalRow = (global_id.y * 4u);
+  uint globalCol = (global_id.x * 4u);
+  uint numTiles = (((uniforms.dimInner - 1u) / 64u) + 1u);
   float acc[16] = float[16](0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
   float ACached = 0.0f;
   float BCached[4] = float[4](0.0f, 0.0f, 0.0f, 0.0f);
   {
-    for(uint index = 0u; (index < (RowPerThread * ColPerThread)); index = (index + 1u)) {
+    for(uint index = 0u; (index < (4u * 4u)); index = (index + 1u)) {
       acc[index] = 0.0f;
     }
   }
-  uint ColPerThreadA = (TileInner / 16u);
+  uint ColPerThreadA = (64u / 16u);
   uint tileColA = (local_id.x * ColPerThreadA);
-  uint RowPerThreadB = (TileInner / 16u);
+  uint RowPerThreadB = (64u / 16u);
   uint tileRowB = (local_id.y * RowPerThreadB);
   {
     for(uint t = 0u; (t < numTiles); t = (t + 1u)) {
       {
-        for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+        for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
           {
             for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
               uint inputRow = (tileRow + innerRow);
               uint inputCol = (tileColA + innerCol);
-              float tint_symbol_1 = mm_readA((globalRow + innerRow), ((t * TileInner) + inputCol));
+              float tint_symbol_1 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
               mm_Asub[inputRow][inputCol] = tint_symbol_1;
             }
           }
@@ -105,10 +102,10 @@
       {
         for(uint innerRow = 0u; (innerRow < RowPerThreadB); innerRow = (innerRow + 1u)) {
           {
-            for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
+            for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
               uint inputRow = (tileRowB + innerRow);
               uint inputCol = (tileCol + innerCol);
-              float tint_symbol_2 = mm_readB(((t * TileInner) + inputRow), (globalCol + innerCol));
+              float tint_symbol_2 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
               mm_Bsub[innerCol][inputCol] = tint_symbol_2;
             }
           }
@@ -116,18 +113,18 @@
       }
       barrier();
       {
-        for(uint k = 0u; (k < TileInner); k = (k + 1u)) {
+        for(uint k = 0u; (k < 64u); k = (k + 1u)) {
           {
-            for(uint inner = 0u; (inner < ColPerThread); inner = (inner + 1u)) {
+            for(uint inner = 0u; (inner < 4u); inner = (inner + 1u)) {
               BCached[inner] = mm_Bsub[k][(tileCol + inner)];
             }
           }
           {
-            for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+            for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
               ACached = mm_Asub[(tileRow + innerRow)][k];
               {
-                for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
-                  uint index = ((innerRow * ColPerThread) + innerCol);
+                for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
+                  uint index = ((innerRow * 4u) + innerCol);
                   acc[index] = (acc[index] + (ACached * BCached[innerCol]));
                 }
               }
@@ -139,10 +136,10 @@
     }
   }
   {
-    for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+    for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
       {
-        for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
-          uint index = ((innerRow * ColPerThread) + innerCol);
+        for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
+          uint index = ((innerRow * 4u) + innerCol);
           mm_write((globalRow + innerRow), (globalCol + innerCol), acc[index]);
         }
       }
diff --git a/test/tint/bug/tint/914.wgsl.expected.hlsl b/test/tint/bug/tint/914.wgsl.expected.hlsl
index 5dbfaa1..a9ca8f8 100644
--- a/test/tint/bug/tint/914.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/914.wgsl.expected.hlsl
@@ -40,12 +40,6 @@
   }
 }
 
-static const uint RowPerThread = 4u;
-static const uint ColPerThread = 4u;
-static const uint TileAOuter = 64u;
-static const uint TileBOuter = 64u;
-static const uint TileInner = 64u;
-
 groupshared float mm_Asub[64][64];
 groupshared float mm_Bsub[64][64];
 
@@ -65,32 +59,32 @@
     }
   }
   GroupMemoryBarrierWithGroupSync();
-  const uint tileRow = (local_id.y * RowPerThread);
-  const uint tileCol = (local_id.x * ColPerThread);
-  const uint globalRow = (global_id.y * RowPerThread);
-  const uint globalCol = (global_id.x * ColPerThread);
-  const uint numTiles = (((uniforms[0].y - 1u) / TileInner) + 1u);
+  const uint tileRow = (local_id.y * 4u);
+  const uint tileCol = (local_id.x * 4u);
+  const uint globalRow = (global_id.y * 4u);
+  const uint globalCol = (global_id.x * 4u);
+  const uint numTiles = (((uniforms[0].y - 1u) / 64u) + 1u);
   float acc[16] = (float[16])0;
   float ACached = 0.0f;
   float BCached[4] = (float[4])0;
   {
-    [loop] for(uint index = 0u; (index < (RowPerThread * ColPerThread)); index = (index + 1u)) {
+    [loop] for(uint index = 0u; (index < (4u * 4u)); index = (index + 1u)) {
       acc[index] = 0.0f;
     }
   }
-  const uint ColPerThreadA = (TileInner / 16u);
+  const uint ColPerThreadA = (64u / 16u);
   const uint tileColA = (local_id.x * ColPerThreadA);
-  const uint RowPerThreadB = (TileInner / 16u);
+  const uint RowPerThreadB = (64u / 16u);
   const uint tileRowB = (local_id.y * RowPerThreadB);
   {
     [loop] for(uint t = 0u; (t < numTiles); t = (t + 1u)) {
       {
-        [loop] for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+        [loop] for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
           {
             [loop] for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
               const uint inputRow = (tileRow + innerRow);
               const uint inputCol = (tileColA + innerCol);
-              const float tint_symbol_2 = mm_readA((globalRow + innerRow), ((t * TileInner) + inputCol));
+              const float tint_symbol_2 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
               mm_Asub[inputRow][inputCol] = tint_symbol_2;
             }
           }
@@ -99,10 +93,10 @@
       {
         [loop] for(uint innerRow = 0u; (innerRow < RowPerThreadB); innerRow = (innerRow + 1u)) {
           {
-            [loop] for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
+            [loop] for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
               const uint inputRow = (tileRowB + innerRow);
               const uint inputCol = (tileCol + innerCol);
-              const float tint_symbol_3 = mm_readB(((t * TileInner) + inputRow), (globalCol + innerCol));
+              const float tint_symbol_3 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
               mm_Bsub[innerCol][inputCol] = tint_symbol_3;
             }
           }
@@ -110,18 +104,18 @@
       }
       GroupMemoryBarrierWithGroupSync();
       {
-        [loop] for(uint k = 0u; (k < TileInner); k = (k + 1u)) {
+        [loop] for(uint k = 0u; (k < 64u); k = (k + 1u)) {
           {
-            [loop] for(uint inner = 0u; (inner < ColPerThread); inner = (inner + 1u)) {
+            [loop] for(uint inner = 0u; (inner < 4u); inner = (inner + 1u)) {
               BCached[inner] = mm_Bsub[k][(tileCol + inner)];
             }
           }
           {
-            [loop] for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+            [loop] for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
               ACached = mm_Asub[(tileRow + innerRow)][k];
               {
-                [loop] for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
-                  const uint index = ((innerRow * ColPerThread) + innerCol);
+                [loop] for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
+                  const uint index = ((innerRow * 4u) + innerCol);
                   acc[index] = (acc[index] + (ACached * BCached[innerCol]));
                 }
               }
@@ -133,10 +127,10 @@
     }
   }
   {
-    [loop] for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+    [loop] for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
       {
-        [loop] for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
-          const uint index = ((innerRow * ColPerThread) + innerCol);
+        [loop] for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
+          const uint index = ((innerRow * 4u) + innerCol);
           mm_write((globalRow + innerRow), (globalCol + innerCol), acc[index]);
         }
       }
diff --git a/test/tint/bug/tint/914.wgsl.expected.msl b/test/tint/bug/tint/914.wgsl.expected.msl
index 94c3891..d70dc36 100644
--- a/test/tint/bug/tint/914.wgsl.expected.msl
+++ b/test/tint/bug/tint/914.wgsl.expected.msl
@@ -47,16 +47,6 @@
   }
 }
 
-constant uint RowPerThread = 4u;
-
-constant uint ColPerThread = 4u;
-
-constant uint TileAOuter = 64u;
-
-constant uint TileBOuter = 64u;
-
-constant uint TileInner = 64u;
-
 void tint_symbol_inner(uint3 local_id, uint3 global_id, uint local_invocation_index, threadgroup tint_array<tint_array<float, 64>, 64>* const tint_symbol_9, threadgroup tint_array<tint_array<float, 64>, 64>* const tint_symbol_10, const constant Uniforms* const tint_symbol_11, const device Matrix* const tint_symbol_12, const device Matrix* const tint_symbol_13, device Matrix* const tint_symbol_14) {
   for(uint idx = local_invocation_index; (idx < 4096u); idx = (idx + 256u)) {
     uint const i = (idx / 64u);
@@ -65,56 +55,56 @@
     (*(tint_symbol_10))[i][i_1] = 0.0f;
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  uint const tileRow = (local_id[1] * RowPerThread);
-  uint const tileCol = (local_id[0] * ColPerThread);
-  uint const globalRow = (global_id[1] * RowPerThread);
-  uint const globalCol = (global_id[0] * ColPerThread);
-  uint const numTiles = ((((*(tint_symbol_11)).dimInner - 1u) / TileInner) + 1u);
+  uint const tileRow = (local_id[1] * 4u);
+  uint const tileCol = (local_id[0] * 4u);
+  uint const globalRow = (global_id[1] * 4u);
+  uint const globalCol = (global_id[0] * 4u);
+  uint const numTiles = ((((*(tint_symbol_11)).dimInner - 1u) / 64u) + 1u);
   tint_array<float, 16> acc = {};
   float ACached = 0.0f;
   tint_array<float, 4> BCached = {};
-  for(uint index = 0u; (index < (RowPerThread * ColPerThread)); index = (index + 1u)) {
+  for(uint index = 0u; (index < (4u * 4u)); index = (index + 1u)) {
     acc[index] = 0.0f;
   }
-  uint const ColPerThreadA = (TileInner / 16u);
+  uint const ColPerThreadA = (64u / 16u);
   uint const tileColA = (local_id[0] * ColPerThreadA);
-  uint const RowPerThreadB = (TileInner / 16u);
+  uint const RowPerThreadB = (64u / 16u);
   uint const tileRowB = (local_id[1] * RowPerThreadB);
   for(uint t = 0u; (t < numTiles); t = (t + 1u)) {
-    for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+    for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
       for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
         uint const inputRow = (tileRow + innerRow);
         uint const inputCol = (tileColA + innerCol);
-        float const tint_symbol_1 = mm_readA((globalRow + innerRow), ((t * TileInner) + inputCol), tint_symbol_11, tint_symbol_12);
+        float const tint_symbol_1 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol), tint_symbol_11, tint_symbol_12);
         (*(tint_symbol_9))[inputRow][inputCol] = tint_symbol_1;
       }
     }
     for(uint innerRow = 0u; (innerRow < RowPerThreadB); innerRow = (innerRow + 1u)) {
-      for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
+      for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
         uint const inputRow = (tileRowB + innerRow);
         uint const inputCol = (tileCol + innerCol);
-        float const tint_symbol_2 = mm_readB(((t * TileInner) + inputRow), (globalCol + innerCol), tint_symbol_11, tint_symbol_13);
+        float const tint_symbol_2 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol), tint_symbol_11, tint_symbol_13);
         (*(tint_symbol_10))[innerCol][inputCol] = tint_symbol_2;
       }
     }
     threadgroup_barrier(mem_flags::mem_threadgroup);
-    for(uint k = 0u; (k < TileInner); k = (k + 1u)) {
-      for(uint inner = 0u; (inner < ColPerThread); inner = (inner + 1u)) {
+    for(uint k = 0u; (k < 64u); k = (k + 1u)) {
+      for(uint inner = 0u; (inner < 4u); inner = (inner + 1u)) {
         BCached[inner] = (*(tint_symbol_10))[k][(tileCol + inner)];
       }
-      for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
+      for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
         ACached = (*(tint_symbol_9))[(tileRow + innerRow)][k];
-        for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
-          uint const index = ((innerRow * ColPerThread) + innerCol);
+        for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
+          uint const index = ((innerRow * 4u) + innerCol);
           acc[index] = (acc[index] + (ACached * BCached[innerCol]));
         }
       }
     }
     threadgroup_barrier(mem_flags::mem_threadgroup);
   }
-  for(uint innerRow = 0u; (innerRow < RowPerThread); innerRow = (innerRow + 1u)) {
-    for(uint innerCol = 0u; (innerCol < ColPerThread); innerCol = (innerCol + 1u)) {
-      uint const index = ((innerRow * ColPerThread) + innerCol);
+  for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
+    for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
+      uint const index = ((innerRow * 4u) + innerCol);
       mm_write((globalRow + innerRow), (globalCol + innerCol), acc[index], tint_symbol_11, tint_symbol_14);
     }
   }
diff --git a/test/tint/bug/tint/914.wgsl.expected.spvasm b/test/tint/bug/tint/914.wgsl.expected.spvasm
index 460cc21..8647c10 100644
--- a/test/tint/bug/tint/914.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/914.wgsl.expected.spvasm
@@ -20,11 +20,6 @@
                OpMemberName %Uniforms 1 "dimInner"
                OpMemberName %Uniforms 2 "dimBOuter"
                OpName %uniforms "uniforms"
-               OpName %RowPerThread "RowPerThread"
-               OpName %RowPerThread "ColPerThread"
-               OpName %TileAOuter "TileAOuter"
-               OpName %TileAOuter "TileBOuter"
-               OpName %TileAOuter "TileInner"
                OpName %mm_Asub "mm_Asub"
                OpName %mm_Bsub "mm_Bsub"
                OpName %mm_readA "mm_readA"
@@ -80,10 +75,10 @@
                OpDecorate %uniforms NonWritable
                OpDecorate %uniforms DescriptorSet 0
                OpDecorate %uniforms Binding 3
-               OpDecorate %_arr_float_TileAOuter ArrayStride 4
-               OpDecorate %_arr__arr_float_TileAOuter_TileAOuter ArrayStride 256
+               OpDecorate %_arr_float_uint_64 ArrayStride 4
+               OpDecorate %_arr__arr_float_uint_64_uint_64 ArrayStride 256
                OpDecorate %_arr_float_uint_16 ArrayStride 4
-               OpDecorate %_arr_float_RowPerThread ArrayStride 4
+               OpDecorate %_arr_float_uint_4 ArrayStride 4
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
@@ -101,199 +96,199 @@
    %Uniforms = OpTypeStruct %uint %uint %uint
 %_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms
    %uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform
-%RowPerThread = OpConstant %uint 4
- %TileAOuter = OpConstant %uint 64
-%_arr_float_TileAOuter = OpTypeArray %float %TileAOuter
-%_arr__arr_float_TileAOuter_TileAOuter = OpTypeArray %_arr_float_TileAOuter %TileAOuter
-%_ptr_Workgroup__arr__arr_float_TileAOuter_TileAOuter = OpTypePointer Workgroup %_arr__arr_float_TileAOuter_TileAOuter
-    %mm_Asub = OpVariable %_ptr_Workgroup__arr__arr_float_TileAOuter_TileAOuter Workgroup
-    %mm_Bsub = OpVariable %_ptr_Workgroup__arr__arr_float_TileAOuter_TileAOuter Workgroup
-         %25 = OpTypeFunction %float %uint %uint
+    %uint_64 = OpConstant %uint 64
+%_arr_float_uint_64 = OpTypeArray %float %uint_64
+%_arr__arr_float_uint_64_uint_64 = OpTypeArray %_arr_float_uint_64 %uint_64
+%_ptr_Workgroup__arr__arr_float_uint_64_uint_64 = OpTypePointer Workgroup %_arr__arr_float_uint_64_uint_64
+    %mm_Asub = OpVariable %_ptr_Workgroup__arr__arr_float_uint_64_uint_64 Workgroup
+    %mm_Bsub = OpVariable %_ptr_Workgroup__arr__arr_float_uint_64_uint_64 Workgroup
+         %24 = OpTypeFunction %float %uint %uint
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
        %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
-         %52 = OpConstantNull %float
+         %51 = OpConstantNull %float
      %uint_2 = OpConstant %uint 2
        %void = OpTypeVoid
-         %75 = OpTypeFunction %void %uint %uint %float
-         %98 = OpTypeFunction %void %v3uint %v3uint %uint
+         %74 = OpTypeFunction %void %uint %uint %float
+         %97 = OpTypeFunction %void %v3uint %v3uint %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-        %106 = OpConstantNull %uint
+        %105 = OpConstantNull %uint
   %uint_4096 = OpConstant %uint 4096
 %_ptr_Workgroup_float = OpTypePointer Workgroup %float
    %uint_256 = OpConstant %uint 256
    %uint_264 = OpConstant %uint 264
+     %uint_4 = OpConstant %uint 4
     %uint_16 = OpConstant %uint 16
 %_arr_float_uint_16 = OpTypeArray %float %uint_16
 %_ptr_Function__arr_float_uint_16 = OpTypePointer Function %_arr_float_uint_16
         %146 = OpConstantNull %_arr_float_uint_16
 %_ptr_Function_float = OpTypePointer Function %float
-%_arr_float_RowPerThread = OpTypeArray %float %RowPerThread
-%_ptr_Function__arr_float_RowPerThread = OpTypePointer Function %_arr_float_RowPerThread
-        %152 = OpConstantNull %_arr_float_RowPerThread
+%_arr_float_uint_4 = OpTypeArray %float %uint_4
+%_ptr_Function__arr_float_uint_4 = OpTypePointer Function %_arr_float_uint_4
+        %152 = OpConstantNull %_arr_float_uint_4
         %367 = OpTypeFunction %void
-   %mm_readA = OpFunction %float None %25
+   %mm_readA = OpFunction %float None %24
         %row = OpFunctionParameter %uint
         %col = OpFunctionParameter %uint
-         %29 = OpLabel
-         %32 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0
-         %33 = OpLoad %uint %32
-         %34 = OpULessThan %bool %row %33
-               OpSelectionMerge %36 None
-               OpBranchConditional %34 %37 %36
-         %37 = OpLabel
-         %39 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
-         %40 = OpLoad %uint %39
-         %41 = OpULessThan %bool %col %40
-               OpBranch %36
+         %28 = OpLabel
+         %31 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0
+         %32 = OpLoad %uint %31
+         %33 = OpULessThan %bool %row %32
+               OpSelectionMerge %35 None
+               OpBranchConditional %33 %36 %35
          %36 = OpLabel
-         %42 = OpPhi %bool %34 %29 %41 %37
-               OpSelectionMerge %43 None
-               OpBranchConditional %42 %44 %43
-         %44 = OpLabel
-         %45 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
-         %46 = OpLoad %uint %45
-         %47 = OpIMul %uint %row %46
-         %48 = OpIAdd %uint %47 %col
-         %50 = OpAccessChain %_ptr_StorageBuffer_float %firstMatrix %uint_0 %48
-         %51 = OpLoad %float %50
-               OpReturnValue %51
+         %38 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
+         %39 = OpLoad %uint %38
+         %40 = OpULessThan %bool %col %39
+               OpBranch %35
+         %35 = OpLabel
+         %41 = OpPhi %bool %33 %28 %40 %36
+               OpSelectionMerge %42 None
+               OpBranchConditional %41 %43 %42
          %43 = OpLabel
-               OpReturnValue %52
+         %44 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
+         %45 = OpLoad %uint %44
+         %46 = OpIMul %uint %row %45
+         %47 = OpIAdd %uint %46 %col
+         %49 = OpAccessChain %_ptr_StorageBuffer_float %firstMatrix %uint_0 %47
+         %50 = OpLoad %float %49
+               OpReturnValue %50
+         %42 = OpLabel
+               OpReturnValue %51
                OpFunctionEnd
-   %mm_readB = OpFunction %float None %25
+   %mm_readB = OpFunction %float None %24
       %row_0 = OpFunctionParameter %uint
       %col_0 = OpFunctionParameter %uint
-         %56 = OpLabel
-         %57 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
-         %58 = OpLoad %uint %57
-         %59 = OpULessThan %bool %row_0 %58
-               OpSelectionMerge %60 None
-               OpBranchConditional %59 %61 %60
-         %61 = OpLabel
-         %63 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
-         %64 = OpLoad %uint %63
-         %65 = OpULessThan %bool %col_0 %64
-               OpBranch %60
+         %55 = OpLabel
+         %56 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
+         %57 = OpLoad %uint %56
+         %58 = OpULessThan %bool %row_0 %57
+               OpSelectionMerge %59 None
+               OpBranchConditional %58 %60 %59
          %60 = OpLabel
-         %66 = OpPhi %bool %59 %56 %65 %61
-               OpSelectionMerge %67 None
-               OpBranchConditional %66 %68 %67
-         %68 = OpLabel
-         %69 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
-         %70 = OpLoad %uint %69
-         %71 = OpIMul %uint %row_0 %70
-         %72 = OpIAdd %uint %71 %col_0
-         %73 = OpAccessChain %_ptr_StorageBuffer_float %secondMatrix %uint_0 %72
-         %74 = OpLoad %float %73
-               OpReturnValue %74
+         %62 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
+         %63 = OpLoad %uint %62
+         %64 = OpULessThan %bool %col_0 %63
+               OpBranch %59
+         %59 = OpLabel
+         %65 = OpPhi %bool %58 %55 %64 %60
+               OpSelectionMerge %66 None
+               OpBranchConditional %65 %67 %66
          %67 = OpLabel
-               OpReturnValue %52
+         %68 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
+         %69 = OpLoad %uint %68
+         %70 = OpIMul %uint %row_0 %69
+         %71 = OpIAdd %uint %70 %col_0
+         %72 = OpAccessChain %_ptr_StorageBuffer_float %secondMatrix %uint_0 %71
+         %73 = OpLoad %float %72
+               OpReturnValue %73
+         %66 = OpLabel
+               OpReturnValue %51
                OpFunctionEnd
-   %mm_write = OpFunction %void None %75
+   %mm_write = OpFunction %void None %74
       %row_1 = OpFunctionParameter %uint
       %col_1 = OpFunctionParameter %uint
       %value = OpFunctionParameter %float
-         %81 = OpLabel
-         %82 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0
-         %83 = OpLoad %uint %82
-         %84 = OpULessThan %bool %row_1 %83
-               OpSelectionMerge %85 None
-               OpBranchConditional %84 %86 %85
-         %86 = OpLabel
-         %87 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
-         %88 = OpLoad %uint %87
-         %89 = OpULessThan %bool %col_1 %88
-               OpBranch %85
+         %80 = OpLabel
+         %81 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0
+         %82 = OpLoad %uint %81
+         %83 = OpULessThan %bool %row_1 %82
+               OpSelectionMerge %84 None
+               OpBranchConditional %83 %85 %84
          %85 = OpLabel
-         %90 = OpPhi %bool %84 %81 %89 %86
-               OpSelectionMerge %91 None
-               OpBranchConditional %90 %92 %91
-         %92 = OpLabel
-         %93 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
-         %94 = OpLoad %uint %93
-         %95 = OpIMul %uint %row_1 %94
-         %96 = OpIAdd %uint %col_1 %95
-         %97 = OpAccessChain %_ptr_StorageBuffer_float %resultMatrix %uint_0 %96
-               OpStore %97 %value
-               OpBranch %91
+         %86 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
+         %87 = OpLoad %uint %86
+         %88 = OpULessThan %bool %col_1 %87
+               OpBranch %84
+         %84 = OpLabel
+         %89 = OpPhi %bool %83 %80 %88 %85
+               OpSelectionMerge %90 None
+               OpBranchConditional %89 %91 %90
          %91 = OpLabel
+         %92 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_2
+         %93 = OpLoad %uint %92
+         %94 = OpIMul %uint %row_1 %93
+         %95 = OpIAdd %uint %col_1 %94
+         %96 = OpAccessChain %_ptr_StorageBuffer_float %resultMatrix %uint_0 %95
+               OpStore %96 %value
+               OpBranch %90
+         %90 = OpLabel
                OpReturn
                OpFunctionEnd
- %main_inner = OpFunction %void None %98
+ %main_inner = OpFunction %void None %97
    %local_id = OpFunctionParameter %v3uint
   %global_id = OpFunctionParameter %v3uint
 %local_invocation_index = OpFunctionParameter %uint
-        %103 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %106
+        %102 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %105
         %acc = OpVariable %_ptr_Function__arr_float_uint_16 Function %146
-    %ACached = OpVariable %_ptr_Function_float Function %52
-    %BCached = OpVariable %_ptr_Function__arr_float_RowPerThread Function %152
-      %index = OpVariable %_ptr_Function_uint Function %106
-          %t = OpVariable %_ptr_Function_uint Function %106
-   %innerRow = OpVariable %_ptr_Function_uint Function %106
-   %innerCol = OpVariable %_ptr_Function_uint Function %106
- %innerRow_0 = OpVariable %_ptr_Function_uint Function %106
- %innerCol_0 = OpVariable %_ptr_Function_uint Function %106
-          %k = OpVariable %_ptr_Function_uint Function %106
-      %inner = OpVariable %_ptr_Function_uint Function %106
- %innerRow_1 = OpVariable %_ptr_Function_uint Function %106
- %innerCol_1 = OpVariable %_ptr_Function_uint Function %106
- %innerRow_2 = OpVariable %_ptr_Function_uint Function %106
- %innerCol_2 = OpVariable %_ptr_Function_uint Function %106
+    %ACached = OpVariable %_ptr_Function_float Function %51
+    %BCached = OpVariable %_ptr_Function__arr_float_uint_4 Function %152
+      %index = OpVariable %_ptr_Function_uint Function %105
+          %t = OpVariable %_ptr_Function_uint Function %105
+   %innerRow = OpVariable %_ptr_Function_uint Function %105
+   %innerCol = OpVariable %_ptr_Function_uint Function %105
+ %innerRow_0 = OpVariable %_ptr_Function_uint Function %105
+ %innerCol_0 = OpVariable %_ptr_Function_uint Function %105
+          %k = OpVariable %_ptr_Function_uint Function %105
+      %inner = OpVariable %_ptr_Function_uint Function %105
+ %innerRow_1 = OpVariable %_ptr_Function_uint Function %105
+ %innerCol_1 = OpVariable %_ptr_Function_uint Function %105
+ %innerRow_2 = OpVariable %_ptr_Function_uint Function %105
+ %innerCol_2 = OpVariable %_ptr_Function_uint Function %105
                OpStore %idx %local_invocation_index
-               OpBranch %107
-        %107 = OpLabel
-               OpLoopMerge %108 %109 None
-               OpBranch %110
-        %110 = OpLabel
-        %112 = OpLoad %uint %idx
-        %114 = OpULessThan %bool %112 %uint_4096
-        %111 = OpLogicalNot %bool %114
-               OpSelectionMerge %115 None
-               OpBranchConditional %111 %116 %115
-        %116 = OpLabel
-               OpBranch %108
-        %115 = OpLabel
-        %117 = OpLoad %uint %idx
-        %118 = OpUDiv %uint %117 %TileAOuter
-        %119 = OpLoad %uint %idx
-        %120 = OpUMod %uint %119 %TileAOuter
-        %122 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %118 %120
-               OpStore %122 %52
-        %123 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %118 %120
-               OpStore %123 %52
+               OpBranch %106
+        %106 = OpLabel
+               OpLoopMerge %107 %108 None
                OpBranch %109
         %109 = OpLabel
-        %124 = OpLoad %uint %idx
-        %126 = OpIAdd %uint %124 %uint_256
-               OpStore %idx %126
+        %111 = OpLoad %uint %idx
+        %113 = OpULessThan %bool %111 %uint_4096
+        %110 = OpLogicalNot %bool %113
+               OpSelectionMerge %114 None
+               OpBranchConditional %110 %115 %114
+        %115 = OpLabel
                OpBranch %107
+        %114 = OpLabel
+        %116 = OpLoad %uint %idx
+        %117 = OpUDiv %uint %116 %uint_64
+        %118 = OpLoad %uint %idx
+        %119 = OpUMod %uint %118 %uint_64
+        %121 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %117 %119
+               OpStore %121 %51
+        %122 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %117 %119
+               OpStore %122 %51
+               OpBranch %108
         %108 = OpLabel
+        %123 = OpLoad %uint %idx
+        %125 = OpIAdd %uint %123 %uint_256
+               OpStore %idx %125
+               OpBranch %106
+        %107 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-        %129 = OpCompositeExtract %uint %local_id 1
-        %130 = OpIMul %uint %129 %RowPerThread
+        %128 = OpCompositeExtract %uint %local_id 1
+        %130 = OpIMul %uint %128 %uint_4
         %131 = OpCompositeExtract %uint %local_id 0
-        %132 = OpIMul %uint %131 %RowPerThread
+        %132 = OpIMul %uint %131 %uint_4
         %133 = OpCompositeExtract %uint %global_id 1
-        %134 = OpIMul %uint %133 %RowPerThread
+        %134 = OpIMul %uint %133 %uint_4
         %135 = OpCompositeExtract %uint %global_id 0
-        %136 = OpIMul %uint %135 %RowPerThread
+        %136 = OpIMul %uint %135 %uint_4
         %137 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_1
         %138 = OpLoad %uint %137
         %139 = OpISub %uint %138 %uint_1
-        %140 = OpUDiv %uint %139 %TileAOuter
+        %140 = OpUDiv %uint %139 %uint_64
         %141 = OpIAdd %uint %140 %uint_1
-               OpStore %index %106
+               OpStore %index %105
                OpBranch %154
         %154 = OpLabel
                OpLoopMerge %155 %156 None
                OpBranch %157
         %157 = OpLabel
         %159 = OpLoad %uint %index
-        %160 = OpIMul %uint %RowPerThread %RowPerThread
+        %160 = OpIMul %uint %uint_4 %uint_4
         %161 = OpULessThan %bool %159 %160
         %158 = OpLogicalNot %bool %161
                OpSelectionMerge %162 None
@@ -303,7 +298,7 @@
         %162 = OpLabel
         %164 = OpLoad %uint %index
         %165 = OpAccessChain %_ptr_Function_float %acc %164
-               OpStore %165 %52
+               OpStore %165 %51
                OpBranch %156
         %156 = OpLabel
         %166 = OpLoad %uint %index
@@ -311,13 +306,13 @@
                OpStore %index %167
                OpBranch %154
         %155 = OpLabel
-        %168 = OpUDiv %uint %TileAOuter %uint_16
+        %168 = OpUDiv %uint %uint_64 %uint_16
         %169 = OpCompositeExtract %uint %local_id 0
         %170 = OpIMul %uint %169 %168
-        %171 = OpUDiv %uint %TileAOuter %uint_16
+        %171 = OpUDiv %uint %uint_64 %uint_16
         %172 = OpCompositeExtract %uint %local_id 1
         %173 = OpIMul %uint %172 %171
-               OpStore %t %106
+               OpStore %t %105
                OpBranch %175
         %175 = OpLabel
                OpLoopMerge %176 %177 None
@@ -331,21 +326,21 @@
         %183 = OpLabel
                OpBranch %176
         %182 = OpLabel
-               OpStore %innerRow %106
+               OpStore %innerRow %105
                OpBranch %185
         %185 = OpLabel
                OpLoopMerge %186 %187 None
                OpBranch %188
         %188 = OpLabel
         %190 = OpLoad %uint %innerRow
-        %191 = OpULessThan %bool %190 %RowPerThread
+        %191 = OpULessThan %bool %190 %uint_4
         %189 = OpLogicalNot %bool %191
                OpSelectionMerge %192 None
                OpBranchConditional %189 %193 %192
         %193 = OpLabel
                OpBranch %186
         %192 = OpLabel
-               OpStore %innerCol %106
+               OpStore %innerCol %105
                OpBranch %195
         %195 = OpLabel
                OpLoopMerge %196 %197 None
@@ -366,7 +361,7 @@
         %209 = OpLoad %uint %innerRow
         %210 = OpIAdd %uint %134 %209
         %211 = OpLoad %uint %t
-        %212 = OpIMul %uint %211 %TileAOuter
+        %212 = OpIMul %uint %211 %uint_64
         %213 = OpIAdd %uint %212 %207
         %208 = OpFunctionCall %float %mm_readA %210 %213
         %214 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %205 %207
@@ -385,7 +380,7 @@
                OpStore %innerRow %218
                OpBranch %185
         %186 = OpLabel
-               OpStore %innerRow_0 %106
+               OpStore %innerRow_0 %105
                OpBranch %220
         %220 = OpLabel
                OpLoopMerge %221 %222 None
@@ -399,14 +394,14 @@
         %228 = OpLabel
                OpBranch %221
         %227 = OpLabel
-               OpStore %innerCol_0 %106
+               OpStore %innerCol_0 %105
                OpBranch %230
         %230 = OpLabel
                OpLoopMerge %231 %232 None
                OpBranch %233
         %233 = OpLabel
         %235 = OpLoad %uint %innerCol_0
-        %236 = OpULessThan %bool %235 %RowPerThread
+        %236 = OpULessThan %bool %235 %uint_4
         %234 = OpLogicalNot %bool %236
                OpSelectionMerge %237 None
                OpBranchConditional %234 %238 %237
@@ -418,7 +413,7 @@
         %241 = OpLoad %uint %innerCol_0
         %242 = OpIAdd %uint %132 %241
         %244 = OpLoad %uint %t
-        %245 = OpIMul %uint %244 %TileAOuter
+        %245 = OpIMul %uint %244 %uint_64
         %246 = OpIAdd %uint %245 %240
         %247 = OpLoad %uint %innerCol_0
         %248 = OpIAdd %uint %136 %247
@@ -441,28 +436,28 @@
                OpBranch %220
         %221 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-               OpStore %k %106
+               OpStore %k %105
                OpBranch %257
         %257 = OpLabel
                OpLoopMerge %258 %259 None
                OpBranch %260
         %260 = OpLabel
         %262 = OpLoad %uint %k
-        %263 = OpULessThan %bool %262 %TileAOuter
+        %263 = OpULessThan %bool %262 %uint_64
         %261 = OpLogicalNot %bool %263
                OpSelectionMerge %264 None
                OpBranchConditional %261 %265 %264
         %265 = OpLabel
                OpBranch %258
         %264 = OpLabel
-               OpStore %inner %106
+               OpStore %inner %105
                OpBranch %267
         %267 = OpLabel
                OpLoopMerge %268 %269 None
                OpBranch %270
         %270 = OpLabel
         %272 = OpLoad %uint %inner
-        %273 = OpULessThan %bool %272 %RowPerThread
+        %273 = OpULessThan %bool %272 %uint_4
         %271 = OpLogicalNot %bool %273
                OpSelectionMerge %274 None
                OpBranchConditional %271 %275 %274
@@ -484,14 +479,14 @@
                OpStore %inner %284
                OpBranch %267
         %268 = OpLabel
-               OpStore %innerRow_1 %106
+               OpStore %innerRow_1 %105
                OpBranch %286
         %286 = OpLabel
                OpLoopMerge %287 %288 None
                OpBranch %289
         %289 = OpLabel
         %291 = OpLoad %uint %innerRow_1
-        %292 = OpULessThan %bool %291 %RowPerThread
+        %292 = OpULessThan %bool %291 %uint_4
         %290 = OpLogicalNot %bool %292
                OpSelectionMerge %293 None
                OpBranchConditional %290 %294 %293
@@ -504,14 +499,14 @@
         %298 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %296 %297
         %299 = OpLoad %float %298
                OpStore %ACached %299
-               OpStore %innerCol_1 %106
+               OpStore %innerCol_1 %105
                OpBranch %301
         %301 = OpLabel
                OpLoopMerge %302 %303 None
                OpBranch %304
         %304 = OpLabel
         %306 = OpLoad %uint %innerCol_1
-        %307 = OpULessThan %bool %306 %RowPerThread
+        %307 = OpULessThan %bool %306 %uint_4
         %305 = OpLogicalNot %bool %307
                OpSelectionMerge %308 None
                OpBranchConditional %305 %309 %308
@@ -519,7 +514,7 @@
                OpBranch %302
         %308 = OpLabel
         %310 = OpLoad %uint %innerRow_1
-        %311 = OpIMul %uint %310 %RowPerThread
+        %311 = OpIMul %uint %310 %uint_4
         %312 = OpLoad %uint %innerCol_1
         %313 = OpIAdd %uint %311 %312
         %314 = OpAccessChain %_ptr_Function_float %acc %313
@@ -561,28 +556,28 @@
                OpStore %t %331
                OpBranch %175
         %176 = OpLabel
-               OpStore %innerRow_2 %106
+               OpStore %innerRow_2 %105
                OpBranch %333
         %333 = OpLabel
                OpLoopMerge %334 %335 None
                OpBranch %336
         %336 = OpLabel
         %338 = OpLoad %uint %innerRow_2
-        %339 = OpULessThan %bool %338 %RowPerThread
+        %339 = OpULessThan %bool %338 %uint_4
         %337 = OpLogicalNot %bool %339
                OpSelectionMerge %340 None
                OpBranchConditional %337 %341 %340
         %341 = OpLabel
                OpBranch %334
         %340 = OpLabel
-               OpStore %innerCol_2 %106
+               OpStore %innerCol_2 %105
                OpBranch %343
         %343 = OpLabel
                OpLoopMerge %344 %345 None
                OpBranch %346
         %346 = OpLabel
         %348 = OpLoad %uint %innerCol_2
-        %349 = OpULessThan %bool %348 %RowPerThread
+        %349 = OpULessThan %bool %348 %uint_4
         %347 = OpLogicalNot %bool %349
                OpSelectionMerge %350 None
                OpBranchConditional %347 %351 %350
@@ -590,7 +585,7 @@
                OpBranch %344
         %350 = OpLabel
         %352 = OpLoad %uint %innerRow_2
-        %353 = OpIMul %uint %352 %RowPerThread
+        %353 = OpIMul %uint %352 %uint_4
         %354 = OpLoad %uint %innerCol_2
         %355 = OpIAdd %uint %353 %354
         %357 = OpLoad %uint %innerRow_2
diff --git a/test/tint/bug/tint/914.wgsl.expected.wgsl b/test/tint/bug/tint/914.wgsl.expected.wgsl
index 67fd494..7b1cedb 100644
--- a/test/tint/bug/tint/914.wgsl.expected.wgsl
+++ b/test/tint/bug/tint/914.wgsl.expected.wgsl
@@ -39,15 +39,15 @@
   }
 }
 
-let RowPerThread : u32 = 4u;
+const RowPerThread : u32 = 4u;
 
-let ColPerThread : u32 = 4u;
+const ColPerThread : u32 = 4u;
 
-let TileAOuter : u32 = 64u;
+const TileAOuter : u32 = 64u;
 
-let TileBOuter : u32 = 64u;
+const TileBOuter : u32 = 64u;
 
-let TileInner : u32 = 64u;
+const TileInner : u32 = 64u;
 
 var<workgroup> mm_Asub : array<array<f32, 64>, 64>;
 
diff --git a/test/tint/const/global/global.wgsl b/test/tint/const/global/global.wgsl
new file mode 100644
index 0000000..12f56a8
--- /dev/null
+++ b/test/tint/const/global/global.wgsl
@@ -0,0 +1,27 @@
+type MyArray = array<f32, 10>;
+
+// Global consts
+const c1 = 1;
+const c2 = 1u;
+const c3 = 1.0;
+
+const c4 = vec3<i32>(1, 1, 1);
+const c5 = vec3<u32>(1u, 1u, 1u);
+const c6 = vec3<f32>(1.0, 1.0, 1.0);
+
+const c7 = mat3x3<f32>(vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0));
+
+const c9 = MyArray();
+
+@fragment
+fn main() -> @location(0) vec4<f32> {
+    var v1 = c1;
+    var v2 = c2;
+    var v3 = c3;
+    var v4 = c4;
+    var v5 = c5;
+    var v6 = c6;
+    var v7 = c7;
+    var v9 = c9;
+    return vec4<f32>(0.0,0.0,0.0,0.0);
+}
diff --git a/test/tint/const/global/global.wgsl.expected.glsl b/test/tint/const/global/global.wgsl.expected.glsl
new file mode 100644
index 0000000..54e642b
--- /dev/null
+++ b/test/tint/const/global/global.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+precision mediump float;
+
+layout(location = 0) out vec4 value;
+vec4 tint_symbol() {
+  int v1 = 1;
+  uint v2 = 1u;
+  float v3 = 1.0f;
+  ivec3 v4 = ivec3(1);
+  uvec3 v5 = uvec3(1u);
+  vec3 v6 = vec3(1.0f);
+  mat3 v7 = mat3(vec3(1.0f), vec3(1.0f), vec3(1.0f));
+  float v9[10] = float[10](0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+  return vec4(0.0f);
+}
+
+void main() {
+  vec4 inner_result = tint_symbol();
+  value = inner_result;
+  return;
+}
diff --git a/test/tint/const/global/global.wgsl.expected.hlsl b/test/tint/const/global/global.wgsl.expected.hlsl
new file mode 100644
index 0000000..cc2c4c6
--- /dev/null
+++ b/test/tint/const/global/global.wgsl.expected.hlsl
@@ -0,0 +1,22 @@
+struct tint_symbol {
+  float4 value : SV_Target0;
+};
+
+float4 main_inner() {
+  int v1 = 1;
+  uint v2 = 1u;
+  float v3 = 1.0f;
+  int3 v4 = (1).xxx;
+  uint3 v5 = (1u).xxx;
+  float3 v6 = (1.0f).xxx;
+  float3x3 v7 = float3x3((1.0f).xxx, (1.0f).xxx, (1.0f).xxx);
+  float v9[10] = (float[10])0;
+  return (0.0f).xxxx;
+}
+
+tint_symbol main() {
+  const float4 inner_result = main_inner();
+  tint_symbol wrapper_result = (tint_symbol)0;
+  wrapper_result.value = inner_result;
+  return wrapper_result;
+}
diff --git a/test/tint/let/global/global.wgsl.expected.msl b/test/tint/const/global/global.wgsl.expected.msl
similarity index 72%
rename from test/tint/let/global/global.wgsl.expected.msl
rename to test/tint/const/global/global.wgsl.expected.msl
index d4ded52..1807542 100644
--- a/test/tint/let/global/global.wgsl.expected.msl
+++ b/test/tint/const/global/global.wgsl.expected.msl
@@ -14,33 +14,19 @@
     T elements[N];
 };
 
-struct MyStruct {
-  float f1;
-};
-
-constant int v1 = 1;
-
-constant uint v2 = 1u;
-
-constant float v3 = 1.0f;
-
-constant int3 v4 = int3(1);
-
-constant uint3 v5 = uint3(1u);
-
-constant float3 v6 = float3(1.0f);
-
-constant float3x3 v7 = float3x3(float3(1.0f), float3(1.0f), float3(1.0f));
-
-constant MyStruct v8 = {};
-
-constant tint_array<float, 10> v9 = tint_array<float, 10>{};
-
 struct tint_symbol_1 {
   float4 value [[color(0)]];
 };
 
 float4 tint_symbol_inner() {
+  int v1 = 1;
+  uint v2 = 1u;
+  float v3 = 1.0f;
+  int3 v4 = int3(1);
+  uint3 v5 = uint3(1u);
+  float3 v6 = float3(1.0f);
+  float3x3 v7 = float3x3(float3(1.0f), float3(1.0f), float3(1.0f));
+  tint_array<float, 10> v9 = tint_array<float, 10>{};
   return float4(0.0f);
 }
 
diff --git a/test/tint/const/global/global.wgsl.expected.spvasm b/test/tint/const/global/global.wgsl.expected.spvasm
new file mode 100644
index 0000000..d93b74d
--- /dev/null
+++ b/test/tint/const/global/global.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 53
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %value
+               OpExecutionMode %main OriginUpperLeft
+               OpName %value "value"
+               OpName %main_inner "main_inner"
+               OpName %v1 "v1"
+               OpName %v2 "v2"
+               OpName %v3 "v3"
+               OpName %v4 "v4"
+               OpName %v5 "v5"
+               OpName %v6 "v6"
+               OpName %v7 "v7"
+               OpName %v9 "v9"
+               OpName %main "main"
+               OpDecorate %value Location 0
+               OpDecorate %_arr_float_uint_10 ArrayStride 4
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %5 = OpConstantNull %v4float
+      %value = OpVariable %_ptr_Output_v4float Output %5
+          %6 = OpTypeFunction %v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Function_int = OpTypePointer Function %int
+         %13 = OpConstantNull %int
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %18 = OpConstantNull %uint
+    %float_1 = OpConstant %float 1
+%_ptr_Function_float = OpTypePointer Function %float
+         %22 = OpConstantNull %float
+      %v3int = OpTypeVector %int 3
+         %24 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %27 = OpConstantNull %v3int
+     %v3uint = OpTypeVector %uint 3
+         %29 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %32 = OpConstantNull %v3uint
+    %v3float = OpTypeVector %float 3
+         %34 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %37 = OpConstantNull %v3float
+%mat3v3float = OpTypeMatrix %v3float 3
+         %39 = OpConstantComposite %mat3v3float %34 %34 %34
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+         %42 = OpConstantNull %mat3v3float
+    %uint_10 = OpConstant %uint 10
+%_arr_float_uint_10 = OpTypeArray %float %uint_10
+         %45 = OpConstantNull %_arr_float_uint_10
+%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10
+       %void = OpTypeVoid
+         %48 = OpTypeFunction %void
+ %main_inner = OpFunction %v4float None %6
+          %8 = OpLabel
+         %v1 = OpVariable %_ptr_Function_int Function %13
+         %v2 = OpVariable %_ptr_Function_uint Function %18
+         %v3 = OpVariable %_ptr_Function_float Function %22
+         %v4 = OpVariable %_ptr_Function_v3int Function %27
+         %v5 = OpVariable %_ptr_Function_v3uint Function %32
+         %v6 = OpVariable %_ptr_Function_v3float Function %37
+         %v7 = OpVariable %_ptr_Function_mat3v3float Function %42
+         %v9 = OpVariable %_ptr_Function__arr_float_uint_10 Function %45
+               OpStore %v1 %int_1
+               OpStore %v2 %uint_1
+               OpStore %v3 %float_1
+               OpStore %v4 %24
+               OpStore %v5 %29
+               OpStore %v6 %34
+               OpStore %v7 %39
+               OpStore %v9 %45
+               OpReturnValue %5
+               OpFunctionEnd
+       %main = OpFunction %void None %48
+         %51 = OpLabel
+         %52 = OpFunctionCall %v4float %main_inner
+               OpStore %value %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/const/global/global.wgsl.expected.wgsl b/test/tint/const/global/global.wgsl.expected.wgsl
new file mode 100644
index 0000000..8fc0106
--- /dev/null
+++ b/test/tint/const/global/global.wgsl.expected.wgsl
@@ -0,0 +1,30 @@
+type MyArray = array<f32, 10>;
+
+const c1 = 1;
+
+const c2 = 1u;
+
+const c3 = 1.0;
+
+const c4 = vec3<i32>(1, 1, 1);
+
+const c5 = vec3<u32>(1u, 1u, 1u);
+
+const c6 = vec3<f32>(1.0, 1.0, 1.0);
+
+const c7 = mat3x3<f32>(vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0));
+
+const c9 = MyArray();
+
+@fragment
+fn main() -> @location(0) vec4<f32> {
+  var v1 = c1;
+  var v2 = c2;
+  var v3 = c3;
+  var v4 = c4;
+  var v5 = c5;
+  var v6 = c6;
+  var v7 = c7;
+  var v9 = c9;
+  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
+}
diff --git a/test/tint/const/inferred/function.wgsl b/test/tint/const/inferred/function.wgsl
new file mode 100644
index 0000000..cd8811b
--- /dev/null
+++ b/test/tint/const/inferred/function.wgsl
@@ -0,0 +1,21 @@
+type MyArray = array<f32, 10>;
+
+// Function-scope consts
+fn const_decls() {
+    const v1 = 1;
+    const v2 = 1u;
+    const v3 = 1.0;
+
+    const v4 = vec3<i32>(1, 1, 1);
+    const v5 = vec3<u32>(1u, 1u, 1u);
+    const v6 = vec3<f32>(1.0, 1.0, 1.0);
+
+    const v7 = mat3x3<f32>(v6, v6, v6);
+
+    const v8 = MyArray();
+}
+
+@fragment
+fn main() -> @location(0) vec4<f32> {
+    return vec4<f32>(0.0,0.0,0.0,0.0);
+}
diff --git a/test/tint/let/global/global.wgsl.expected.glsl b/test/tint/const/inferred/function.wgsl.expected.glsl
similarity index 85%
rename from test/tint/let/global/global.wgsl.expected.glsl
rename to test/tint/const/inferred/function.wgsl.expected.glsl
index b350456..69a3a97 100644
--- a/test/tint/let/global/global.wgsl.expected.glsl
+++ b/test/tint/const/inferred/function.wgsl.expected.glsl
@@ -2,10 +2,6 @@
 precision mediump float;
 
 layout(location = 0) out vec4 value;
-struct MyStruct {
-  float f1;
-};
-
 vec4 tint_symbol() {
   return vec4(0.0f);
 }
diff --git a/test/tint/const/inferred/function.wgsl.expected.hlsl b/test/tint/const/inferred/function.wgsl.expected.hlsl
new file mode 100644
index 0000000..f60a041
--- /dev/null
+++ b/test/tint/const/inferred/function.wgsl.expected.hlsl
@@ -0,0 +1,17 @@
+void const_decls() {
+}
+
+struct tint_symbol {
+  float4 value : SV_Target0;
+};
+
+float4 main_inner() {
+  return (0.0f).xxxx;
+}
+
+tint_symbol main() {
+  const float4 inner_result = main_inner();
+  tint_symbol wrapper_result = (tint_symbol)0;
+  wrapper_result.value = inner_result;
+  return wrapper_result;
+}
diff --git a/test/tint/const/inferred/function.wgsl.expected.msl b/test/tint/const/inferred/function.wgsl.expected.msl
new file mode 100644
index 0000000..ad4f634
--- /dev/null
+++ b/test/tint/const/inferred/function.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void const_decls() {
+}
+
+struct tint_symbol_1 {
+  float4 value [[color(0)]];
+};
+
+float4 tint_symbol_inner() {
+  return float4(0.0f);
+}
+
+fragment tint_symbol_1 tint_symbol() {
+  float4 const inner_result = tint_symbol_inner();
+  tint_symbol_1 wrapper_result = {};
+  wrapper_result.value = inner_result;
+  return wrapper_result;
+}
+
diff --git a/test/tint/const/inferred/function.wgsl.expected.spvasm b/test/tint/const/inferred/function.wgsl.expected.spvasm
new file mode 100644
index 0000000..c24ee9e
--- /dev/null
+++ b/test/tint/const/inferred/function.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %value
+               OpExecutionMode %main OriginUpperLeft
+               OpName %value "value"
+               OpName %const_decls "const_decls"
+               OpName %main_inner "main_inner"
+               OpName %main "main"
+               OpDecorate %value Location 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %5 = OpConstantNull %v4float
+      %value = OpVariable %_ptr_Output_v4float Output %5
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+         %10 = OpTypeFunction %v4float
+%const_decls = OpFunction %void None %6
+          %9 = OpLabel
+               OpReturn
+               OpFunctionEnd
+ %main_inner = OpFunction %v4float None %10
+         %12 = OpLabel
+               OpReturnValue %5
+               OpFunctionEnd
+       %main = OpFunction %void None %6
+         %14 = OpLabel
+         %15 = OpFunctionCall %v4float %main_inner
+               OpStore %value %15
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/const/inferred/function.wgsl.expected.wgsl b/test/tint/const/inferred/function.wgsl.expected.wgsl
new file mode 100644
index 0000000..94ff328
--- /dev/null
+++ b/test/tint/const/inferred/function.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+type MyArray = array<f32, 10>;
+
+fn const_decls() {
+  const v1 = 1;
+  const v2 = 1u;
+  const v3 = 1.0;
+  const v4 = vec3<i32>(1, 1, 1);
+  const v5 = vec3<u32>(1u, 1u, 1u);
+  const v6 = vec3<f32>(1.0, 1.0, 1.0);
+  const v7 = mat3x3<f32>(v6, v6, v6);
+  const v8 = MyArray();
+}
+
+@fragment
+fn main() -> @location(0) vec4<f32> {
+  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
+}
diff --git a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl
index cb4a95b..c41e7ef 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int a = 4;
   const int3 b = int3(1, 2, 3);
-  const int3 r = (a / b);
+  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl
index 8942ff8..ac675e2 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(1u, 2u, 3u);
-  const uint3 r = (a / b);
+  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl
index 33a4443..98c4e64 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(4, 5, 6);
-  const int3 r = (a / b);
+  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl
index 815ad9b..2f2a501 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(4u, 5u, 6u);
-  const uint3 r = (a / b);
+  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl
index 35cc532..99ed924 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int a = 4;
   const int3 b = int3(0, 2, 0);
-  const int3 r = (a / int3(1, 2, 1));
+  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl
index f57e7ed..1ebcc7f 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / uint3(1u, 2u, 1u));
+  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl
index 3cd640e..30d26ca 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(0, 5, 0);
-  const int3 r = (a / int3(1, 5, 1));
+  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl
index ea7ca06..c337dc3 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / uint3(1u, 5u, 1u));
+  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.hlsl
index 5b0bfca..847b0fb 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int a = 4;
   const int3 b = int3(1, 2, 3);
-  const int3 r = (a % b);
+  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.hlsl
index 97533fb..396d57a 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(1u, 2u, 3u);
-  const uint3 r = (a % b);
+  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl
index f39516d..86d89a5 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(4, 5, 6);
-  const int3 r = (a % b);
+  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl
index 33e6b96..5d234b8 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(4u, 5u, 6u);
-  const uint3 r = (a % b);
+  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl
index fa4482f..dfe722c 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int a = 4;
   const int3 b = int3(0, 2, 0);
-  const int3 r = (a % int3(1, 2, 1));
+  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl
index 12aa8c0..5583772 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % uint3(1u, 2u, 1u));
+  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl
index ee60674..ce3cfca 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(0, 5, 0);
-  const int3 r = (a % int3(1, 5, 1));
+  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl
index 2389839..ef3ed45 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.hlsl
@@ -2,6 +2,6 @@
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % uint3(1u, 5u, 1u));
+  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
   return;
 }
diff --git a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.glsl b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.glsl
index 4333b6d..3761f17 100644
--- a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.glsl
+++ b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.glsl
@@ -6,6 +6,6 @@
 }
 int f() {
   int a[8] = int[8](1, 2, 3, 4, 5, 6, 7, 8);
-  return 2;
+  return a[1];
 }
 
diff --git a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.hlsl b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.hlsl
index 25a029a..7174cfa 100644
--- a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.hlsl
+++ b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.hlsl
@@ -5,5 +5,5 @@
 
 int f() {
   const int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
-  return 2;
+  return a[1];
 }
diff --git a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.msl b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.msl
index c5f5865..f999fd1 100644
--- a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.msl
@@ -17,6 +17,6 @@
 int f() {
   tint_array<int, 8> const a = tint_array<int, 8>{1, 2, 3, 4, 5, 6, 7, 8};
   int const i = 1;
-  return 2;
+  return a[i];
 }
 
diff --git a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.spvasm b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.spvasm
index bc9f2a8..3530a99 100644
--- a/test/tint/expressions/index/let/let/literal/array.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/let/literal/array.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 27
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,7 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
+               OpName %var_for_index "var_for_index"
                OpDecorate %_arr_int_uint_8 ArrayStride 4
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
@@ -26,11 +27,18 @@
       %int_7 = OpConstant %int 7
       %int_8 = OpConstant %int 8
          %20 = OpConstantComposite %_arr_int_uint_8 %int_1 %int_2 %int_3 %int_4 %int_5 %int_6 %int_7 %int_8
+%_ptr_Function__arr_int_uint_8 = OpTypePointer Function %_arr_int_uint_8
+         %23 = OpConstantNull %_arr_int_uint_8
+%_ptr_Function_int = OpTypePointer Function %int
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %int None %5
           %8 = OpLabel
-               OpReturnValue %int_2
+%var_for_index = OpVariable %_ptr_Function__arr_int_uint_8 Function %23
+               OpStore %var_for_index %20
+         %25 = OpAccessChain %_ptr_Function_int %var_for_index %int_1
+         %26 = OpLoad %int %25
+               OpReturnValue %26
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.glsl b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.glsl
index a88b339..1b66086 100644
--- a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.glsl
+++ b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.glsl
@@ -6,6 +6,6 @@
 }
 vec3 f() {
   mat3 m = mat3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));
-  return vec3(4.0f, 5.0f, 6.0f);
+  return m[1];
 }
 
diff --git a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.hlsl b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.hlsl
index a730c4e..ad2d36b 100644
--- a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.hlsl
+++ b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.hlsl
@@ -5,5 +5,5 @@
 
 float3 f() {
   const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  return float3(4.0f, 5.0f, 6.0f);
+  return m[1];
 }
diff --git a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.msl b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.msl
index 6cc4826..ca9238e 100644
--- a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.msl
@@ -4,6 +4,6 @@
 float3 f() {
   float3x3 const m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
   int const i = 1;
-  return float3(4.0f, 5.0f, 6.0f);
+  return m[i];
 }
 
diff --git a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.spvasm b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.spvasm
index 9e8d909..500165e 100644
--- a/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/let/literal/matrix.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 26
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,7 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
+               OpName %var_for_index "var_for_index"
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
       %float = OpTypeFloat 32
@@ -30,11 +31,18 @@
          %23 = OpConstantComposite %mat3v3float %14 %18 %22
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+         %28 = OpConstantNull %mat3v3float
+%_ptr_Function_v3float = OpTypePointer Function %v3float
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %v3float None %5
           %9 = OpLabel
-               OpReturnValue %18
+%var_for_index = OpVariable %_ptr_Function_mat3v3float Function %28
+               OpStore %var_for_index %23
+         %30 = OpAccessChain %_ptr_Function_v3float %var_for_index %int_1
+         %31 = OpLoad %v3float %30
+               OpReturnValue %31
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.glsl b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.glsl
index 0d06163..0f24df5 100644
--- a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.glsl
+++ b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.glsl
@@ -6,6 +6,6 @@
 }
 float f() {
   vec3 v = vec3(1.0f, 2.0f, 3.0f);
-  return 2.0f;
+  return v[1];
 }
 
diff --git a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.hlsl b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.hlsl
index 04d609c..ede6118 100644
--- a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.hlsl
+++ b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.hlsl
@@ -5,5 +5,5 @@
 
 float f() {
   const float3 v = float3(1.0f, 2.0f, 3.0f);
-  return 2.0f;
+  return v[1];
 }
diff --git a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.msl b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.msl
index 2218b65..587f5cf 100644
--- a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.msl
@@ -4,6 +4,6 @@
 float f() {
   float3 const v = float3(1.0f, 2.0f, 3.0f);
   int const i = 1;
-  return 2.0f;
+  return v[i];
 }
 
diff --git a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.spvasm b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.spvasm
index 91f8eea..86157e1 100644
--- a/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/let/literal/vector.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 17
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -26,5 +26,6 @@
                OpFunctionEnd
           %f = OpFunction %float None %5
           %8 = OpLabel
-               OpReturnValue %float_2
+         %16 = OpVectorExtractDynamic %float %13 %int_1
+               OpReturnValue %16
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/literal/array.wgsl.expected.glsl b/test/tint/expressions/index/let/literal/array.wgsl.expected.glsl
index 4333b6d..3761f17 100644
--- a/test/tint/expressions/index/let/literal/array.wgsl.expected.glsl
+++ b/test/tint/expressions/index/let/literal/array.wgsl.expected.glsl
@@ -6,6 +6,6 @@
 }
 int f() {
   int a[8] = int[8](1, 2, 3, 4, 5, 6, 7, 8);
-  return 2;
+  return a[1];
 }
 
diff --git a/test/tint/expressions/index/let/literal/array.wgsl.expected.hlsl b/test/tint/expressions/index/let/literal/array.wgsl.expected.hlsl
index 25a029a..7174cfa 100644
--- a/test/tint/expressions/index/let/literal/array.wgsl.expected.hlsl
+++ b/test/tint/expressions/index/let/literal/array.wgsl.expected.hlsl
@@ -5,5 +5,5 @@
 
 int f() {
   const int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
-  return 2;
+  return a[1];
 }
diff --git a/test/tint/expressions/index/let/literal/array.wgsl.expected.msl b/test/tint/expressions/index/let/literal/array.wgsl.expected.msl
index e0a4066..2196ad9 100644
--- a/test/tint/expressions/index/let/literal/array.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/literal/array.wgsl.expected.msl
@@ -16,6 +16,6 @@
 
 int f() {
   tint_array<int, 8> const a = tint_array<int, 8>{1, 2, 3, 4, 5, 6, 7, 8};
-  return 2;
+  return a[1];
 }
 
diff --git a/test/tint/expressions/index/let/literal/array.wgsl.expected.spvasm b/test/tint/expressions/index/let/literal/array.wgsl.expected.spvasm
index bc9f2a8..1dc9cda 100644
--- a/test/tint/expressions/index/let/literal/array.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/literal/array.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 22
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -32,5 +32,6 @@
                OpFunctionEnd
           %f = OpFunction %int None %5
           %8 = OpLabel
-               OpReturnValue %int_2
+         %21 = OpCompositeExtract %int %20 1
+               OpReturnValue %21
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.glsl b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.glsl
index a88b339..1b66086 100644
--- a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.glsl
+++ b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.glsl
@@ -6,6 +6,6 @@
 }
 vec3 f() {
   mat3 m = mat3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));
-  return vec3(4.0f, 5.0f, 6.0f);
+  return m[1];
 }
 
diff --git a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.hlsl b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.hlsl
index a730c4e..ad2d36b 100644
--- a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.hlsl
+++ b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.hlsl
@@ -5,5 +5,5 @@
 
 float3 f() {
   const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  return float3(4.0f, 5.0f, 6.0f);
+  return m[1];
 }
diff --git a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.msl b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.msl
index cd5b0bf..92a23c4 100644
--- a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.msl
@@ -3,6 +3,6 @@
 using namespace metal;
 float3 f() {
   float3x3 const m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  return float3(4.0f, 5.0f, 6.0f);
+  return m[1];
 }
 
diff --git a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.spvasm b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.spvasm
index 362678c..0e46829 100644
--- a/test/tint/expressions/index/let/literal/matrix.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/literal/matrix.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 24
+; Bound: 27
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -28,11 +28,14 @@
     %float_9 = OpConstant %float 9
          %22 = OpConstantComposite %v3float %float_7 %float_8 %float_9
          %23 = OpConstantComposite %mat3v3float %14 %18 %22
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %v3float None %5
           %9 = OpLabel
-               OpReturnValue %18
+         %26 = OpCompositeExtract %v3float %23 1
+               OpReturnValue %26
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/literal/vector.wgsl.expected.glsl b/test/tint/expressions/index/let/literal/vector.wgsl.expected.glsl
index 0d06163..0f24df5 100644
--- a/test/tint/expressions/index/let/literal/vector.wgsl.expected.glsl
+++ b/test/tint/expressions/index/let/literal/vector.wgsl.expected.glsl
@@ -6,6 +6,6 @@
 }
 float f() {
   vec3 v = vec3(1.0f, 2.0f, 3.0f);
-  return 2.0f;
+  return v[1];
 }
 
diff --git a/test/tint/expressions/index/let/literal/vector.wgsl.expected.hlsl b/test/tint/expressions/index/let/literal/vector.wgsl.expected.hlsl
index 04d609c..ede6118 100644
--- a/test/tint/expressions/index/let/literal/vector.wgsl.expected.hlsl
+++ b/test/tint/expressions/index/let/literal/vector.wgsl.expected.hlsl
@@ -5,5 +5,5 @@
 
 float f() {
   const float3 v = float3(1.0f, 2.0f, 3.0f);
-  return 2.0f;
+  return v[1];
 }
diff --git a/test/tint/expressions/index/let/literal/vector.wgsl.expected.msl b/test/tint/expressions/index/let/literal/vector.wgsl.expected.msl
index cb5b4bb..94dc06a 100644
--- a/test/tint/expressions/index/let/literal/vector.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/literal/vector.wgsl.expected.msl
@@ -3,6 +3,6 @@
 using namespace metal;
 float f() {
   float3 const v = float3(1.0f, 2.0f, 3.0f);
-  return 2.0f;
+  return v[1];
 }
 
diff --git a/test/tint/expressions/index/let/literal/vector.wgsl.expected.spvasm b/test/tint/expressions/index/let/literal/vector.wgsl.expected.spvasm
index 0c4b98e..d274e46 100644
--- a/test/tint/expressions/index/let/literal/vector.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/literal/vector.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 17
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -18,11 +18,14 @@
     %float_2 = OpConstant %float 2
     %float_3 = OpConstant %float 3
          %13 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %float None %5
           %8 = OpLabel
-               OpReturnValue %float_2
+         %16 = OpCompositeExtract %float %13 1
+               OpReturnValue %16
                OpFunctionEnd
diff --git a/test/tint/identifiers/underscore/double/const.wgsl b/test/tint/identifiers/underscore/double/const.wgsl
new file mode 100644
index 0000000..cb9cf5b
--- /dev/null
+++ b/test/tint/identifiers/underscore/double/const.wgsl
@@ -0,0 +1,7 @@
+const a : i32 = 1;
+const a__ : i32 = 2;
+
+fn f() {
+    const b = a;
+    const b__ = a__;
+}
diff --git a/test/tint/identifiers/underscore/double/const.wgsl.expected.glsl b/test/tint/identifiers/underscore/double/const.wgsl.expected.glsl
new file mode 100644
index 0000000..45d48f9
--- /dev/null
+++ b/test/tint/identifiers/underscore/double/const.wgsl.expected.glsl
@@ -0,0 +1,9 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+void f() {
+}
+
diff --git a/test/tint/identifiers/underscore/double/const.wgsl.expected.hlsl b/test/tint/identifiers/underscore/double/const.wgsl.expected.hlsl
new file mode 100644
index 0000000..7412e64
--- /dev/null
+++ b/test/tint/identifiers/underscore/double/const.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+void f() {
+}
diff --git a/test/tint/identifiers/underscore/double/const.wgsl.expected.msl b/test/tint/identifiers/underscore/double/const.wgsl.expected.msl
new file mode 100644
index 0000000..7e5829a
--- /dev/null
+++ b/test/tint/identifiers/underscore/double/const.wgsl.expected.msl
@@ -0,0 +1,6 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+}
+
diff --git a/test/tint/identifiers/underscore/double/const.wgsl.expected.spvasm b/test/tint/identifiers/underscore/double/const.wgsl.expected.spvasm
new file mode 100644
index 0000000..1c4d684
--- /dev/null
+++ b/test/tint/identifiers/underscore/double/const.wgsl.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 7
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %1
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/identifiers/underscore/double/const.wgsl.expected.wgsl b/test/tint/identifiers/underscore/double/const.wgsl.expected.wgsl
new file mode 100644
index 0000000..9e4c8c2
--- /dev/null
+++ b/test/tint/identifiers/underscore/double/const.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+const a : i32 = 1;
+
+const a__ : i32 = 2;
+
+fn f() {
+  const b = a;
+  const b__ = a__;
+}
diff --git a/test/tint/identifiers/underscore/double/let.wgsl b/test/tint/identifiers/underscore/double/let.wgsl
index a6f5ba9..0ee15c4 100644
--- a/test/tint/identifiers/underscore/double/let.wgsl
+++ b/test/tint/identifiers/underscore/double/let.wgsl
@@ -1,7 +1,6 @@
-let a : i32 = 1;
-let a__ : i32 = 2;
-
 fn f() {
+    let a = 1;
+    let a__ = a;
     let b = a;
     let b__ = a__;
 }
diff --git a/test/tint/identifiers/underscore/double/let.wgsl.expected.glsl b/test/tint/identifiers/underscore/double/let.wgsl.expected.glsl
index a0bbe15..88072ea 100644
--- a/test/tint/identifiers/underscore/double/let.wgsl.expected.glsl
+++ b/test/tint/identifiers/underscore/double/let.wgsl.expected.glsl
@@ -4,10 +4,9 @@
 void unused_entry_point() {
   return;
 }
-const int a = 1;
-const int a__ = 2;
 void f() {
+  int a = 1;
   int b = a;
-  int b__ = a__;
+  int b__ = a;
 }
 
diff --git a/test/tint/identifiers/underscore/double/let.wgsl.expected.hlsl b/test/tint/identifiers/underscore/double/let.wgsl.expected.hlsl
index 8f66e9d..b35994e 100644
--- a/test/tint/identifiers/underscore/double/let.wgsl.expected.hlsl
+++ b/test/tint/identifiers/underscore/double/let.wgsl.expected.hlsl
@@ -3,10 +3,8 @@
   return;
 }
 
-static const int a = 1;
-static const int a__ = 2;
-
 void f() {
+  const int a = 1;
   const int b = a;
-  const int b__ = a__;
+  const int b__ = a;
 }
diff --git a/test/tint/identifiers/underscore/double/let.wgsl.expected.msl b/test/tint/identifiers/underscore/double/let.wgsl.expected.msl
index 47c1b05..ed01a8f 100644
--- a/test/tint/identifiers/underscore/double/let.wgsl.expected.msl
+++ b/test/tint/identifiers/underscore/double/let.wgsl.expected.msl
@@ -1,11 +1,9 @@
 #include <metal_stdlib>
 
 using namespace metal;
-constant int a = 1;
-
-constant int a__ = 2;
-
 void f() {
+  int const a = 1;
+  int const a__ = a;
   int const b = a;
   int const b__ = a__;
 }
diff --git a/test/tint/identifiers/underscore/double/let.wgsl.expected.spvasm b/test/tint/identifiers/underscore/double/let.wgsl.expected.spvasm
index f51d6d6..a8ec188 100644
--- a/test/tint/identifiers/underscore/double/let.wgsl.expected.spvasm
+++ b/test/tint/identifiers/underscore/double/let.wgsl.expected.spvasm
@@ -1,26 +1,23 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 10
+; Bound: 9
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
-               OpName %a "a"
-               OpName %a__ "a__"
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
-        %int = OpTypeInt 32 1
-          %a = OpConstant %int 1
-        %a__ = OpConstant %int 2
        %void = OpTypeVoid
-          %4 = OpTypeFunction %void
-%unused_entry_point = OpFunction %void None %4
-          %7 = OpLabel
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %4
-          %9 = OpLabel
+          %f = OpFunction %void None %1
+          %6 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/identifiers/underscore/double/let.wgsl.expected.wgsl b/test/tint/identifiers/underscore/double/let.wgsl.expected.wgsl
index a8db78c..ff017ef 100644
--- a/test/tint/identifiers/underscore/double/let.wgsl.expected.wgsl
+++ b/test/tint/identifiers/underscore/double/let.wgsl.expected.wgsl
@@ -1,8 +1,6 @@
-let a : i32 = 1;
-
-let a__ : i32 = 2;
-
 fn f() {
+  let a = 1;
+  let a__ = a;
   let b = a;
   let b__ = a__;
 }
diff --git a/test/tint/identifiers/underscore/prefix/lower/const.wgsl b/test/tint/identifiers/underscore/prefix/lower/const.wgsl
new file mode 100644
index 0000000..626eaa3
--- /dev/null
+++ b/test/tint/identifiers/underscore/prefix/lower/const.wgsl
@@ -0,0 +1,7 @@
+const a : i32 = 1;
+const _a : i32 = 2;
+
+fn f() {
+    const b = a;
+    const _b = _a;
+}
diff --git a/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.glsl b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.glsl
new file mode 100644
index 0000000..45d48f9
--- /dev/null
+++ b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.glsl
@@ -0,0 +1,9 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+void f() {
+}
+
diff --git a/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.hlsl b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.hlsl
new file mode 100644
index 0000000..7412e64
--- /dev/null
+++ b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+void f() {
+}
diff --git a/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.msl b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.msl
new file mode 100644
index 0000000..7e5829a
--- /dev/null
+++ b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.msl
@@ -0,0 +1,6 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+}
+
diff --git a/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.spvasm b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.spvasm
new file mode 100644
index 0000000..1c4d684
--- /dev/null
+++ b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 7
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %1
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.wgsl b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.wgsl
new file mode 100644
index 0000000..1a5d565
--- /dev/null
+++ b/test/tint/identifiers/underscore/prefix/lower/const.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+const a : i32 = 1;
+
+const _a : i32 = 2;
+
+fn f() {
+  const b = a;
+  const _b = _a;
+}
diff --git a/test/tint/identifiers/underscore/prefix/lower/let.wgsl b/test/tint/identifiers/underscore/prefix/lower/let.wgsl
index 6ded620..6670f41 100644
--- a/test/tint/identifiers/underscore/prefix/lower/let.wgsl
+++ b/test/tint/identifiers/underscore/prefix/lower/let.wgsl
@@ -1,7 +1,6 @@
-let a : i32 = 1;
-let _a : i32 = 2;
-
 fn f() {
+    let a = 1;
+    let _a = a;
     let b = a;
     let _b = _a;
 }
diff --git a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.glsl b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.glsl
index c5a6a9f..469fa8c 100644
--- a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.glsl
+++ b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.glsl
@@ -4,10 +4,9 @@
 void unused_entry_point() {
   return;
 }
-const int a = 1;
-const int _a = 2;
 void f() {
+  int a = 1;
   int b = a;
-  int _b = _a;
+  int _b = a;
 }
 
diff --git a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.hlsl b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.hlsl
index 4e65f71..7698191 100644
--- a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.hlsl
+++ b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.hlsl
@@ -3,10 +3,8 @@
   return;
 }
 
-static const int a = 1;
-static const int _a = 2;
-
 void f() {
+  const int a = 1;
   const int b = a;
-  const int _b = _a;
+  const int _b = a;
 }
diff --git a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.msl b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.msl
index 7b3d669..f62a1f4 100644
--- a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.msl
+++ b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.msl
@@ -1,11 +1,9 @@
 #include <metal_stdlib>
 
 using namespace metal;
-constant int a = 1;
-
-constant int _a = 2;
-
 void f() {
+  int const a = 1;
+  int const _a = a;
   int const b = a;
   int const _b = _a;
 }
diff --git a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.spvasm b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.spvasm
index df61dfe..a8ec188 100644
--- a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.spvasm
+++ b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.spvasm
@@ -1,26 +1,23 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 10
+; Bound: 9
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
-               OpName %a "a"
-               OpName %_a "_a"
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
-        %int = OpTypeInt 32 1
-          %a = OpConstant %int 1
-         %_a = OpConstant %int 2
        %void = OpTypeVoid
-          %4 = OpTypeFunction %void
-%unused_entry_point = OpFunction %void None %4
-          %7 = OpLabel
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %4
-          %9 = OpLabel
+          %f = OpFunction %void None %1
+          %6 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.wgsl b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.wgsl
index 9f75219..f2bfc61 100644
--- a/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.wgsl
+++ b/test/tint/identifiers/underscore/prefix/lower/let.wgsl.expected.wgsl
@@ -1,8 +1,6 @@
-let a : i32 = 1;
-
-let _a : i32 = 2;
-
 fn f() {
+  let a = 1;
+  let _a = a;
   let b = a;
   let _b = _a;
 }
diff --git a/test/tint/identifiers/underscore/prefix/upper/let.wgsl b/test/tint/identifiers/underscore/prefix/upper/let.wgsl
index 06c3aae..0a76a88 100644
--- a/test/tint/identifiers/underscore/prefix/upper/let.wgsl
+++ b/test/tint/identifiers/underscore/prefix/upper/let.wgsl
@@ -1,7 +1,6 @@
-let A : i32 = 1;
-let _A : i32 = 2;
-
 fn f() {
+    let A : i32 = 1;
+    let _A : i32 = 2;
     let B = A;
     let _B = _A;
 }
diff --git a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.glsl b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.glsl
index ae9a9c8..2ea9129 100644
--- a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.glsl
+++ b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.glsl
@@ -4,10 +4,8 @@
 void unused_entry_point() {
   return;
 }
-const int A = 1;
-const int _A = 2;
 void f() {
-  int B = A;
-  int _B = _A;
+  int B = 1;
+  int _B = 2;
 }
 
diff --git a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.hlsl b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.hlsl
index fa81c83..11ce076 100644
--- a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.hlsl
+++ b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.hlsl
@@ -3,10 +3,7 @@
   return;
 }
 
-static const int A = 1;
-static const int _A = 2;
-
 void f() {
-  const int B = A;
-  const int _B = _A;
+  const int B = 1;
+  const int _B = 2;
 }
diff --git a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.msl b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.msl
index 5afe76f..3614d7c 100644
--- a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.msl
+++ b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.msl
@@ -1,11 +1,9 @@
 #include <metal_stdlib>
 
 using namespace metal;
-constant int A = 1;
-
-constant int _A = 2;
-
 void f() {
+  int const A = 1;
+  int const _A = 2;
   int const B = A;
   int const _B = _A;
 }
diff --git a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.spvasm b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.spvasm
index 8683520..f52c090 100644
--- a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.spvasm
+++ b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.spvasm
@@ -7,20 +7,18 @@
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
-               OpName %A "A"
-               OpName %_A "_A"
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
-        %int = OpTypeInt 32 1
-          %A = OpConstant %int 1
-         %_A = OpConstant %int 2
        %void = OpTypeVoid
-          %4 = OpTypeFunction %void
-%unused_entry_point = OpFunction %void None %4
-          %7 = OpLabel
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %4
-          %9 = OpLabel
+          %f = OpFunction %void None %1
+          %6 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.wgsl b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.wgsl
index 5c9a0fb..e9ac4ce 100644
--- a/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.wgsl
+++ b/test/tint/identifiers/underscore/prefix/upper/let.wgsl.expected.wgsl
@@ -1,8 +1,6 @@
-let A : i32 = 1;
-
-let _A : i32 = 2;
-
 fn f() {
+  let A : i32 = 1;
+  let _A : i32 = 2;
   let B = A;
   let _B = _A;
 }
diff --git a/test/tint/let/global/global.wgsl b/test/tint/let/global/global.wgsl
deleted file mode 100644
index 6639d5d..0000000
--- a/test/tint/let/global/global.wgsl
+++ /dev/null
@@ -1,24 +0,0 @@
-struct MyStruct {
-    f1 : f32,
-};
-
-type MyArray = array<f32, 10>;
-
-// Global lets
-let v1 = 1;
-let v2 = 1u;
-let v3 = 1.0;
-
-let v4 = vec3<i32>(1, 1, 1);
-let v5 = vec3<u32>(1u, 1u, 1u);
-let v6 = vec3<f32>(1.0, 1.0, 1.0);
-
-let v7 = mat3x3<f32>(vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0));
-
-let v8 = MyStruct();
-let v9 = MyArray();
-
-@fragment
-fn main() -> @location(0) vec4<f32> {
-    return vec4<f32>(0.0,0.0,0.0,0.0);
-}
diff --git a/test/tint/let/global/global.wgsl.expected.hlsl b/test/tint/let/global/global.wgsl.expected.hlsl
deleted file mode 100644
index 2b62ccc..0000000
--- a/test/tint/let/global/global.wgsl.expected.hlsl
+++ /dev/null
@@ -1,28 +0,0 @@
-struct MyStruct {
-  float f1;
-};
-
-static const int v1 = 1;
-static const uint v2 = 1u;
-static const float v3 = 1.0f;
-static const int3 v4 = (1).xxx;
-static const uint3 v5 = (1u).xxx;
-static const float3 v6 = (1.0f).xxx;
-static const float3x3 v7 = float3x3((1.0f).xxx, (1.0f).xxx, (1.0f).xxx);
-static const MyStruct v8 = (MyStruct)0;
-static const float v9[10] = (float[10])0;
-
-struct tint_symbol {
-  float4 value : SV_Target0;
-};
-
-float4 main_inner() {
-  return (0.0f).xxxx;
-}
-
-tint_symbol main() {
-  const float4 inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.value = inner_result;
-  return wrapper_result;
-}
diff --git a/test/tint/let/global/global.wgsl.expected.spvasm b/test/tint/let/global/global.wgsl.expected.spvasm
deleted file mode 100644
index f9c63e2..0000000
--- a/test/tint/let/global/global.wgsl.expected.spvasm
+++ /dev/null
@@ -1,62 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 32
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %main "main" %value
-               OpExecutionMode %main OriginUpperLeft
-               OpName %value "value"
-               OpName %v1 "v1"
-               OpName %v2 "v2"
-               OpName %v3 "v3"
-               OpName %v4 "v4"
-               OpName %v5 "v5"
-               OpName %v6 "v6"
-               OpName %v7 "v7"
-               OpName %MyStruct "MyStruct"
-               OpMemberName %MyStruct 0 "f1"
-               OpName %v8 "v8"
-               OpName %v9 "v9"
-               OpName %main_inner "main_inner"
-               OpName %main "main"
-               OpDecorate %value Location 0
-               OpMemberDecorate %MyStruct 0 Offset 0
-               OpDecorate %_arr_float_uint_10 ArrayStride 4
-      %float = OpTypeFloat 32
-    %v4float = OpTypeVector %float 4
-%_ptr_Output_v4float = OpTypePointer Output %v4float
-          %5 = OpConstantNull %v4float
-      %value = OpVariable %_ptr_Output_v4float Output %5
-        %int = OpTypeInt 32 1
-         %v1 = OpConstant %int 1
-       %uint = OpTypeInt 32 0
-         %v2 = OpConstant %uint 1
-         %v3 = OpConstant %float 1
-      %v3int = OpTypeVector %int 3
-         %v4 = OpConstantComposite %v3int %v1 %v1 %v1
-     %v3uint = OpTypeVector %uint 3
-         %v5 = OpConstantComposite %v3uint %v2 %v2 %v2
-    %v3float = OpTypeVector %float 3
-         %v6 = OpConstantComposite %v3float %v3 %v3 %v3
-%mat3v3float = OpTypeMatrix %v3float 3
-         %v7 = OpConstantComposite %mat3v3float %v6 %v6 %v6
-   %MyStruct = OpTypeStruct %float
-         %v8 = OpConstantNull %MyStruct
-    %uint_10 = OpConstant %uint 10
-%_arr_float_uint_10 = OpTypeArray %float %uint_10
-         %v9 = OpConstantNull %_arr_float_uint_10
-         %24 = OpTypeFunction %v4float
-       %void = OpTypeVoid
-         %27 = OpTypeFunction %void
- %main_inner = OpFunction %v4float None %24
-         %26 = OpLabel
-               OpReturnValue %5
-               OpFunctionEnd
-       %main = OpFunction %void None %27
-         %30 = OpLabel
-         %31 = OpFunctionCall %v4float %main_inner
-               OpStore %value %31
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/let/global/global.wgsl.expected.wgsl b/test/tint/let/global/global.wgsl.expected.wgsl
deleted file mode 100644
index 8f76f49..0000000
--- a/test/tint/let/global/global.wgsl.expected.wgsl
+++ /dev/null
@@ -1,28 +0,0 @@
-struct MyStruct {
-  f1 : f32,
-}
-
-type MyArray = array<f32, 10>;
-
-let v1 = 1;
-
-let v2 = 1u;
-
-let v3 = 1.0;
-
-let v4 = vec3<i32>(1, 1, 1);
-
-let v5 = vec3<u32>(1u, 1u, 1u);
-
-let v6 = vec3<f32>(1.0, 1.0, 1.0);
-
-let v7 = mat3x3<f32>(vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(1.0, 1.0, 1.0));
-
-let v8 = MyStruct();
-
-let v9 = MyArray();
-
-@fragment
-fn main() -> @location(0) vec4<f32> {
-  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
-}
diff --git a/test/tint/let/inferred/function.wgsl.expected.hlsl b/test/tint/let/inferred/function.wgsl.expected.hlsl
index 5a75ea6..152e8d1 100644
--- a/test/tint/let/inferred/function.wgsl.expected.hlsl
+++ b/test/tint/let/inferred/function.wgsl.expected.hlsl
@@ -32,7 +32,7 @@
   const int3 v4 = (1).xxx;
   const uint3 v5 = (1u).xxx;
   const float3 v6 = (1.0f).xxx;
-  const float3x3 v7 = float3x3((1.0f).xxx, (1.0f).xxx, (1.0f).xxx);
+  const float3x3 v7 = float3x3(v6, v6, v6);
   const MyStruct v8 = {1.0f};
   const float v9[10] = (float[10])0;
   const int v10 = ret_i32();
diff --git a/test/tint/let/inferred/function.wgsl.expected.msl b/test/tint/let/inferred/function.wgsl.expected.msl
index 604c979..440faea 100644
--- a/test/tint/let/inferred/function.wgsl.expected.msl
+++ b/test/tint/let/inferred/function.wgsl.expected.msl
@@ -47,7 +47,7 @@
   int3 const v4 = int3(1);
   uint3 const v5 = uint3(1u);
   float3 const v6 = float3(1.0f);
-  float3x3 const v7 = float3x3(float3(1.0f), float3(1.0f), float3(1.0f));
+  float3x3 const v7 = float3x3(v6, v6, v6);
   MyStruct const v8 = {.f1=1.0f};
   tint_array<float, 10> const v9 = tint_array<float, 10>{};
   int const v10 = ret_i32();
diff --git a/test/tint/let/inferred/function.wgsl.expected.spvasm b/test/tint/let/inferred/function.wgsl.expected.spvasm
index e3f36f6..6e2ddcb 100644
--- a/test/tint/let/inferred/function.wgsl.expected.spvasm
+++ b/test/tint/let/inferred/function.wgsl.expected.spvasm
@@ -50,7 +50,6 @@
     %v3float = OpTypeVector %float 3
          %40 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %mat3v3float = OpTypeMatrix %v3float 3
-         %42 = OpConstantComposite %mat3v3float %40 %40 %40
          %43 = OpConstantComposite %MyStruct %float_1
          %50 = OpTypeFunction %v4float
     %ret_i32 = OpFunction %int None %6
@@ -75,6 +74,7 @@
                OpFunctionEnd
   %let_decls = OpFunction %void None %31
          %34 = OpLabel
+         %42 = OpCompositeConstruct %mat3v3float %40 %40 %40
          %44 = OpFunctionCall %int %ret_i32
          %45 = OpFunctionCall %uint %ret_u32
          %46 = OpFunctionCall %float %ret_f32
diff --git a/test/tint/out_of_order_decls/func/const.wgsl b/test/tint/out_of_order_decls/func/const.wgsl
new file mode 100644
index 0000000..df32cd3
--- /dev/null
+++ b/test/tint/out_of_order_decls/func/const.wgsl
@@ -0,0 +1,6 @@
+@fragment
+fn f() {
+  const b = a;
+}
+
+const a : i32 = 1;
diff --git a/test/tint/out_of_order_decls/func/let.wgsl.expected.glsl b/test/tint/out_of_order_decls/func/const.wgsl.expected.glsl
similarity index 74%
rename from test/tint/out_of_order_decls/func/let.wgsl.expected.glsl
rename to test/tint/out_of_order_decls/func/const.wgsl.expected.glsl
index f308959..3d91b99 100644
--- a/test/tint/out_of_order_decls/func/let.wgsl.expected.glsl
+++ b/test/tint/out_of_order_decls/func/const.wgsl.expected.glsl
@@ -1,9 +1,7 @@
 #version 310 es
 precision mediump float;
 
-const int a = 1;
 void f() {
-  int b = a;
 }
 
 void main() {
diff --git a/test/tint/out_of_order_decls/func/const.wgsl.expected.hlsl b/test/tint/out_of_order_decls/func/const.wgsl.expected.hlsl
new file mode 100644
index 0000000..f55de92
--- /dev/null
+++ b/test/tint/out_of_order_decls/func/const.wgsl.expected.hlsl
@@ -0,0 +1,3 @@
+void f() {
+  return;
+}
diff --git a/test/tint/out_of_order_decls/func/let.wgsl.expected.msl b/test/tint/out_of_order_decls/func/const.wgsl.expected.msl
similarity index 67%
rename from test/tint/out_of_order_decls/func/let.wgsl.expected.msl
rename to test/tint/out_of_order_decls/func/const.wgsl.expected.msl
index 2509d6c..7733815 100644
--- a/test/tint/out_of_order_decls/func/let.wgsl.expected.msl
+++ b/test/tint/out_of_order_decls/func/const.wgsl.expected.msl
@@ -1,10 +1,7 @@
 #include <metal_stdlib>
 
 using namespace metal;
-constant int a = 1;
-
 fragment void f() {
-  int const b = a;
   return;
 }
 
diff --git a/test/tint/out_of_order_decls/func/let.wgsl.expected.spvasm b/test/tint/out_of_order_decls/func/const.wgsl.expected.spvasm
similarity index 64%
rename from test/tint/out_of_order_decls/func/let.wgsl.expected.spvasm
rename to test/tint/out_of_order_decls/func/const.wgsl.expected.spvasm
index 452861f..5a28811 100644
--- a/test/tint/out_of_order_decls/func/let.wgsl.expected.spvasm
+++ b/test/tint/out_of_order_decls/func/const.wgsl.expected.spvasm
@@ -1,19 +1,16 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 7
+; Bound: 5
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint Fragment %f "f"
                OpExecutionMode %f OriginUpperLeft
-               OpName %a "a"
                OpName %f "f"
-        %int = OpTypeInt 32 1
-          %a = OpConstant %int 1
        %void = OpTypeVoid
-          %3 = OpTypeFunction %void
-          %f = OpFunction %void None %3
-          %6 = OpLabel
+          %1 = OpTypeFunction %void
+          %f = OpFunction %void None %1
+          %4 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/out_of_order_decls/func/const.wgsl.expected.wgsl b/test/tint/out_of_order_decls/func/const.wgsl.expected.wgsl
new file mode 100644
index 0000000..df32cd3
--- /dev/null
+++ b/test/tint/out_of_order_decls/func/const.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@fragment
+fn f() {
+  const b = a;
+}
+
+const a : i32 = 1;
diff --git a/test/tint/out_of_order_decls/func/let.wgsl b/test/tint/out_of_order_decls/func/let.wgsl
deleted file mode 100644
index 6498fe7..0000000
--- a/test/tint/out_of_order_decls/func/let.wgsl
+++ /dev/null
@@ -1,6 +0,0 @@
-@fragment
-fn f() {
-  let b = a;
-}
-
-let a : i32 = 1;
diff --git a/test/tint/out_of_order_decls/func/let.wgsl.expected.wgsl b/test/tint/out_of_order_decls/func/let.wgsl.expected.wgsl
deleted file mode 100644
index 6498fe7..0000000
--- a/test/tint/out_of_order_decls/func/let.wgsl.expected.wgsl
+++ /dev/null
@@ -1,6 +0,0 @@
-@fragment
-fn f() {
-  let b = a;
-}
-
-let a : i32 = 1;
diff --git a/test/tint/samples/triangle.wgsl b/test/tint/samples/triangle.wgsl
index 8c6afbd..814c1c0 100644
--- a/test/tint/samples/triangle.wgsl
+++ b/test/tint/samples/triangle.wgsl
@@ -13,10 +13,9 @@
 // limitations under the License.
 
 // Vertex shader
-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));
+const pos = array<vec2<f32>, 3>(vec2(0.0, 0.5),
+                                vec2(-0.5, -0.5),
+                                vec2(0.5, -0.5));
 
 @vertex
 fn vtx_main(@builtin(vertex_index) VertexIndex : u32)
diff --git a/test/tint/samples/triangle.wgsl.expected.glsl b/test/tint/samples/triangle.wgsl.expected.glsl
index 915a97d..c0961e2 100644
--- a/test/tint/samples/triangle.wgsl.expected.glsl
+++ b/test/tint/samples/triangle.wgsl.expected.glsl
@@ -1,8 +1,8 @@
 #version 310 es
 
-const vec2 pos[3] = vec2[3](vec2(0.0f, 0.5f), vec2(-0.5f), vec2(0.5f, -0.5f));
 vec4 vtx_main(uint VertexIndex) {
-  return vec4(pos[VertexIndex], 0.0f, 1.0f);
+  vec2 tint_symbol[3] = vec2[3](vec2(0.0f, 0.5f), vec2(-0.5f), vec2(0.5f, -0.5f));
+  return vec4(tint_symbol[VertexIndex], 0.0f, 1.0f);
 }
 
 void main() {
diff --git a/test/tint/samples/triangle.wgsl.expected.hlsl b/test/tint/samples/triangle.wgsl.expected.hlsl
index a17efb8..ee8118cd 100644
--- a/test/tint/samples/triangle.wgsl.expected.hlsl
+++ b/test/tint/samples/triangle.wgsl.expected.hlsl
@@ -1,5 +1,3 @@
-static const float2 pos[3] = {float2(0.0f, 0.5f), (-0.5f).xx, float2(0.5f, -0.5f)};
-
 struct tint_symbol_1 {
   uint VertexIndex : SV_VertexID;
 };
@@ -8,7 +6,8 @@
 };
 
 float4 vtx_main_inner(uint VertexIndex) {
-  return float4(pos[VertexIndex], 0.0f, 1.0f);
+  const float2 tint_symbol_4[3] = {float2(0.0f, 0.5f), (-0.5f).xx, float2(0.5f, -0.5f)};
+  return float4(tint_symbol_4[VertexIndex], 0.0f, 1.0f);
 }
 
 tint_symbol_2 vtx_main(tint_symbol_1 tint_symbol) {
diff --git a/test/tint/samples/triangle.wgsl.expected.msl b/test/tint/samples/triangle.wgsl.expected.msl
index 664ec4e..bac249a 100644
--- a/test/tint/samples/triangle.wgsl.expected.msl
+++ b/test/tint/samples/triangle.wgsl.expected.msl
@@ -14,14 +14,13 @@
     T elements[N];
 };
 
-constant tint_array<float2, 3> pos = tint_array<float2, 3>{float2(0.0f, 0.5f), float2(-0.5f), float2(0.5f, -0.5f)};
-
 struct tint_symbol {
   float4 value [[position]];
 };
 
 float4 vtx_main_inner(uint VertexIndex) {
-  return float4(pos[VertexIndex], 0.0f, 1.0f);
+  tint_array<float2, 3> const tint_symbol_2 = tint_array<float2, 3>{float2(0.0f, 0.5f), float2(-0.5f), float2(0.5f, -0.5f)};
+  return float4(tint_symbol_2[VertexIndex], 0.0f, 1.0f);
 }
 
 vertex tint_symbol vtx_main(uint VertexIndex [[vertex_id]]) {
diff --git a/test/tint/samples/triangle.wgsl.expected.spvasm b/test/tint/samples/triangle.wgsl.expected.spvasm
index 63b1751..c8c5b59 100644
--- a/test/tint/samples/triangle.wgsl.expected.spvasm
+++ b/test/tint/samples/triangle.wgsl.expected.spvasm
@@ -12,7 +12,6 @@
                OpName %value "value"
                OpName %vertex_point_size "vertex_point_size"
                OpName %value_1 "value_1"
-               OpName %pos "pos"
                OpName %vtx_main_inner "vtx_main_inner"
                OpName %VertexIndex "VertexIndex"
                OpName %var_for_index "var_for_index"
@@ -36,16 +35,16 @@
          %11 = OpConstantNull %float
 %vertex_point_size = OpVariable %_ptr_Output_float Output %11
     %value_1 = OpVariable %_ptr_Output_v4float Output %8
+         %13 = OpTypeFunction %v4float %uint
     %v2float = OpTypeVector %float 2
      %uint_3 = OpConstant %uint 3
 %_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3
   %float_0_5 = OpConstant %float 0.5
-         %17 = OpConstantComposite %v2float %11 %float_0_5
+         %21 = OpConstantComposite %v2float %11 %float_0_5
  %float_n0_5 = OpConstant %float -0.5
-         %19 = OpConstantComposite %v2float %float_n0_5 %float_n0_5
-         %20 = OpConstantComposite %v2float %float_0_5 %float_n0_5
-        %pos = OpConstantComposite %_arr_v2float_uint_3 %17 %19 %20
-         %22 = OpTypeFunction %v4float %uint
+         %23 = OpConstantComposite %v2float %float_n0_5 %float_n0_5
+         %24 = OpConstantComposite %v2float %float_0_5 %float_n0_5
+         %25 = OpConstantComposite %_arr_v2float_uint_3 %21 %23 %24
 %_ptr_Function__arr_v2float_uint_3 = OpTypePointer Function %_arr_v2float_uint_3
          %28 = OpConstantNull %_arr_v2float_uint_3
 %_ptr_Function_v2float = OpTypePointer Function %v2float
@@ -54,11 +53,11 @@
          %36 = OpTypeFunction %void
          %42 = OpTypeFunction %v4float
          %45 = OpConstantComposite %v4float %float_1 %11 %11 %float_1
-%vtx_main_inner = OpFunction %v4float None %22
+%vtx_main_inner = OpFunction %v4float None %13
 %VertexIndex = OpFunctionParameter %uint
-         %25 = OpLabel
+         %16 = OpLabel
 %var_for_index = OpVariable %_ptr_Function__arr_v2float_uint_3 Function %28
-               OpStore %var_for_index %pos
+               OpStore %var_for_index %25
          %30 = OpAccessChain %_ptr_Function_v2float %var_for_index %VertexIndex
          %31 = OpLoad %v2float %30
          %32 = OpCompositeExtract %float %31 0
diff --git a/test/tint/samples/triangle.wgsl.expected.wgsl b/test/tint/samples/triangle.wgsl.expected.wgsl
index 84af3b2..dcdf48c 100644
--- a/test/tint/samples/triangle.wgsl.expected.wgsl
+++ b/test/tint/samples/triangle.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-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));
+const pos = array<vec2<f32>, 3>(vec2(0.0, 0.5), vec2(-0.5, -0.5), vec2(0.5, -0.5));
 
 @vertex
 fn vtx_main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
diff --git a/test/tint/shadowing/alias/const.wgsl b/test/tint/shadowing/alias/const.wgsl
new file mode 100644
index 0000000..a2bdd05
--- /dev/null
+++ b/test/tint/shadowing/alias/const.wgsl
@@ -0,0 +1,10 @@
+type a = i32;
+
+fn f() {
+  {
+    const a : a = a();
+    const b = a;
+  }
+  const a : a = a();
+  const b = a;
+}
diff --git a/test/tint/shadowing/alias/const.wgsl.expected.glsl b/test/tint/shadowing/alias/const.wgsl.expected.glsl
new file mode 100644
index 0000000..0da98e3
--- /dev/null
+++ b/test/tint/shadowing/alias/const.wgsl.expected.glsl
@@ -0,0 +1,11 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+void f() {
+  {
+  }
+}
+
diff --git a/test/tint/shadowing/alias/const.wgsl.expected.hlsl b/test/tint/shadowing/alias/const.wgsl.expected.hlsl
new file mode 100644
index 0000000..6316714
--- /dev/null
+++ b/test/tint/shadowing/alias/const.wgsl.expected.hlsl
@@ -0,0 +1,9 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+void f() {
+  {
+  }
+}
diff --git a/test/tint/shadowing/alias/const.wgsl.expected.msl b/test/tint/shadowing/alias/const.wgsl.expected.msl
new file mode 100644
index 0000000..ee183f0
--- /dev/null
+++ b/test/tint/shadowing/alias/const.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  {
+  }
+}
+
diff --git a/test/tint/shadowing/alias/const.wgsl.expected.spvasm b/test/tint/shadowing/alias/const.wgsl.expected.spvasm
new file mode 100644
index 0000000..1c4d684
--- /dev/null
+++ b/test/tint/shadowing/alias/const.wgsl.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 7
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %1
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/shadowing/alias/const.wgsl.expected.wgsl b/test/tint/shadowing/alias/const.wgsl.expected.wgsl
new file mode 100644
index 0000000..a2bdd05
--- /dev/null
+++ b/test/tint/shadowing/alias/const.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+type a = i32;
+
+fn f() {
+  {
+    const a : a = a();
+    const b = a;
+  }
+  const a : a = a();
+  const b = a;
+}
diff --git a/test/tint/statements/decrement/vector_component.wgsl.expected.hlsl b/test/tint/statements/decrement/vector_component.wgsl.expected.hlsl
index 843a2b0..88bf0a8 100644
--- a/test/tint/statements/decrement/vector_component.wgsl.expected.hlsl
+++ b/test/tint/statements/decrement/vector_component.wgsl.expected.hlsl
@@ -7,6 +7,6 @@
 
 void main() {
   const int tint_symbol_1 = 1;
-  a.Store((4u * 1u), asuint((a.Load((4u * 1u)) - 1u)));
+  a.Store((4u * uint(tint_symbol_1)), asuint((a.Load((4u * uint(tint_symbol_1))) - 1u)));
   a.Store(8u, asuint((a.Load(8u) - 1u)));
 }
diff --git a/test/tint/statements/for/condition/array_ctor.wgsl.expected.glsl b/test/tint/statements/for/condition/array_ctor.wgsl.expected.glsl
index b0d20e8..bf6fed3 100644
--- a/test/tint/statements/for/condition/array_ctor.wgsl.expected.glsl
+++ b/test/tint/statements/for/condition/array_ctor.wgsl.expected.glsl
@@ -8,7 +8,7 @@
   int i = 0;
   while (true) {
     int tint_symbol[1] = int[1](1);
-    if (!((i < 1))) {
+    if (!((i < tint_symbol[0]))) {
       break;
     }
     {
diff --git a/test/tint/statements/for/condition/array_ctor.wgsl.expected.hlsl b/test/tint/statements/for/condition/array_ctor.wgsl.expected.hlsl
index ace9c8b..141cd27 100644
--- a/test/tint/statements/for/condition/array_ctor.wgsl.expected.hlsl
+++ b/test/tint/statements/for/condition/array_ctor.wgsl.expected.hlsl
@@ -7,7 +7,7 @@
   int i = 0;
   [loop] while (true) {
     const int tint_symbol[1] = {1};
-    if (!((i < 1))) {
+    if (!((i < tint_symbol[0]))) {
       break;
     }
     {
diff --git a/test/tint/statements/for/condition/array_ctor.wgsl.expected.msl b/test/tint/statements/for/condition/array_ctor.wgsl.expected.msl
index ffacf97..db04646 100644
--- a/test/tint/statements/for/condition/array_ctor.wgsl.expected.msl
+++ b/test/tint/statements/for/condition/array_ctor.wgsl.expected.msl
@@ -18,7 +18,7 @@
   int i = 0;
   while (true) {
     tint_array<int, 1> const tint_symbol = tint_array<int, 1>{1};
-    if (!((i < 1))) {
+    if (!((i < tint_symbol[0]))) {
       break;
     }
     {
diff --git a/test/tint/statements/for/continuing/array_ctor.wgsl.expected.glsl b/test/tint/statements/for/continuing/array_ctor.wgsl.expected.glsl
index e6c4725..9fb3a6a 100644
--- a/test/tint/statements/for/continuing/array_ctor.wgsl.expected.glsl
+++ b/test/tint/statements/for/continuing/array_ctor.wgsl.expected.glsl
@@ -14,7 +14,7 @@
     }
     {
       int tint_symbol[1] = int[1](1);
-      i = (i + 1);
+      i = (i + tint_symbol[0]);
     }
   }
 }
diff --git a/test/tint/statements/for/continuing/array_ctor.wgsl.expected.hlsl b/test/tint/statements/for/continuing/array_ctor.wgsl.expected.hlsl
index 3e525fd..7348a72 100644
--- a/test/tint/statements/for/continuing/array_ctor.wgsl.expected.hlsl
+++ b/test/tint/statements/for/continuing/array_ctor.wgsl.expected.hlsl
@@ -13,7 +13,7 @@
     }
     {
       const int tint_symbol[1] = {1};
-      i = (i + 1);
+      i = (i + tint_symbol[0]);
     }
   }
 }
diff --git a/test/tint/statements/for/continuing/array_ctor.wgsl.expected.msl b/test/tint/statements/for/continuing/array_ctor.wgsl.expected.msl
index e596e14..775e167 100644
--- a/test/tint/statements/for/continuing/array_ctor.wgsl.expected.msl
+++ b/test/tint/statements/for/continuing/array_ctor.wgsl.expected.msl
@@ -24,7 +24,7 @@
     }
     {
       tint_array<int, 1> const tint_symbol = tint_array<int, 1>{1};
-      i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)));
+      i = as_type<int>((as_type<uint>(i) + as_type<uint>(tint_symbol[0])));
     }
   }
 }
diff --git a/test/tint/statements/for/initializer/array_ctor.wgsl.expected.glsl b/test/tint/statements/for/initializer/array_ctor.wgsl.expected.glsl
index fc74894..eeb0109 100644
--- a/test/tint/statements/for/initializer/array_ctor.wgsl.expected.glsl
+++ b/test/tint/statements/for/initializer/array_ctor.wgsl.expected.glsl
@@ -7,7 +7,7 @@
 void f() {
   int tint_symbol[1] = int[1](1);
   {
-    for(int i = 1; false; ) {
+    for(int i = tint_symbol[0]; false; ) {
     }
   }
 }
diff --git a/test/tint/statements/for/initializer/array_ctor.wgsl.expected.hlsl b/test/tint/statements/for/initializer/array_ctor.wgsl.expected.hlsl
index de7d3a5..1de4bce 100644
--- a/test/tint/statements/for/initializer/array_ctor.wgsl.expected.hlsl
+++ b/test/tint/statements/for/initializer/array_ctor.wgsl.expected.hlsl
@@ -6,7 +6,7 @@
 void f() {
   const int tint_symbol[1] = {1};
   {
-    [loop] for(int i = 1; false; ) {
+    [loop] for(int i = tint_symbol[0]; false; ) {
     }
   }
 }
diff --git a/test/tint/statements/for/initializer/array_ctor.wgsl.expected.msl b/test/tint/statements/for/initializer/array_ctor.wgsl.expected.msl
index f729fc7..7600e08 100644
--- a/test/tint/statements/for/initializer/array_ctor.wgsl.expected.msl
+++ b/test/tint/statements/for/initializer/array_ctor.wgsl.expected.msl
@@ -16,7 +16,7 @@
 
 void f() {
   tint_array<int, 1> const tint_symbol = tint_array<int, 1>{1};
-  for(int i = 1; false; ) {
+  for(int i = tint_symbol[0]; false; ) {
   }
 }
 
diff --git a/test/tint/statements/increment/vector_component.wgsl.expected.hlsl b/test/tint/statements/increment/vector_component.wgsl.expected.hlsl
index 9ba08fd..95c9272 100644
--- a/test/tint/statements/increment/vector_component.wgsl.expected.hlsl
+++ b/test/tint/statements/increment/vector_component.wgsl.expected.hlsl
@@ -7,6 +7,6 @@
 
 void main() {
   const int tint_symbol_1 = 1;
-  a.Store((4u * 1u), asuint((a.Load((4u * 1u)) + 1u)));
+  a.Store((4u * uint(tint_symbol_1)), asuint((a.Load((4u * uint(tint_symbol_1))) + 1u)));
   a.Store(8u, asuint((a.Load(8u) + 1u)));
 }
diff --git a/test/tint/types/module_scope_const.wgsl b/test/tint/types/module_scope_const.wgsl
new file mode 100644
index 0000000..c507b99
--- /dev/null
+++ b/test/tint/types/module_scope_const.wgsl
@@ -0,0 +1,13 @@
+const const_bool : bool = bool();
+const const_i32 : i32 = i32();
+const const_u32 : u32 = u32();
+const const_f32 : f32 = f32();
+const const_v2i32 : vec2<i32> = vec2<i32>();
+const const_v3u32 : vec3<u32> = vec3<u32>();
+const const_v4f32 : vec4<f32> = vec4<f32>();
+const const_m3x4 : mat3x4<f32> = mat3x4<f32>();
+const const_arr : array<f32, 4> = array<f32, 4>();
+
+@compute @workgroup_size(1)
+fn main() {
+}
diff --git a/test/tint/types/module_scope_let.wgsl.expected.glsl b/test/tint/types/module_scope_const.wgsl.expected.glsl
similarity index 85%
rename from test/tint/types/module_scope_let.wgsl.expected.glsl
rename to test/tint/types/module_scope_const.wgsl.expected.glsl
index 966cd2a..5b9616f 100644
--- a/test/tint/types/module_scope_let.wgsl.expected.glsl
+++ b/test/tint/types/module_scope_const.wgsl.expected.glsl
@@ -1,9 +1,5 @@
 #version 310 es
 
-struct S {
-  float a;
-};
-
 void tint_symbol() {
 }
 
diff --git a/test/tint/types/module_scope_const.wgsl.expected.hlsl b/test/tint/types/module_scope_const.wgsl.expected.hlsl
new file mode 100644
index 0000000..9989160
--- /dev/null
+++ b/test/tint/types/module_scope_const.wgsl.expected.hlsl
@@ -0,0 +1,4 @@
+[numthreads(1, 1, 1)]
+void main() {
+  return;
+}
diff --git a/test/tint/types/module_scope_const.wgsl.expected.msl b/test/tint/types/module_scope_const.wgsl.expected.msl
new file mode 100644
index 0000000..09c45a0
--- /dev/null
+++ b/test/tint/types/module_scope_const.wgsl.expected.msl
@@ -0,0 +1,7 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+  return;
+}
+
diff --git a/test/tint/types/module_scope_const.wgsl.expected.spvasm b/test/tint/types/module_scope_const.wgsl.expected.spvasm
new file mode 100644
index 0000000..292eb05
--- /dev/null
+++ b/test/tint/types/module_scope_const.wgsl.expected.spvasm
@@ -0,0 +1,16 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 5
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %main "main"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %main = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/types/module_scope_const.wgsl.expected.wgsl b/test/tint/types/module_scope_const.wgsl.expected.wgsl
new file mode 100644
index 0000000..7951dc6
--- /dev/null
+++ b/test/tint/types/module_scope_const.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+const const_bool : bool = bool();
+
+const const_i32 : i32 = i32();
+
+const const_u32 : u32 = u32();
+
+const const_f32 : f32 = f32();
+
+const const_v2i32 : vec2<i32> = vec2<i32>();
+
+const const_v3u32 : vec3<u32> = vec3<u32>();
+
+const const_v4f32 : vec4<f32> = vec4<f32>();
+
+const const_m3x4 : mat3x4<f32> = mat3x4<f32>();
+
+const const_arr : array<f32, 4> = array<f32, 4>();
+
+@compute @workgroup_size(1)
+fn main() {
+}
diff --git a/test/tint/types/module_scope_let.wgsl b/test/tint/types/module_scope_let.wgsl
deleted file mode 100644
index f7e9375..0000000
--- a/test/tint/types/module_scope_let.wgsl
+++ /dev/null
@@ -1,18 +0,0 @@
-struct S {
-  a : f32,
-};
-
-let bool_let : bool = bool();
-let i32_let : i32 = i32();
-let u32_let : u32 = u32();
-let f32_let : f32 = f32();
-let v2i32_let : vec2<i32> = vec2<i32>();
-let v3u32_let : vec3<u32> = vec3<u32>();
-let v4f32_let : vec4<f32> = vec4<f32>();
-let m3x4_let : mat3x4<f32> = mat3x4<f32>();
-let arr_let : array<f32, 4> = array<f32, 4>();
-let struct_let : S = S();
-
-@compute @workgroup_size(1)
-fn main() {
-}
diff --git a/test/tint/types/module_scope_let.wgsl.expected.hlsl b/test/tint/types/module_scope_let.wgsl.expected.hlsl
deleted file mode 100644
index 16d38f9..0000000
--- a/test/tint/types/module_scope_let.wgsl.expected.hlsl
+++ /dev/null
@@ -1,19 +0,0 @@
-struct S {
-  float a;
-};
-
-static const bool bool_let = false;
-static const int i32_let = 0;
-static const uint u32_let = 0u;
-static const float f32_let = 0.0f;
-static const int2 v2i32_let = (0).xx;
-static const uint3 v3u32_let = (0u).xxx;
-static const float4 v4f32_let = (0.0f).xxxx;
-static const float3x4 m3x4_let = float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
-static const float arr_let[4] = (float[4])0;
-static const S struct_let = (S)0;
-
-[numthreads(1, 1, 1)]
-void main() {
-  return;
-}
diff --git a/test/tint/types/module_scope_let.wgsl.expected.msl b/test/tint/types/module_scope_let.wgsl.expected.msl
deleted file mode 100644
index a48f863..0000000
--- a/test/tint/types/module_scope_let.wgsl.expected.msl
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <metal_stdlib>
-
-using namespace metal;
-
-template<typename T, size_t N>
-struct tint_array {
-    const constant T& operator[](size_t i) const constant { return elements[i]; }
-    device T& operator[](size_t i) device { return elements[i]; }
-    const device T& operator[](size_t i) const device { return elements[i]; }
-    thread T& operator[](size_t i) thread { return elements[i]; }
-    const thread T& operator[](size_t i) const thread { return elements[i]; }
-    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
-    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
-    T elements[N];
-};
-
-struct S {
-  float a;
-};
-
-constant bool bool_let = false;
-
-constant int i32_let = 0;
-
-constant uint u32_let = 0u;
-
-constant float f32_let = 0.0f;
-
-constant int2 v2i32_let = int2(0);
-
-constant uint3 v3u32_let = uint3(0u);
-
-constant float4 v4f32_let = float4(0.0f);
-
-constant float3x4 m3x4_let = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
-
-constant tint_array<float, 4> arr_let = tint_array<float, 4>{};
-
-constant S struct_let = {};
-
-kernel void tint_symbol() {
-  return;
-}
-
diff --git a/test/tint/types/module_scope_let.wgsl.expected.spvasm b/test/tint/types/module_scope_let.wgsl.expected.spvasm
deleted file mode 100644
index 9482c0c..0000000
--- a/test/tint/types/module_scope_let.wgsl.expected.spvasm
+++ /dev/null
@@ -1,51 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 26
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %main "main"
-               OpExecutionMode %main LocalSize 1 1 1
-               OpName %bool_let "bool_let"
-               OpName %i32_let "i32_let"
-               OpName %u32_let "u32_let"
-               OpName %f32_let "f32_let"
-               OpName %v2i32_let "v2i32_let"
-               OpName %v3u32_let "v3u32_let"
-               OpName %v4f32_let "v4f32_let"
-               OpName %m3x4_let "m3x4_let"
-               OpName %arr_let "arr_let"
-               OpName %S "S"
-               OpMemberName %S 0 "a"
-               OpName %struct_let "struct_let"
-               OpName %main "main"
-               OpDecorate %_arr_float_uint_4 ArrayStride 4
-               OpMemberDecorate %S 0 Offset 0
-       %bool = OpTypeBool
-   %bool_let = OpConstantNull %bool
-        %int = OpTypeInt 32 1
-    %i32_let = OpConstantNull %int
-       %uint = OpTypeInt 32 0
-    %u32_let = OpConstantNull %uint
-      %float = OpTypeFloat 32
-    %f32_let = OpConstantNull %float
-      %v2int = OpTypeVector %int 2
-  %v2i32_let = OpConstantNull %v2int
-     %v3uint = OpTypeVector %uint 3
-  %v3u32_let = OpConstantNull %v3uint
-    %v4float = OpTypeVector %float 4
-  %v4f32_let = OpConstantNull %v4float
-%mat3v4float = OpTypeMatrix %v4float 3
-   %m3x4_let = OpConstantNull %mat3v4float
-     %uint_4 = OpConstant %uint 4
-%_arr_float_uint_4 = OpTypeArray %float %uint_4
-    %arr_let = OpConstantNull %_arr_float_uint_4
-          %S = OpTypeStruct %float
- %struct_let = OpConstantNull %S
-       %void = OpTypeVoid
-         %22 = OpTypeFunction %void
-       %main = OpFunction %void None %22
-         %25 = OpLabel
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/types/module_scope_let.wgsl.expected.wgsl b/test/tint/types/module_scope_let.wgsl.expected.wgsl
deleted file mode 100644
index 2baded4..0000000
--- a/test/tint/types/module_scope_let.wgsl.expected.wgsl
+++ /dev/null
@@ -1,27 +0,0 @@
-struct S {
-  a : f32,
-}
-
-let bool_let : bool = bool();
-
-let i32_let : i32 = i32();
-
-let u32_let : u32 = u32();
-
-let f32_let : f32 = f32();
-
-let v2i32_let : vec2<i32> = vec2<i32>();
-
-let v3u32_let : vec3<u32> = vec3<u32>();
-
-let v4f32_let : vec4<f32> = vec4<f32>();
-
-let m3x4_let : mat3x4<f32> = mat3x4<f32>();
-
-let arr_let : array<f32, 4> = array<f32, 4>();
-
-let struct_let : S = S();
-
-@compute @workgroup_size(1)
-fn main() {
-}
diff --git a/test/tint/var/initialization/function/array/array_i32.wgsl.expected.glsl b/test/tint/var/initialization/function/array/array_i32.wgsl.expected.glsl
index cff063b..132ba50 100644
--- a/test/tint/var/initialization/function/array/array_i32.wgsl.expected.glsl
+++ b/test/tint/var/initialization/function/array/array_i32.wgsl.expected.glsl
@@ -4,7 +4,7 @@
   int zero[2][3] = int[2][3](int[3](0, 0, 0), int[3](0, 0, 0));
   int tint_symbol_1[3] = int[3](1, 2, 3);
   int tint_symbol_2[3] = int[3](4, 5, 6);
-  int init[2][3] = int[2][3](int[3](1, 2, 3), int[3](4, 5, 6));
+  int init[2][3] = int[2][3](tint_symbol_1, tint_symbol_2);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/var/initialization/function/array/array_i32.wgsl.expected.hlsl b/test/tint/var/initialization/function/array/array_i32.wgsl.expected.hlsl
index 03352d4..88d2dd3 100644
--- a/test/tint/var/initialization/function/array/array_i32.wgsl.expected.hlsl
+++ b/test/tint/var/initialization/function/array/array_i32.wgsl.expected.hlsl
@@ -3,6 +3,6 @@
   int zero[2][3] = (int[2][3])0;
   const int tint_symbol[3] = {1, 2, 3};
   const int tint_symbol_1[3] = {4, 5, 6};
-  int init[2][3] = {{1, 2, 3}, {4, 5, 6}};
+  int init[2][3] = {tint_symbol, tint_symbol_1};
   return;
 }
diff --git a/test/tint/var/initialization/function/array/array_i32.wgsl.expected.msl b/test/tint/var/initialization/function/array/array_i32.wgsl.expected.msl
index 9b02242..7ad097e 100644
--- a/test/tint/var/initialization/function/array/array_i32.wgsl.expected.msl
+++ b/test/tint/var/initialization/function/array/array_i32.wgsl.expected.msl
@@ -18,7 +18,7 @@
   tint_array<tint_array<int, 3>, 2> zero = {};
   tint_array<int, 3> const tint_symbol_1 = tint_array<int, 3>{1, 2, 3};
   tint_array<int, 3> const tint_symbol_2 = tint_array<int, 3>{4, 5, 6};
-  tint_array<tint_array<int, 3>, 2> init = tint_array<tint_array<int, 3>, 2>{tint_array<int, 3>{1, 2, 3}, tint_array<int, 3>{4, 5, 6}};
+  tint_array<tint_array<int, 3>, 2> init = tint_array<tint_array<int, 3>, 2>{tint_symbol_1, tint_symbol_2};
   return;
 }