tint/writer: Handle and emit 'const' variables

Bug: tint:1580
Change-Id: Ib3a5ff5c567e19eca1ba8fb3c2f7e83dee68e2a0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94686
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index d2cb602..4a9f5c6 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -1772,12 +1772,7 @@
             // 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()) {
-                // We do not want to inline array constants, as this will undo the work of
-                // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's
-                // before their usage.
-                if (!constant.Type()->Is<sem::Array>()) {
-                    return EmitConstant(out, constant);
-                }
+                return EmitConstant(out, constant);
             }
         }
     }
@@ -1938,6 +1933,9 @@
         },
         [&](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
+        },
         [&](Default) {
             TINT_ICE(Writer, diagnostics_)
                 << "unhandled global variable type " << global->TypeInfo().name;
@@ -2252,10 +2250,7 @@
             ScopedParen sp(out);
 
             if (constant.AllEqual(start, end)) {
-                if (!EmitConstantRange(out, constant, v->type(), start, start + 1)) {
-                    return false;
-                }
-                return true;
+                return EmitConstantRange(out, constant, v->type(), start, start + 1);
             }
 
             for (size_t i = start; i < end; i++) {
@@ -2287,6 +2282,28 @@
             }
             return true;
         },
+        [&](const sem::Array* a) {
+            if (!EmitType(out, a, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+                return false;
+            }
+
+            ScopedParen sp(out);
+
+            auto* el_ty = a->ElemType();
+
+            uint32_t step = 0;
+            sem::Type::DeepestElementOf(el_ty, &step);
+            for (size_t i = start; i < end; i += step) {
+                if (i > start) {
+                    out << ", ";
+                }
+                if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+                    return false;
+                }
+            }
+
+            return true;
+        },
         [&](Default) {
             diagnostics_.add_error(
                 diag::System::Writer,
@@ -2655,6 +2672,9 @@
             v->variable,  //
             [&](const ast::Var* var) { return EmitVar(var); },
             [&](const ast::Let* let) { return EmitLet(let); },
+            [&](const ast::Const*) {
+                return true;  // Constants are embedded at their use
+            },
             [&](Default) {  //
                 TINT_ICE(Writer, diagnostics_)
                     << "unknown variable type: " << v->variable->TypeInfo().name;
diff --git a/src/tint/writer/glsl/generator_impl_constructor_test.cc b/src/tint/writer/glsl/generator_impl_constructor_test.cc
index e70ecaf..9a937e8 100644
--- a/src/tint/writer/glsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_constructor_test.cc
@@ -189,8 +189,7 @@
     GeneratorImpl& gen = Build();
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
-    EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f),"
-                                        " vec3(0.0f, 0.0f, 0.0f))"));
+    EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(0.0f), vec3(0.0f), vec3(0.0f))"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index e43ad53..b283302 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -805,7 +805,7 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
+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));
@@ -830,6 +830,28 @@
 )");
 }
 
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
+    GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
+    GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
+    GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
+    Func("main", {}, 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
+
+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_OverridableConst) {
     Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
diff --git a/src/tint/writer/glsl/generator_impl_module_constant_test.cc b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
index a97d4cd..b483511 100644
--- a/src/tint/writer/glsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
@@ -22,7 +22,7 @@
 
 using GlslGeneratorImplTest_ModuleConstant = TestHelper;
 
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalLet) {
     auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
     WrapInFunction(Decl(var));
 
@@ -32,7 +32,216 @@
     EXPECT_EQ(gen.result(), "const float pos[3] = float[3](1.0f, 2.0f, 3.0f);\n");
 }
 
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AInt) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AFloat) {
+    auto* var = GlobalConst("G", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_i32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_u32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  uint l = 1u;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  ivec3 l = ivec3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
+    auto* var = GlobalConst("G", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
+    auto* var = GlobalConst("G", nullptr,
+                            Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
+    auto* var = GlobalConst("G", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  float l[3] = float[3](1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
+    auto* var = GlobalConst("G", nullptr,
+                            Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                                      vec2<bool>(true, false),         //
+                                      vec2<bool>(false, true),         //
+                                      vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  bvec2 l[3] = bvec2[3](bvec2(true, false), bvec2(false, true), bvec2(true));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_Override) {
     auto* var = Override("pos", ty.f32(), Expr(3_f),
                          ast::AttributeList{
                              Id(23),
@@ -48,7 +257,7 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_Override_NoConstructor) {
     auto* var = Override("pos", ty.f32(), nullptr,
                          ast::AttributeList{
                              Id(23),
@@ -64,7 +273,7 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
+TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_Override_NoId) {
     auto* a = Override("a", ty.f32(), Expr(3_f),
                        ast::AttributeList{
                            Id(0),
diff --git a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
index c3a02b4..daa664a 100644
--- a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
@@ -16,6 +16,8 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
@@ -36,7 +38,7 @@
     EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
-TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Let) {
     auto* var = Let("a", ty.f32(), Construct(ty.f32()));
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -49,6 +51,228 @@
     EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+    auto* var = Const("a", ty.f32(), Construct(ty.f32()));
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
+
+    GeneratorImpl& gen = Build();
+
+    gen.increment_indent();
+
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "");  // Not a mistake - 'const' is inlined
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AInt) {
+    auto* C = Const("C", nullptr, Expr(1_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AFloat) {
+    auto* C = Const("C", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_i32) {
+    auto* C = Const("C", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  int l = 1;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_u32) {
+    auto* C = Const("C", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  uint l = 1u;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f32) {
+    auto* C = Const("C", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  float l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  ivec3 l = ivec3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
+    auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  vec3 l = vec3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+    auto* C =
+        Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+    auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  mat2x3 l = mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32) {
+    auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  float l[3] = float[3](1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+    auto* C = Const("C", nullptr,
+                    Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                              vec2<bool>(true, false),         //
+                              vec2<bool>(false, true),         //
+                              vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#version 310 es
+
+void f() {
+  bvec2 l[3] = bvec2[3](bvec2(true, false), bvec2(false, true), bvec2(true));
+}
+
+)");
+}
+
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
     auto* var = Var("a", ty.array<f32, 5>());
 
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 8139e6b..bd58e30 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -2617,12 +2617,7 @@
             // 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()) {
-                // We do not want to inline array constants, as this will undo the work of
-                // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's
-                // before their usage.
-                if (!constant.Type()->Is<sem::Array>()) {
-                    return EmitConstant(out, constant);
-                }
+                return EmitConstant(out, constant);
             }
         }
     }
@@ -2856,6 +2851,9 @@
         },
         [&](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
+        },
         [&](Default) {
             TINT_ICE(Writer, diagnostics_)
                 << "unhandled global variable type " << global->TypeInfo().name;
@@ -3174,8 +3172,7 @@
             return true;
         },
         [&](const sem::Matrix* m) {
-            if (!EmitType(out, constant.Type(), ast::StorageClass::kNone, ast::Access::kUndefined,
-                          "")) {
+            if (!EmitType(out, m, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
                 return false;
             }
 
@@ -3193,6 +3190,34 @@
             }
             return true;
         },
+        [&](const sem::Array* a) {
+            if (constant.AllZero(start, end)) {
+                out << "(";
+                if (!EmitType(out, a, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+                    return false;
+                }
+                out << ")0";
+                return true;
+            }
+
+            out << "{";
+            TINT_DEFER(out << "}");
+
+            auto* el_ty = a->ElemType();
+
+            uint32_t step = 0;
+            sem::Type::DeepestElementOf(el_ty, &step);
+            for (size_t i = start; i < end; i += step) {
+                if (i > start) {
+                    out << ", ";
+                }
+                if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+                    return false;
+                }
+            }
+
+            return true;
+        },
         [&](Default) {
             diagnostics_.add_error(
                 diag::System::Writer,
@@ -3571,6 +3596,9 @@
                 v->variable,  //
                 [&](const ast::Var* var) { return EmitVar(var); },
                 [&](const ast::Let* let) { return EmitLet(let); },
+                [&](const ast::Const*) {
+                    return true;  // Constants are embedded at their use
+                },
                 [&](Default) {  //
                     TINT_ICE(Writer, diagnostics_)
                         << "unknown variable type: " << v->variable->TypeInfo().name;
diff --git a/src/tint/writer/hlsl/generator_impl_assign_test.cc b/src/tint/writer/hlsl/generator_impl_assign_test.cc
index 5e5f031..7982e6b 100644
--- a/src/tint/writer/hlsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_assign_test.cc
@@ -41,7 +41,7 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_ConstantIndex) {
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_LetIndex) {
     Func("fn", {}, ty.void_(),
          {
              Decl(Var("lhs", ty.vec3<f32>())),
@@ -63,6 +63,27 @@
 )");
 }
 
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_ConstIndex) {
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.vec3<f32>())),
+             Decl(Var("rhs", ty.f32())),
+             Decl(Const("index", ty.u32(), Expr(0_u))),
+             Assign(IndexAccessor("lhs", "index"), "rhs"),
+         });
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
+  float3 lhs = float3(0.0f, 0.0f, 0.0f);
+  float rhs = 0.0f;
+  lhs[0u] = rhs;
+}
+)");
+}
+
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_DynamicIndex) {
     Func("fn", {}, ty.void_(),
          {
@@ -89,7 +110,7 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_ConstantIndex) {
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_LetIndex) {
     Func("fn", {}, ty.void_(),
          {
              Decl(Var("lhs", ty.mat4x2<f32>())),
@@ -111,6 +132,27 @@
 )");
 }
 
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_ConstIndex) {
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.mat4x2<f32>())),
+             Decl(Var("rhs", ty.vec2<f32>())),
+             Decl(Const("index", ty.u32(), Expr(0_u))),
+             Assign(IndexAccessor("lhs", "index"), "rhs"),
+         });
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
+  float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+  float2 rhs = float2(0.0f, 0.0f);
+  lhs[0u] = rhs;
+}
+)");
+}
+
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_DynamicIndex) {
     Func("fn", {}, ty.void_(),
          {
@@ -142,7 +184,7 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_ConstantIndex) {
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_LetIndex) {
     Func("fn", {}, ty.void_(),
          {
              Decl(Var("lhs", ty.mat4x2<f32>())),
@@ -164,6 +206,27 @@
 )");
 }
 
+TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_ConstIndex) {
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.mat4x2<f32>())),
+             Decl(Var("rhs", ty.f32())),
+             Decl(Const("index", ty.u32(), Expr(0_u))),
+             Assign(IndexAccessor(IndexAccessor("lhs", "index"), "index"), "rhs"),
+         });
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
+  float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+  float rhs = 0.0f;
+  lhs[0u][0u] = rhs;
+}
+)");
+}
+
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_DynamicIndex) {
     Func("fn", {}, ty.void_(),
          {
diff --git a/src/tint/writer/hlsl/generator_impl_function_test.cc b/src/tint/writer/hlsl/generator_impl_function_test.cc
index 17b4ed4..4e8e721 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -705,7 +705,7 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
+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));
@@ -729,6 +729,26 @@
 )");
 }
 
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
+    GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
+    GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
+    GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
+    Func("main", {}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize("width", "height", "depth"),
+         });
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"([numthreads(2, 3, 4)]
+void main() {
+  return;
+}
+)");
+}
+
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_Attribute_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
     Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
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 19be5e6..f858499 100644
--- a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -22,7 +22,7 @@
 
 using HlslGeneratorImplTest_ModuleConstant = TestHelper;
 
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
+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));
 
@@ -32,7 +32,180 @@
     EXPECT_EQ(gen.result(), "static const float pos[3] = {1.0f, 2.0f, 3.0f};\n");
 }
 
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
+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)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_AFloat) {
+    auto* var = GlobalConst("G", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_i32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_u32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const uint l = 1u;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_f32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const int3 l = int3(1, 2, 3);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
+    auto* var = GlobalConst("G", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
+    auto* var = GlobalConst("G", nullptr,
+                            Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
+    auto* var = GlobalConst("G", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float l[3] = {1.0f, 2.0f, 3.0f};
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
+    auto* var = GlobalConst("G", nullptr,
+                            Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                                      vec2<bool>(true, false),         //
+                                      vec2<bool>(false, true),         //
+                                      vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const bool2 l[3] = {bool2(true, false), bool2(false, true), (true).xx};
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override) {
     auto* var = Override("pos", ty.f32(), Expr(3_f),
                          ast::AttributeList{
                              Id(23),
@@ -48,7 +221,7 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override_NoConstructor) {
     auto* var = Override("pos", ty.f32(), nullptr,
                          ast::AttributeList{
                              Id(23),
@@ -64,7 +237,7 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_Override_NoId) {
     auto* a = Override("a", ty.f32(), Expr(3_f),
                        ast::AttributeList{
                            Id(0),
diff --git a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index 1109014..1e111cd 100644
--- a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -16,6 +16,8 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
@@ -36,7 +38,7 @@
     EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
-TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Let) {
     auto* var = Let("a", ty.f32(), Construct(ty.f32()));
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -49,6 +51,192 @@
     EXPECT_EQ(gen.result(), "  const float a = 0.0f;\n");
 }
 
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
+    auto* var = Const("a", ty.f32(), Construct(ty.f32()));
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
+
+    GeneratorImpl& gen = Build();
+
+    gen.increment_indent();
+
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "");  // Not a mistake - 'const' is inlined
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AInt) {
+    auto* C = Const("C", nullptr, Expr(1_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_AFloat) {
+    auto* C = Const("C", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_i32) {
+    auto* C = Const("C", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const int l = 1;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_u32) {
+    auto* C = Const("C", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const uint l = 1u;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_f32) {
+    auto* C = Const("C", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float l = 1.0f;
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const int3 l = int3(1, 2, 3);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
+    auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float3 l = float3(1.0f, 2.0f, 3.0f);
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+    auto* C =
+        Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+    auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32) {
+    auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const float l[3] = {1.0f, 2.0f, 3.0f};
+}
+)");
+}
+
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+    auto* C = Const("C", nullptr,
+                    Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                              vec2<bool>(true, false),         //
+                              vec2<bool>(false, true),         //
+                              vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(void f() {
+  const bool2 l[3] = {bool2(true, false), bool2(false, true), (true).xx};
+}
+)");
+}
+
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
     auto* var = Var("a", ty.array<f32, 5>());
 
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index dd25dcb..a2e333d 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -255,6 +255,9 @@
                 TINT_DEFER(line());
                 return EmitProgramConstVariable(let);
             },
+            [&](const ast::Const*) {
+                return true;  // Constants are embedded at their use
+            },
             [&](const ast::Override* override) {
                 TINT_DEFER(line());
                 return EmitOverride(override);
@@ -1660,6 +1663,34 @@
             }
             return true;
         },
+        [&](const sem::Array* a) {
+            if (!EmitType(out, a, "")) {
+                return false;
+            }
+
+            if (constant.AllZero(start, end)) {
+                out << "{}";
+                return true;
+            }
+
+            out << "{";
+            TINT_DEFER(out << "}");
+
+            auto* el_ty = a->ElemType();
+
+            uint32_t step = 0;
+            sem::Type::DeepestElementOf(el_ty, &step);
+            for (size_t i = start; i < end; i += step) {
+                if (i > start) {
+                    out << ", ";
+                }
+                if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+                    return false;
+                }
+            }
+
+            return true;
+        },
         [&](Default) {
             diagnostics_.add_error(
                 diag::System::Writer,
@@ -1708,12 +1739,7 @@
             // 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()) {
-                // We do not want to inline array constants, as this will undo the work of
-                // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's
-                // before their usage.
-                if (!constant.Type()->Is<sem::Array>()) {
-                    return EmitConstant(out, constant);
-                }
+                return EmitConstant(out, constant);
             }
         }
     }
@@ -2356,6 +2382,9 @@
                 v->variable,  //
                 [&](const ast::Var* var) { return EmitVar(var); },
                 [&](const ast::Let* let) { return EmitLet(let); },
+                [&](const ast::Const*) {
+                    return true;  // Constants are embedded at their use
+                },
                 [&](Default) {  //
                     TINT_ICE(Writer, diagnostics_)
                         << "unknown statement type: " << stmt->TypeInfo().name;
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 3685f40..155f703 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,264 @@
 
 using MslGeneratorImplTest = TestHelper;
 
-TEST_F(MslGeneratorImplTest, Emit_ModuleConstant) {
+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");
+    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_SpecConstant) {
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_AInt) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_AFloat) {
+    auto* var = GlobalConst("G", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_i32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_u32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  uint const l = 1u;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_f32) {
+    auto* var = GlobalConst("G", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_AInt) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  int3 const l = int3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_AFloat) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_f32) {
+    auto* var = GlobalConst("G", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_AFloat) {
+    auto* var = GlobalConst("G", nullptr,
+                            Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_f32) {
+    auto* var = GlobalConst("G", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_arr_f32) {
+    auto* var = GlobalConst("G", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#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];
+};
+
+void f() {
+  tint_array<float, 3> const l = tint_array<float, 3>{1.0f, 2.0f, 3.0f};
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_GlobalConst_arr_vec2_bool) {
+    auto* var = GlobalConst("G", nullptr,
+                            Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                                      vec2<bool>(true, false),         //
+                                      vec2<bool>(false, true),         //
+                                      vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(Let("l", nullptr, Expr(var)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#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];
+};
+
+void f() {
+  tint_array<bool2, 3> const l = tint_array<bool2, 3>{bool2(true, false), bool2(false, true), bool2(true)};
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_Override) {
     auto* var = Override("pos", ty.f32(), Expr(3_f),
                          ast::AttributeList{
                              Id(23),
@@ -43,7 +291,7 @@
     EXPECT_EQ(gen.result(), "constant float pos [[function_constant(23)]];\n");
 }
 
-TEST_F(MslGeneratorImplTest, Emit_SpecConstant_NoId) {
+TEST_F(MslGeneratorImplTest, Emit_Override_NoId) {
     auto* var_a = Override("a", ty.f32(), nullptr,
                            ast::AttributeList{
                                Id(0),
diff --git a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
index 7a0a379..46becb0 100644
--- a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -38,7 +38,7 @@
     EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Let) {
     auto* var = Let("a", ty.f32(), Construct(ty.f32()));
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -51,6 +51,266 @@
     EXPECT_EQ(gen.result(), "  float const a = 0.0f;\n");
 }
 
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
+    auto* var = Const("a", ty.f32(), Construct(ty.f32()));
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
+
+    GeneratorImpl& gen = Build();
+
+    gen.increment_indent();
+
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "");  // Not a mistake - 'const' is inlined
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_AInt) {
+    auto* C = Const("C", nullptr, Expr(1_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_AFloat) {
+    auto* C = Const("C", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_i32) {
+    auto* C = Const("C", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  int const l = 1;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_u32) {
+    auto* C = Const("C", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  uint const l = 1u;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_f32) {
+    auto* C = Const("C", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float const l = 1.0f;
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  int3 const l = int3(1, 2, 3);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
+    auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float3 const l = float3(1.0f, 2.0f, 3.0f);
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+    auto* C =
+        Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+    auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+void f() {
+  float2x3 const l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
+    auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#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];
+};
+
+void f() {
+  tint_array<float, 3> const l = tint_array<float, 3>{1.0f, 2.0f, 3.0f};
+}
+
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+    auto* C = Const("C", nullptr,
+                    Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                              vec2<bool>(true, false),         //
+                              vec2<bool>(false, true),         //
+                              vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(#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];
+};
+
+void f() {
+  tint_array<bool2, 3> const l = tint_array<bool2, 3>{bool2(true, false), bool2(false, true), bool2(true)};
+}
+
+)");
+}
+
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
     auto* var = Var("a", ty.array<f32, 5>(), ast::StorageClass::kNone);
     auto* stmt = Decl(var);
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index ab8952e..28f8727 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -693,6 +693,12 @@
 }
 
 bool Builder::GenerateFunctionVariable(const ast::Variable* v) {
+    if (v->Is<ast::Const>()) {
+        // Constants are generated at their use. This is required as the 'const' declaration may be
+        // abstract-numeric, which has no SPIR-V type.
+        return true;
+    }
+
     uint32_t init_id = 0;
     if (v->constructor) {
         init_id = GenerateExpressionWithLoadIfNeeded(v->constructor);
@@ -703,9 +709,9 @@
 
     auto* sem = builder_.Sem().Get(v);
 
-    if (auto* let = v->As<ast::Let>()) {
-        if (!let->constructor) {
-            error_ = "missing constructor for constant";
+    if (v->Is<ast::Let>()) {
+        if (!v->constructor) {
+            error_ = "missing constructor for let";
             return false;
         }
         RegisterVariable(sem, init_id);
@@ -748,6 +754,12 @@
 }
 
 bool Builder::GenerateGlobalVariable(const ast::Variable* v) {
+    if (v->Is<ast::Const>()) {
+        // Constants are generated at their use. This is required as the 'const' declaration may be
+        // abstract-numeric, which has no SPIR-V type.
+        return true;
+    }
+
     auto* sem = builder_.Sem().Get(v);
     auto* type = sem->Type()->UnwrapRef();
 
@@ -1280,8 +1292,16 @@
 
 uint32_t Builder::GenerateConstructorExpression(const ast::Variable* var,
                                                 const ast::Expression* expr) {
-    if (auto* literal = expr->As<ast::LiteralExpression>()) {
-        return GenerateLiteralIfNeeded(var, literal);
+    if (Is<ast::Override>(var)) {
+        if (auto* literal = expr->As<ast::LiteralExpression>()) {
+            return GenerateLiteralIfNeeded(var, literal);
+        }
+    } else {
+        if (auto* sem = builder_.Sem().Get(expr)) {
+            if (auto constant = sem->ConstantValue()) {
+                return GenerateConstantIfNeeded(constant);
+            }
+        }
     }
     if (auto* call = builder_.Sem().Get<sem::Call>(expr)) {
         if (call->Target()->IsAnyOf<sem::TypeConstructor, sem::TypeConversion>()) {
diff --git a/src/tint/writer/spirv/builder_accessor_expression_test.cc b/src/tint/writer/spirv/builder_accessor_expression_test.cc
index ebb3f96..7c8236b 100644
--- a/src/tint/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_accessor_expression_test.cc
@@ -22,7 +22,7 @@
 
 using BuilderTest = TestHelper;
 
-TEST_F(BuilderTest, Const_IndexAccessor_Vector) {
+TEST_F(BuilderTest, Let_IndexAccessor_Vector) {
     // let ary = vec3<i32>(1, 2, 3);
     // var x = ary[1i];
 
@@ -54,6 +54,35 @@
     Validate(b);
 }
 
+TEST_F(BuilderTest, Const_IndexAccessor_Vector) {
+    // const ary = vec3<i32>(1, 2, 3);
+    // var x = ary[1i];
+
+    auto* ary = Const("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
+    auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeInt 32 1
+%6 = OpConstant %5 2
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%7 = OpVariable %8 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %7 %6
+OpReturn
+)");
+
+    Validate(b);
+}
+
 TEST_F(BuilderTest, Runtime_IndexAccessor_Vector) {
     // var ary : vec3<u32>;
     // var x = ary[1i];
@@ -244,7 +273,7 @@
     Validate(b);
 }
 
-TEST_F(BuilderTest, Const_IndexAccessor_Array_MultiLevel) {
+TEST_F(BuilderTest, Let_IndexAccessor_Array_MultiLevel) {
     // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
     // var x = ary[1i][2i];
 
@@ -287,6 +316,37 @@
     Validate(b);
 }
 
+TEST_F(BuilderTest, Const_IndexAccessor_Array_MultiLevel) {
+    // const ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
+    // var x = ary[1i][2i];
+
+    auto* ary =
+        Const("ary", nullptr,
+              array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 6
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%7 = OpVariable %8 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %7 %6
+OpReturn
+)");
+
+    Validate(b);
+}
+
 TEST_F(BuilderTest, Runtime_IndexAccessor_Array_MultiLevel) {
     // var ary : array<vec3<f32>, 4u>;
     // var x = ary[1i][2i];
@@ -510,7 +570,7 @@
     Validate(b);
 }
 
-TEST_F(BuilderTest, Const_IndexAccessor_Nested_Array_f32) {
+TEST_F(BuilderTest, Let_IndexAccessor_Nested_Array_f32) {
     // let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
     //   array<f32, 2>(0.0, 0.5),
     //   array<f32, 2>(-0.5, -0.5),
@@ -553,6 +613,40 @@
     Validate(b);
 }
 
+TEST_F(BuilderTest, Const_IndexAccessor_Nested_Array_f32) {
+    // const pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
+    //   array<f32, 2>(0.0, 0.5),
+    //   array<f32, 2>(-0.5, -0.5),
+    //   array<f32, 2>(0.5, -0.5));
+    // var x = pos[1u][0u];
+
+    auto* pos = Const("pos", ty.array(ty.vec2<f32>(), 3_u),
+                      Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
+                                vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
+    WrapInFunction(pos, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 -0.5
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%7 = OpVariable %8 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %7 %6
+OpReturn
+)");
+
+    Validate(b);
+}
+
 TEST_F(BuilderTest, Runtime_IndexAccessor_Nested_Array_f32) {
     // var pos : array<array<f32, 2>, 3u>;
     // var x = pos[1u][2u];
@@ -636,7 +730,7 @@
     Validate(b);
 }
 
-TEST_F(BuilderTest, Const_IndexAccessor_Matrix) {
+TEST_F(BuilderTest, Let_IndexAccessor_Matrix) {
     // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
     // var x = a[1i]
 
@@ -674,6 +768,40 @@
     Validate(b);
 }
 
+TEST_F(BuilderTest, Const_IndexAccessor_Matrix) {
+    // const a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
+    // var x = a[1i]
+
+    auto* a = Const("a", ty.mat2x2<f32>(),
+                    Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
+                              Construct(ty.vec2<f32>(), 3_f, 4_f)));
+    auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
+    WrapInFunction(a, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 3
+%8 = OpConstant %6 4
+%9 = OpConstantComposite %5 %7 %8
+%11 = OpTypePointer Function %5
+%12 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%10 = OpVariable %11 Function %12
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %10 %9
+OpReturn
+)");
+
+    Validate(b);
+}
+
 TEST_F(BuilderTest, Runtime_IndexAccessor_Matrix) {
     // var a : mat2x2<f32>;
     // var x = a[1i]
diff --git a/src/tint/writer/spirv/builder_constructor_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
index 9f08347..c1b95df 100644
--- a/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -1073,7 +1073,7 @@
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_F32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_F32_With_F32) {
     auto* ctor = Construct<f32>(2_f);
     GlobalLet("g", ty.f32(), ctor);
 
@@ -1088,7 +1088,45 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_U32_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F32_With_F32) {
+    auto* ctor = Construct<f32>(2_f);
+    GlobalConst("g", ty.f32(), ctor);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 2
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F32_With_F32) {
+    auto* ctor = Construct<f32>(2_f);
+    GlobalVar("g", ty.f32(), ast::StorageClass::kPrivate, ctor);
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+%2 = OpConstant %1 2
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_U32_With_F32) {
     auto* ctor = Construct<u32>(1.5_f);
     GlobalLet("g", ty.u32(), ctor);
 
@@ -1103,9 +1141,47 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_F32) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F32) {
+    auto* ctor = Construct<u32>(1.5_f);
+    GlobalConst("g", ty.u32(), ctor);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F32) {
+    auto* ctor = Construct<u32>(1.5_f);
+    GlobalVar("g", ty.u32(), ast::StorageClass::kPrivate, ctor);
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+%2 = OpConstant %1 1
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec2_With_F32) {
     auto* cast = vec2<f32>(2_f);
-    auto* g = GlobalVar("g", ty.vec2<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* g = GlobalLet("g", ty.vec2<f32>(), cast);
 
     spirv::Builder& b = Build();
 
@@ -1119,7 +1195,46 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F32) {
+    auto* cast = vec2<f32>(2_f);
+    GlobalConst("g", ty.vec2<f32>(), cast);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F32) {
+    auto* cast = vec2<f32>(2_f);
+    auto* g = GlobalVar("g", ty.vec2<f32>(), ast::StorageClass::kPrivate, 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_GlobalLet_Vec2_With_Vec2) {
     auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
     GlobalLet("a", ty.vec2<f32>(), cast);
 
@@ -1137,7 +1252,50 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_Vec2) {
+    auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
+    GlobalConst("g", ty.vec2<f32>(), cast);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_Vec2) {
+    auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
+    GlobalVar("a", ty.vec2<f32>(), ast::StorageClass::kPrivate, 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 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+    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);
 
@@ -1155,7 +1313,50 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec4) {
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec3) {
+    auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
+    GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate, 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 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+    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);
 
@@ -1173,9 +1374,51 @@
     Validate(b);
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32) {
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec4) {
+    auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
+    GlobalVar("a", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalLet_Vec3_With_F32) {
     auto* cast = vec3<f32>(2_f);
-    auto* g = GlobalVar("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* g = GlobalLet("g", ty.vec3<f32>(), cast);
 
     spirv::Builder& b = Build();
 
@@ -1189,55 +1432,158 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32_Vec2) {
-    auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32) {
+    auto* cast = vec3<f32>(2_f);
+    GlobalConst("g", ty.vec3<f32>(), cast);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32) {
+    auto* cast = vec3<f32>(2_f);
+    auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    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 = OpTypeVector %2 2
-%5 = OpConstantComposite %4 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %3 %6 %9
+%4 = OpConstantComposite %1 %3 %3 %3
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec2_F32) {
-    auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
-    auto* g = GlobalVar("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+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), 11u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
-%3 = OpTypeVector %2 2
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %6 %9 %4
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32) {
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32_Vec2) {
+    auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
+    auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, 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_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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F32) {
+    auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
+    auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, 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_GlobalLet_Vec4_With_F32) {
     auto* cast = vec4<f32>(2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
 
     spirv::Builder& b = Build();
 
@@ -1251,147 +1597,372 @@
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_F32_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32) {
+    auto* cast = vec4<f32>(2_f);
+    GlobalConst("g", ty.vec4<f32>(), cast);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32) {
+    auto* cast = vec4<f32>(2_f);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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_GlobalLet_Vec4_With_F32_F32_Vec2) {
     auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    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 = OpTypeVector %2 2
-%5 = OpConstantComposite %4 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %3 %3 %6 %9
+%4 = OpConstantComposite %1 %3 %3 %3 %3
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_Vec2_F32) {
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) {
+    auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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_GlobalLet_Vec4_With_F32_Vec2_F32) {
     auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    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 = OpTypeVector %2 2
-%5 = OpConstantComposite %4 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %3 %6 %9 %3
+%4 = OpConstantComposite %1 %3 %3 %3 %3
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec2_F32_F32) {
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) {
+    auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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_GlobalLet_Vec4_With_Vec2_F32_F32) {
     auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* g = GlobalLet("g", ty.vec4<f32>(), cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpTypeVector %2 2
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantComposite %1 %6 %9 %4 %4
-)");
-}
-
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec2_Vec2) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 4
-%3 = OpTypeVector %2 2
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%11 = OpSpecConstantOp %2 CompositeExtract %5 8
-%12 = OpSpecConstantOp %2 CompositeExtract %5 10
-%13 = OpSpecConstantComposite %1 %6 %9 %11 %12
-)");
-}
-
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_Vec3) {
-    auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+    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 = OpTypeVector %2 3
-%5 = OpConstantComposite %4 %3 %3 %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%12 = OpConstant %7 2
-%11 = OpSpecConstantOp %2 CompositeExtract %5 12
-%13 = OpSpecConstantComposite %1 %3 %6 %9 %11
+%4 = OpConstantComposite %1 %3 %3 %3 %3
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec3_F32) {
-    auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
-    auto* g = GlobalVar("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) {
+    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
-%3 = OpTypeVector %2 3
-%4 = OpConstant %2 2
-%5 = OpConstantComposite %3 %4 %4 %4
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%6 = OpSpecConstantOp %2 CompositeExtract %5 8
-%10 = OpConstant %7 1
-%9 = OpSpecConstantOp %2 CompositeExtract %5 10
-%12 = OpConstant %7 2
-%11 = OpSpecConstantOp %2 CompositeExtract %5 12
-%13 = OpSpecConstantComposite %1 %6 %9 %11 %4
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_Vec2) {
+    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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_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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec3) {
+    auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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_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);
+    WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 2
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+    Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F32) {
+    auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
+    auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, 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
 )");
 }
 
diff --git a/src/tint/writer/spirv/builder_function_attribute_test.cc b/src/tint/writer/spirv/builder_function_attribute_test.cc
index 0bfca02..7bec69e 100644
--- a/src/tint/writer/spirv/builder_function_attribute_test.cc
+++ b/src/tint/writer/spirv/builder_function_attribute_test.cc
@@ -131,7 +131,7 @@
 )");
 }
 
-TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
+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));
@@ -149,6 +149,24 @@
 )");
 }
 
+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));
+    GlobalConst("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_OverridableConst) {
     Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
     Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
@@ -179,7 +197,7 @@
 )");
 }
 
-TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
+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_(), {},
@@ -206,6 +224,33 @@
 )");
 }
 
+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));
+    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_MultipleFragment) {
     auto* func1 = Func("main1", {}, ty.void_(), {},
                        {
diff --git a/src/tint/writer/spirv/builder_function_variable_test.cc b/src/tint/writer/spirv/builder_function_variable_test.cc
index da72233..4a7026a 100644
--- a/src/tint/writer/spirv/builder_function_variable_test.cc
+++ b/src/tint/writer/spirv/builder_function_variable_test.cc
@@ -138,7 +138,7 @@
 )");
 }
 
-TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
+TEST_F(BuilderTest, FunctionVar_LetWithVarInitializer) {
     // var v : f32 = 1.0;
     // let v2 : f32 = v; // Should generate the load
 
@@ -173,7 +173,38 @@
 )");
 }
 
-TEST_F(BuilderTest, FunctionVar_Const) {
+TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
+    // const v : f32 = 1.0;
+    // let v2 : f32 = v;
+
+    auto* v = Const("v", ty.f32(), Expr(1_f));
+
+    auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
+    WrapInFunction(v, v2);
+
+    spirv::Builder& b = Build();
+
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v2"
+)");
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+%2 = OpConstant %1 1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%3 = OpVariable %4 Function %5
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %3 %2
+)");
+}
+
+TEST_F(BuilderTest, FunctionVar_Let) {
     auto* init = vec3<f32>(1_f, 1_f, 3_f);
 
     auto* v = Let("var", ty.vec3<f32>(), init);
@@ -193,5 +224,20 @@
 )");
 }
 
+TEST_F(BuilderTest, FunctionVar_Const) {
+    auto* init = vec3<f32>(1_f, 1_f, 3_f);
+
+    auto* v = Const("var", ty.vec3<f32>(), init);
+
+    WrapInFunction(v);
+
+    spirv::Builder& b = Build();
+
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), "");  // Not a mistake - 'const' is inlined
+}
+
 }  // namespace
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index ca37315..8f0b481 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -61,7 +61,7 @@
 )");
 }
 
-TEST_F(BuilderTest, GlobalVar_Const) {
+TEST_F(BuilderTest, GlobalLet) {
     auto* init = vec3<f32>(1_f, 1_f, 3_f);
 
     auto* v = GlobalLet("l", ty.vec3<f32>(), init);
@@ -81,7 +81,32 @@
 )");
 }
 
-TEST_F(BuilderTest, GlobalVar_Complex_Constructor) {
+TEST_F(BuilderTest, GlobalConst) {
+    // const c = 42;
+    // var v = c;
+
+    auto* c = GlobalConst("c", nullptr, Expr(42_a));
+    GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+%2 = OpConstant %1 42
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+    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);
@@ -100,7 +125,94 @@
 )");
 }
 
-TEST_F(BuilderTest, GlobalVar_Complex_ConstructorNestedVector) {
+TEST_F(BuilderTest, GlobalConst_Vec_Constructor) {
+    // const c = vec3<f32>(1f, 2f, 3f);
+    // var v = c;
+
+    auto* c = GlobalConst("c", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << 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
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, GlobalConst_Vec_AInt_Constructor) {
+    // const c = vec3(1, 2, 3);
+    // var v = c;
+
+    auto* c = GlobalConst("c", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 1
+%4 = OpConstant %2 2
+%5 = OpConstant %2 3
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, GlobalConst_Vec_AFloat_Constructor) {
+    // const c = vec3(1.0, 2.0, 3.0);
+    // var v = c;
+
+    auto* c = GlobalConst("c", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << 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
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+    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);
@@ -119,6 +231,35 @@
 )");
 }
 
+TEST_F(BuilderTest, GlobalConst_Nested_Vec_Constructor) {
+    // const c = vec3<f32>(vec2<f32>(1f, 2f), 3f));
+    // var v = c;
+
+    auto* c = GlobalConst("c", nullptr, vec3<f32>(vec2<f32>(1_f, 2_f), 3_f));
+    GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << 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
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+    Validate(b);
+}
+
 TEST_F(BuilderTest, GlobalVar_WithBindingAndGroup) {
     auto* v =
         GlobalVar("var", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
diff --git a/src/tint/writer/spirv/builder_ident_expression_test.cc b/src/tint/writer/spirv/builder_ident_expression_test.cc
index 37d0fd1..0f24146 100644
--- a/src/tint/writer/spirv/builder_ident_expression_test.cc
+++ b/src/tint/writer/spirv/builder_ident_expression_test.cc
@@ -25,9 +25,9 @@
 TEST_F(BuilderTest, IdentifierExpression_GlobalConst) {
     auto* init = vec3<f32>(1_f, 1_f, 3_f);
 
-    auto* v = GlobalLet("var", ty.vec3<f32>(), init);
+    auto* v = GlobalConst("c", ty.vec3<f32>(), init);
 
-    auto* expr = Expr("var");
+    auto* expr = Expr("c");
     WrapInFunction(expr);
 
     spirv::Builder& b = Build();
@@ -35,14 +35,9 @@
     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 3
-%5 = OpConstantComposite %1 %3 %3 %4
-)");
+    EXPECT_EQ(DumpInstructions(b.types()), R"()");
 
-    EXPECT_EQ(b.GenerateIdentifierExpression(expr), 5u);
+    EXPECT_EQ(b.GenerateIdentifierExpression(expr), 0u);
 }
 
 TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
@@ -115,7 +110,6 @@
 
 TEST_F(BuilderTest, IdentifierExpression_Load) {
     auto* var = GlobalVar("var", ty.i32(), ast::StorageClass::kPrivate);
-
     auto* expr = Add("var", "var");
     WrapInFunction(expr);
 
@@ -138,15 +132,14 @@
 }
 
 TEST_F(BuilderTest, IdentifierExpression_NoLoadConst) {
-    auto* var = GlobalLet("var", ty.i32(), Expr(2_i));
-
-    auto* expr = Add("var", "var");
-    WrapInFunction(expr);
+    auto* let = Let("let", ty.i32(), Expr(2_i));
+    auto* expr = Add("let", "let");
+    WrapInFunction(let, expr);
 
     spirv::Builder& b = Build();
 
     b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunctionVariable(let)) << b.error();
 
     EXPECT_EQ(b.GenerateBinaryExpression(expr->As<ast::BinaryExpression>()), 3u) << b.error();
     EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
diff --git a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index a68932c..aeacd30 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -50,5 +50,189 @@
     EXPECT_EQ(gen.result(), "  var a = 123i;\n");
 }
 
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_AInt) {
+    auto* C = Const("C", nullptr, Expr(1_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = 1;
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_AFloat) {
+    auto* C = Const("C", nullptr, Expr(1._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = 1.0;
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_i32) {
+    auto* C = Const("C", nullptr, Expr(1_i));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = 1i;
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_u32) {
+    auto* C = Const("C", nullptr, Expr(1_u));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = 1u;
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_f32) {
+    auto* C = Const("C", nullptr, Expr(1_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = 1.0f;
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = vec3(1, 2, 3);
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AFloat) {
+    auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1._a, 2._a, 3._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = vec3(1.0, 2.0, 3.0);
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
+    auto* C = Const("C", nullptr, vec3<f32>(1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = vec3<f32>(1.0f, 2.0f, 3.0f);
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
+    auto* C =
+        Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = mat2x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
+    auto* C = Const("C", nullptr, mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = mat2x3<f32>(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f);
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
+    auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = array<f32, 3u>(1.0f, 2.0f, 3.0f);
+  let l = C;
+}
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
+    auto* C = Const("C", nullptr,
+                    Construct(ty.array(ty.vec2<bool>(), 3_u),  //
+                              vec2<bool>(true, false),         //
+                              vec2<bool>(false, true),         //
+                              vec2<bool>(true, true)));
+    Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
+
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+
+    EXPECT_EQ(gen.result(), R"(fn f() {
+  const C = array<vec2<bool>, 3u>(vec2<bool>(true, false), vec2<bool>(false, true), vec2<bool>(true, true));
+  let l = C;
+}
+)");
+}
 }  // namespace
 }  // namespace tint::writer::wgsl
diff --git a/test/tint/array/assign_to_function_var.wgsl.expected.glsl b/test/tint/array/assign_to_function_var.wgsl.expected.glsl
index 1440eef..40c0163 100644
--- a/test/tint/array/assign_to_function_var.wgsl.expected.glsl
+++ b/test/tint/array/assign_to_function_var.wgsl.expected.glsl
@@ -18,7 +18,7 @@
   ivec4 arr[4];
 } src_storage;
 ivec4[4] ret_arr() {
-  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   return tint_symbol_1;
 }
 
@@ -34,7 +34,7 @@
   dst = tint_symbol_3;
   dst = src_param;
   dst = ret_arr();
-  ivec4 src_let[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 src_let[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   dst = src_let;
   dst = src_function;
   dst = src_private;
diff --git a/test/tint/array/assign_to_private_var.wgsl.expected.glsl b/test/tint/array/assign_to_private_var.wgsl.expected.glsl
index 7c59609..33061b3 100644
--- a/test/tint/array/assign_to_private_var.wgsl.expected.glsl
+++ b/test/tint/array/assign_to_private_var.wgsl.expected.glsl
@@ -20,7 +20,7 @@
 ivec4 dst[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
 int dst_nested[4][3][2] = int[4][3][2](int[3][2](int[2](0, 0), int[2](0, 0), int[2](0, 0)), int[3][2](int[2](0, 0), int[2](0, 0), int[2](0, 0)), int[3][2](int[2](0, 0), int[2](0, 0), int[2](0, 0)), int[3][2](int[2](0, 0), int[2](0, 0), int[2](0, 0)));
 ivec4[4] ret_arr() {
-  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   return tint_symbol_1;
 }
 
@@ -35,7 +35,7 @@
   dst = tint_symbol_3;
   dst = src_param;
   dst = ret_arr();
-  ivec4 src_let[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 src_let[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   dst = src_let;
   dst = src_function;
   dst = src_private;
diff --git a/test/tint/array/assign_to_storage_var.wgsl.expected.glsl b/test/tint/array/assign_to_storage_var.wgsl.expected.glsl
index 33c0123..e8aa8f1 100644
--- a/test/tint/array/assign_to_storage_var.wgsl.expected.glsl
+++ b/test/tint/array/assign_to_storage_var.wgsl.expected.glsl
@@ -28,7 +28,7 @@
   int arr[4][3][2];
 } dst_nested;
 ivec4[4] ret_arr() {
-  ivec4 tint_symbol_2[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 tint_symbol_2[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   return tint_symbol_2;
 }
 
@@ -44,7 +44,7 @@
   dst.arr = src_param;
   ivec4 tint_symbol[4] = ret_arr();
   dst.arr = tint_symbol;
-  ivec4 src_let[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 src_let[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   dst.arr = src_let;
   dst.arr = src_function;
   dst.arr = src_private;
diff --git a/test/tint/array/assign_to_workgroup_var.wgsl.expected.glsl b/test/tint/array/assign_to_workgroup_var.wgsl.expected.glsl
index 9c78086..4197eee 100644
--- a/test/tint/array/assign_to_workgroup_var.wgsl.expected.glsl
+++ b/test/tint/array/assign_to_workgroup_var.wgsl.expected.glsl
@@ -20,7 +20,7 @@
 shared ivec4 dst[4];
 shared int dst_nested[4][3][2];
 ivec4[4] ret_arr() {
-  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   return tint_symbol_1;
 }
 
@@ -35,7 +35,7 @@
   dst = tint_symbol_3;
   dst = src_param;
   dst = ret_arr();
-  ivec4 src_let[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 src_let[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   dst = src_let;
   dst = src_function;
   dst = src_private;
diff --git a/test/tint/array/type_constructor.wgsl.expected.glsl b/test/tint/array/type_constructor.wgsl.expected.glsl
index c701d15..a9c5edf 100644
--- a/test/tint/array/type_constructor.wgsl.expected.glsl
+++ b/test/tint/array/type_constructor.wgsl.expected.glsl
@@ -9,16 +9,16 @@
   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](tint_symbol_1, tint_symbol_2, tint_symbol_3);
+  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_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](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_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_9[4] = int[4](1, 2, x, (x + 1));
   int tint_symbol_10[4] = int[4](5, 6, 3, (4 + 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, nested_nonempty[1]);
+  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 tint_symbol_12[4] = int[4](0, 0, 0, 0);
   int subexpr_empty = 0;
   int tint_symbol_13[4] = int[4](1, 2, 3, 4);
@@ -26,13 +26,13 @@
   int tint_symbol_14[4] = int[4](1, x, (x + 1), 4);
   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] = tint_symbol_15[1];
+  int subexpr_nested_empty[4] = int[4](0, 0, 0, 0);
   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](tint_symbol_16, tint_symbol_17);
-  int subexpr_nested_nonempty[4] = tint_symbol_18[1];
+  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, nested_nonempty[1][2]);
+  int tint_symbol_20[2][4] = int[2][4](tint_symbol_19, int[4](21, 22, 23, 24));
   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 6b7e3a6..64829e1 100644
--- a/test/tint/array/type_constructor.wgsl.expected.hlsl
+++ b/test/tint/array/type_constructor.wgsl.expected.hlsl
@@ -8,16 +8,16 @@
   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] = {tint_symbol, tint_symbol_1, tint_symbol_2};
+  const int tint_symbol_3[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
   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] = {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_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_8[4] = {1, 2, x, (x + 1)};
   const int tint_symbol_9[4] = {5, 6, 3, (4 + 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, nested_nonempty[1]};
+  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 tint_symbol_11[4] = (int[4])0;
   const int subexpr_empty = 0;
   const int tint_symbol_12[4] = {1, 2, 3, 4};
@@ -25,13 +25,13 @@
   const int tint_symbol_13[4] = {1, x, (x + 1), 4};
   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] = tint_symbol_14[1];
+  const int subexpr_nested_empty[4] = (int[4])0;
   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] = {tint_symbol_15, tint_symbol_16};
-  const int subexpr_nested_nonempty[4] = tint_symbol_17[1];
+  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, nested_nonempty[1][2]};
+  const int tint_symbol_19[2][4] = {tint_symbol_18, {21, 22, 23, 24}};
   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 58c9a9f..54c3dfd 100644
--- a/test/tint/array/type_constructor.wgsl.expected.msl
+++ b/test/tint/array/type_constructor.wgsl.expected.msl
@@ -23,16 +23,16 @@
   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_symbol_1, tint_symbol_2, tint_symbol_3};
+  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<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_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<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<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<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, nested_nonempty[1]};
+  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<int, 4> const tint_symbol_12 = tint_array<int, 4>{};
   int const subexpr_empty = 0;
   tint_array<int, 4> const tint_symbol_13 = tint_array<int, 4>{1, 2, 3, 4};
@@ -40,13 +40,13 @@
   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_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_symbol_15[1];
+  tint_array<int, 4> const subexpr_nested_empty = tint_array<int, 4>{};
   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_symbol_16, tint_symbol_17};
-  tint_array<int, 4> const subexpr_nested_nonempty = tint_symbol_18[1];
+  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, nested_nonempty[1][2]};
+  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<int, 4> const subexpr_nested_nonempty_with_expr = tint_symbol_20[1];
   return;
 }
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl
index e30425c..827cccc 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl
@@ -24,7 +24,7 @@
   s.arr[idx].f = 0.0f;
   s.arr[idx].g = mat2x3(vec3(0.0f), vec3(0.0f));
   s.arr[idx].h = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
-  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0), ivec4(0, 0, 0, 0));
+  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
   s.arr[idx].i = tint_symbol_1;
 }
 
diff --git a/test/tint/bug/tint/749.spvasm.expected.hlsl b/test/tint/bug/tint/749.spvasm.expected.hlsl
index feecebf..3208c15 100644
--- a/test/tint/bug/tint/749.spvasm.expected.hlsl
+++ b/test/tint/bug/tint/749.spvasm.expected.hlsl
@@ -81,7 +81,7 @@
   const int x_34_save = x_33;
   const int x_35 = obj.numbers[x_34_save];
   const QuicksortObject x_943 = obj;
-  const int tint_symbol_52[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_52[10] = (int[10])0;
   const QuicksortObject tint_symbol_53 = {tint_symbol_52};
   obj = tint_symbol_53;
   obj = x_943;
@@ -94,7 +94,7 @@
     obj.numbers = tint_symbol_13;
   }
   const QuicksortObject x_944 = obj;
-  const int tint_symbol_54[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_54[10] = (int[10])0;
   const QuicksortObject tint_symbol_55 = {tint_symbol_54};
   obj = tint_symbol_55;
   obj = x_944;
@@ -135,7 +135,7 @@
     obj.numbers = tint_symbol_21;
   }
   const QuicksortObject x_950 = obj;
-  const int tint_symbol_56[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_56[10] = (int[10])0;
   const QuicksortObject tint_symbol_57 = {tint_symbol_56};
   obj = tint_symbol_57;
   obj = x_950;
@@ -213,7 +213,7 @@
   const float3 x_536 = float3(x_534.x, x_534.z, x_535.x);
   j_1 = 10;
   const QuicksortObject x_960 = obj;
-  const int tint_symbol_58[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_58[10] = (int[10])0;
   const QuicksortObject tint_symbol_59 = {tint_symbol_58};
   obj = tint_symbol_59;
   obj = x_960;
@@ -230,7 +230,7 @@
     pivot = x_963;
     x_537 = float2(float3(1.0f, 2.0f, 3.0f).y, float3(1.0f, 2.0f, 3.0f).z);
     const QuicksortObject x_964 = obj;
-    const int tint_symbol_60[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_60[10] = (int[10])0;
     const QuicksortObject tint_symbol_61 = {tint_symbol_60};
     obj = tint_symbol_61;
     obj = x_964;
@@ -274,7 +274,7 @@
     param_1 = x_971;
     const int x_62 = obj.numbers[x_61_save];
     const QuicksortObject x_972 = obj;
-    const int tint_symbol_62[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_62[10] = (int[10])0;
     const QuicksortObject tint_symbol_63 = {tint_symbol_62};
     obj = tint_symbol_63;
     obj = x_972;
@@ -334,7 +334,7 @@
       param_1 = x_985;
     }
     const QuicksortObject x_986 = obj;
-    const int tint_symbol_64[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_64[10] = (int[10])0;
     const QuicksortObject tint_symbol_65 = {tint_symbol_64};
     obj = tint_symbol_65;
     obj = x_986;
@@ -393,7 +393,7 @@
   }
   const float2 x_549 = float2(x_534.x, x_534.y);
   const QuicksortObject x_994 = obj;
-  const int tint_symbol_66[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_66[10] = (int[10])0;
   const QuicksortObject tint_symbol_67 = {tint_symbol_66};
   obj = tint_symbol_67;
   obj = x_994;
@@ -463,7 +463,7 @@
   param_5 = x_1007;
   h_1 = 9;
   const int x_1008[10] = stack;
-  const int tint_symbol_68[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_68[10] = (int[10])0;
   stack = tint_symbol_68;
   stack = x_1008;
   const float2 x_556 = float2(float3(1.0f, 2.0f, 3.0f).y, float3(1.0f, 2.0f, 3.0f).y);
@@ -497,14 +497,14 @@
   param_4 = x_1015;
   const int x_95 = l_1;
   const QuicksortObject x_1016 = obj;
-  const int tint_symbol_69[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_69[10] = (int[10])0;
   const QuicksortObject tint_symbol_70 = {tint_symbol_69};
   obj = tint_symbol_70;
   obj = x_1016;
   const float3 x_560 = float3(x_559.y, x_559.x, x_557.x);
   const int x_96_save = x_94;
   const int x_1017[10] = stack;
-  const int tint_symbol_71[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_71[10] = (int[10])0;
   stack = tint_symbol_71;
   stack = x_1017;
   const float3 x_561 = float3(x_556.y, x_556.y, x_556.y);
@@ -555,12 +555,12 @@
     h_1 = 0;
     h_1 = x_1028;
     const int x_1029[10] = stack;
-    const int tint_symbol_72[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_72[10] = (int[10])0;
     stack = tint_symbol_72;
     stack = x_1029;
     const int x_106 = top;
     const int x_1030[10] = stack;
-    const int tint_symbol_73[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_73[10] = (int[10])0;
     stack = tint_symbol_73;
     stack = x_1030;
     const float2 x_567 = float2(x_558.x, x_564.z);
@@ -572,7 +572,7 @@
       break;
     }
     const QuicksortObject x_1032 = obj;
-    const int tint_symbol_74[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_74[10] = (int[10])0;
     const QuicksortObject tint_symbol_75 = {tint_symbol_74};
     obj = tint_symbol_75;
     obj = x_1032;
@@ -599,7 +599,7 @@
     stack[x_96_save] = x_1037;
     const int x_111 = stack[x_110_save];
     const int x_1038[10] = stack;
-    const int tint_symbol_76[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_76[10] = (int[10])0;
     stack = tint_symbol_76;
     stack = x_1038;
     const float3 x_571 = float3(x_559.y, x_559.x, x_564.y);
@@ -608,7 +608,7 @@
     l_1 = x_1039;
     h_1 = x_111;
     const int x_1040[10] = stack;
-    const int tint_symbol_77[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_77[10] = (int[10])0;
     stack = tint_symbol_77;
     stack = x_1040;
     const float2 x_572 = float2(x_562.y, x_561.y);
@@ -700,7 +700,7 @@
       stack[x_100_save] = 0;
       stack[x_100_save] = x_1061;
       const int x_1062[10] = stack;
-      const int tint_symbol_78[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      const int tint_symbol_78[10] = (int[10])0;
       stack = tint_symbol_78;
       stack = x_1062;
       const float2 x_584 = float2(x_569.z, x_569.y);
@@ -740,7 +740,7 @@
       h_1 = x_1070;
       top = x_133;
       const int x_1071[10] = stack;
-      const int tint_symbol_79[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      const int tint_symbol_79[10] = (int[10])0;
       stack = tint_symbol_79;
       stack = x_1071;
       const int x_134 = p;
@@ -766,7 +766,7 @@
     stack[x_96_save] = x_1076;
     const float2 x_592 = float2(float3(1.0f, 2.0f, 3.0f).x, float3(1.0f, 2.0f, 3.0f).y);
     const QuicksortObject x_1077 = obj;
-    const int tint_symbol_80[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_80[10] = (int[10])0;
     const QuicksortObject tint_symbol_81 = {tint_symbol_80};
     obj = tint_symbol_81;
     obj = x_1077;
@@ -833,7 +833,7 @@
       const float2 x_601 = float2(x_563.x, x_563.y);
       stack[x_147_save] = asint((1u + asuint(x_145)));
       const int x_1093[10] = stack;
-      const int tint_symbol_82[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      const int tint_symbol_82[10] = (int[10])0;
       stack = tint_symbol_82;
       stack = x_1093;
       const int x_148 = top;
@@ -842,7 +842,7 @@
       stack[x_114_save] = x_1094;
       const float2 x_602 = float2(x_565.y, x_599.y);
       const int x_1095[10] = stack;
-      const int tint_symbol_83[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      const int tint_symbol_83[10] = (int[10])0;
       stack = tint_symbol_83;
       stack = x_1095;
       const int x_149 = (x_148 + asint(1u));
@@ -878,7 +878,7 @@
       l_1 = x_1103;
       const float2 x_604 = float2(x_563.z, x_564.x);
       const QuicksortObject x_1104 = obj;
-      const int tint_symbol_84[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      const int tint_symbol_84[10] = (int[10])0;
       const QuicksortObject tint_symbol_85 = {tint_symbol_84};
       obj = tint_symbol_85;
       obj = x_1104;
@@ -899,13 +899,13 @@
   uv = x_717;
   i_2 = 0;
   const QuicksortObject x_721 = obj;
-  const int tint_symbol_86[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_86[10] = (int[10])0;
   const QuicksortObject tint_symbol_87 = {tint_symbol_86};
   obj = tint_symbol_87;
   obj = x_721;
   if (true) {
     const QuicksortObject x_722 = obj;
-    const int tint_symbol_88[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_88[10] = (int[10])0;
     const QuicksortObject tint_symbol_89 = {tint_symbol_88};
     obj = tint_symbol_89;
     obj = x_722;
@@ -919,13 +919,13 @@
     color = x_725;
     const float2 x_432 = float2(x_431.y, x_431.y);
     const QuicksortObject x_726 = obj;
-    const int tint_symbol_90[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_90[10] = (int[10])0;
     const QuicksortObject tint_symbol_91 = {tint_symbol_90};
     obj = tint_symbol_91;
     obj = x_726;
   }
   const QuicksortObject x_756 = obj;
-  const int tint_symbol_92[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_92[10] = (int[10])0;
   const QuicksortObject tint_symbol_93 = {tint_symbol_92};
   obj = tint_symbol_93;
   obj = x_756;
@@ -935,7 +935,7 @@
   i_2 = x_757;
   quicksort_();
   const QuicksortObject x_758 = obj;
-  const int tint_symbol_94[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_94[10] = (int[10])0;
   const QuicksortObject tint_symbol_95 = {tint_symbol_94};
   obj = tint_symbol_95;
   obj = x_758;
@@ -950,7 +950,7 @@
   const float2 x_185 = float2(x_184.x, x_184.y);
   const float3 x_448 = float3(x_185.y, x_446.y, x_446.y);
   const QuicksortObject x_761 = obj;
-  const int tint_symbol_96[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_96[10] = (int[10])0;
   const QuicksortObject tint_symbol_97 = {tint_symbol_96};
   obj = tint_symbol_97;
   obj = x_761;
@@ -959,7 +959,7 @@
   uv = x_762;
   const float2 x_191 = asfloat(x_188[0].xy);
   const QuicksortObject x_763 = obj;
-  const int tint_symbol_98[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_98[10] = (int[10])0;
   const QuicksortObject tint_symbol_99 = {tint_symbol_98};
   obj = tint_symbol_99;
   obj = x_763;
@@ -969,7 +969,7 @@
   color = x_764;
   const float2 x_192 = (x_185 / x_191);
   const QuicksortObject x_765 = obj;
-  const int tint_symbol_100[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_100[10] = (int[10])0;
   const QuicksortObject tint_symbol_101 = {tint_symbol_100};
   obj = tint_symbol_101;
   obj = x_765;
@@ -987,7 +987,7 @@
   color = x_768;
   const float3 x_451 = float3(x_185.x, x_185.y, x_446.y);
   const QuicksortObject x_769 = obj;
-  const int tint_symbol_102[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_102[10] = (int[10])0;
   const QuicksortObject tint_symbol_103 = {tint_symbol_102};
   obj = tint_symbol_103;
   obj = x_769;
@@ -996,7 +996,7 @@
   obj.numbers[0u] = x_770;
   const int x_201 = obj.numbers[0u];
   const QuicksortObject x_771 = obj;
-  const int tint_symbol_104[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_104[10] = (int[10])0;
   const QuicksortObject tint_symbol_105 = {tint_symbol_104};
   obj = tint_symbol_105;
   obj = x_771;
@@ -1012,7 +1012,7 @@
   i_2 = 0;
   i_2 = x_774;
   const QuicksortObject x_775 = obj;
-  const int tint_symbol_106[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_106[10] = (int[10])0;
   const QuicksortObject tint_symbol_107 = {tint_symbol_106};
   obj = tint_symbol_107;
   obj = x_775;
@@ -1031,7 +1031,7 @@
   uv.x = 0.0f;
   uv.x = x_778;
   const QuicksortObject x_779 = obj;
-  const int tint_symbol_108[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_108[10] = (int[10])0;
   const QuicksortObject tint_symbol_109 = {tint_symbol_108};
   obj = tint_symbol_109;
   obj = x_779;
@@ -1048,7 +1048,7 @@
     uv.x = x_782;
     const int x_216 = obj.numbers[1];
     const QuicksortObject x_783 = obj;
-    const int tint_symbol_110[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_110[10] = (int[10])0;
     const QuicksortObject tint_symbol_111 = {tint_symbol_110};
     obj = tint_symbol_111;
     obj = x_783;
@@ -1057,7 +1057,7 @@
     uv = (0.0f).xx;
     uv = x_784;
     const QuicksortObject x_785 = obj;
-    const int tint_symbol_112[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_112[10] = (int[10])0;
     const QuicksortObject tint_symbol_113 = {tint_symbol_112};
     obj = tint_symbol_113;
     obj = x_785;
@@ -1177,7 +1177,7 @@
     color.x = 0.0f;
     color.x = x_816;
     const QuicksortObject x_817 = obj;
-    const int tint_symbol_114[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_114[10] = (int[10])0;
     const QuicksortObject tint_symbol_115 = {tint_symbol_114};
     obj = tint_symbol_115;
     obj = x_817;
@@ -1288,7 +1288,7 @@
     uv[0] = x_844;
     const float3 x_482 = float3(x_455.x, x_475.y, x_455.y);
     const QuicksortObject x_845 = obj;
-    const int tint_symbol_116[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_116[10] = (int[10])0;
     const QuicksortObject tint_symbol_117 = {tint_symbol_116};
     obj = tint_symbol_117;
     obj = x_845;
@@ -1361,7 +1361,7 @@
     obj.numbers[6u] = x_863;
     const float2 x_490 = float2(x_480.z, x_480.z);
     const QuicksortObject x_864 = obj;
-    const int tint_symbol_118[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_118[10] = (int[10])0;
     const QuicksortObject tint_symbol_119 = {tint_symbol_118};
     obj = tint_symbol_119;
     obj = x_864;
@@ -1380,7 +1380,7 @@
   color.x = x_867;
   const float x_287 = uv.y;
   const QuicksortObject x_868 = obj;
-  const int tint_symbol_120[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_120[10] = (int[10])0;
   const QuicksortObject tint_symbol_121 = {tint_symbol_120};
   obj = tint_symbol_121;
   obj = x_868;
@@ -1542,7 +1542,7 @@
     uv.x = 0.0f;
     uv.x = x_910;
     const QuicksortObject x_911 = obj;
-    const int tint_symbol_122[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    const int tint_symbol_122[10] = (int[10])0;
     const QuicksortObject tint_symbol_123 = {tint_symbol_122};
     obj = tint_symbol_123;
     obj = x_911;
@@ -1596,12 +1596,12 @@
   uv.x = 0.0f;
   uv.x = x_923;
   const QuicksortObject x_924 = obj;
-  const int tint_symbol_124[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_124[10] = (int[10])0;
   const QuicksortObject tint_symbol_125 = {tint_symbol_124};
   obj = tint_symbol_125;
   obj = x_924;
   const QuicksortObject x_925 = obj;
-  const int tint_symbol_126[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_126[10] = (int[10])0;
   const QuicksortObject tint_symbol_127 = {tint_symbol_126};
   obj = tint_symbol_127;
   obj = x_925;
@@ -1622,7 +1622,7 @@
   uv.x = x_929;
   x_GLF_color = x_330;
   const QuicksortObject x_930 = obj;
-  const int tint_symbol_128[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const int tint_symbol_128[10] = (int[10])0;
   const QuicksortObject tint_symbol_129 = {tint_symbol_128};
   obj = tint_symbol_129;
   obj = x_930;
diff --git a/test/tint/bug/tint/749.spvasm.expected.msl b/test/tint/bug/tint/749.spvasm.expected.msl
index f14f399..88d8ef4 100644
--- a/test/tint/bug/tint/749.spvasm.expected.msl
+++ b/test/tint/bug/tint/749.spvasm.expected.msl
@@ -70,7 +70,7 @@
   int const x_34_save = x_33;
   int const x_35 = (*(tint_symbol_81)).numbers[x_34_save];
   QuicksortObject const x_943 = *(tint_symbol_81);
-  tint_array<int, 10> const tint_symbol_2 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_2 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_3 = {.numbers=tint_symbol_2};
   *(tint_symbol_81) = tint_symbol_3;
   *(tint_symbol_81) = x_943;
@@ -79,7 +79,7 @@
   float3 const x_528 = float3(x_524[0], x_524[2], x_524[0]);
   (*(tint_symbol_81)).numbers[x_36_save] = x_35;
   QuicksortObject const x_944 = *(tint_symbol_81);
-  tint_array<int, 10> const tint_symbol_4 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_4 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_5 = {.numbers=tint_symbol_4};
   *(tint_symbol_81) = tint_symbol_5;
   *(tint_symbol_81) = x_944;
@@ -104,7 +104,7 @@
   (*(tint_symbol_81)).numbers[x_36_save] = 0;
   (*(tint_symbol_81)).numbers[x_36_save] = x_949;
   QuicksortObject const x_950 = *(tint_symbol_81);
-  tint_array<int, 10> const tint_symbol_6 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_6 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_7 = {.numbers=tint_symbol_6};
   *(tint_symbol_81) = tint_symbol_7;
   *(tint_symbol_81) = x_950;
@@ -162,7 +162,7 @@
   float3 const x_536 = float3(x_534[0], x_534[2], x_535[0]);
   j_1 = 10;
   QuicksortObject const x_960 = *(tint_symbol_82);
-  tint_array<int, 10> const tint_symbol_8 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_8 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_9 = {.numbers=tint_symbol_8};
   *(tint_symbol_82) = tint_symbol_9;
   *(tint_symbol_82) = x_960;
@@ -179,7 +179,7 @@
     pivot = x_963;
     x_537 = float2(float3(1.0f, 2.0f, 3.0f)[1], float3(1.0f, 2.0f, 3.0f)[2]);
     QuicksortObject const x_964 = *(tint_symbol_82);
-    tint_array<int, 10> const tint_symbol_10 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_10 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_11 = {.numbers=tint_symbol_10};
     *(tint_symbol_82) = tint_symbol_11;
     *(tint_symbol_82) = x_964;
@@ -215,7 +215,7 @@
     param_1 = x_971;
     int const x_62 = (*(tint_symbol_82)).numbers[x_61_save];
     QuicksortObject const x_972 = *(tint_symbol_82);
-    tint_array<int, 10> const tint_symbol_12 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_12 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_13 = {.numbers=tint_symbol_12};
     *(tint_symbol_82) = tint_symbol_13;
     *(tint_symbol_82) = x_972;
@@ -276,7 +276,7 @@
       param_1 = x_985;
     }
     QuicksortObject const x_986 = *(tint_symbol_82);
-    tint_array<int, 10> const tint_symbol_14 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_14 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_15 = {.numbers=tint_symbol_14};
     *(tint_symbol_82) = tint_symbol_15;
     *(tint_symbol_82) = x_986;
@@ -311,7 +311,7 @@
   (*(tint_symbol_82)).numbers[x_42_save] = x_993;
   float2 const x_549 = float2(x_534[0], x_534[1]);
   QuicksortObject const x_994 = *(tint_symbol_82);
-  tint_array<int, 10> const tint_symbol_16 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_16 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_17 = {.numbers=tint_symbol_16};
   *(tint_symbol_82) = tint_symbol_17;
   *(tint_symbol_82) = x_994;
@@ -381,7 +381,7 @@
   param_5 = x_1007;
   h_1 = 9;
   tint_array<int, 10> const x_1008 = stack;
-  tint_array<int, 10> const tint_symbol_18 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_18 = tint_array<int, 10>{};
   stack = tint_symbol_18;
   stack = x_1008;
   float2 const x_556 = float2(float3(1.0f, 2.0f, 3.0f)[1], float3(1.0f, 2.0f, 3.0f)[1]);
@@ -415,14 +415,14 @@
   param_4 = x_1015;
   int const x_95 = l_1;
   QuicksortObject const x_1016 = *(tint_symbol_83);
-  tint_array<int, 10> const tint_symbol_19 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_19 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_20 = {.numbers=tint_symbol_19};
   *(tint_symbol_83) = tint_symbol_20;
   *(tint_symbol_83) = x_1016;
   float3 const x_560 = float3(x_559[1], x_559[0], x_557[0]);
   int const x_96_save = x_94;
   tint_array<int, 10> const x_1017 = stack;
-  tint_array<int, 10> const tint_symbol_21 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_21 = tint_array<int, 10>{};
   stack = tint_symbol_21;
   stack = x_1017;
   float3 const x_561 = float3(x_556[1], x_556[1], x_556[1]);
@@ -473,12 +473,12 @@
     h_1 = 0;
     h_1 = x_1028;
     tint_array<int, 10> const x_1029 = stack;
-    tint_array<int, 10> const tint_symbol_22 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_22 = tint_array<int, 10>{};
     stack = tint_symbol_22;
     stack = x_1029;
     int const x_106 = top;
     tint_array<int, 10> const x_1030 = stack;
-    tint_array<int, 10> const tint_symbol_23 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_23 = tint_array<int, 10>{};
     stack = tint_symbol_23;
     stack = x_1030;
     float2 const x_567 = float2(x_558[0], x_564[2]);
@@ -490,7 +490,7 @@
       break;
     }
     QuicksortObject const x_1032 = *(tint_symbol_83);
-    tint_array<int, 10> const tint_symbol_24 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_24 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_25 = {.numbers=tint_symbol_24};
     *(tint_symbol_83) = tint_symbol_25;
     *(tint_symbol_83) = x_1032;
@@ -517,7 +517,7 @@
     stack[x_96_save] = x_1037;
     int const x_111 = stack[x_110_save];
     tint_array<int, 10> const x_1038 = stack;
-    tint_array<int, 10> const tint_symbol_26 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_26 = tint_array<int, 10>{};
     stack = tint_symbol_26;
     stack = x_1038;
     float3 const x_571 = float3(x_559[1], x_559[0], x_564[1]);
@@ -526,7 +526,7 @@
     l_1 = x_1039;
     h_1 = x_111;
     tint_array<int, 10> const x_1040 = stack;
-    tint_array<int, 10> const tint_symbol_27 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_27 = tint_array<int, 10>{};
     stack = tint_symbol_27;
     stack = x_1040;
     float2 const x_572 = float2(x_562[1], x_561[1]);
@@ -619,7 +619,7 @@
       stack[x_100_save] = 0;
       stack[x_100_save] = x_1061;
       tint_array<int, 10> const x_1062 = stack;
-      tint_array<int, 10> const tint_symbol_28 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      tint_array<int, 10> const tint_symbol_28 = tint_array<int, 10>{};
       stack = tint_symbol_28;
       stack = x_1062;
       float2 const x_584 = float2(x_569[2], x_569[1]);
@@ -659,7 +659,7 @@
       h_1 = x_1070;
       top = x_133;
       tint_array<int, 10> const x_1071 = stack;
-      tint_array<int, 10> const tint_symbol_29 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      tint_array<int, 10> const tint_symbol_29 = tint_array<int, 10>{};
       stack = tint_symbol_29;
       stack = x_1071;
       int const x_134 = p;
@@ -685,7 +685,7 @@
     stack[x_96_save] = x_1076;
     float2 const x_592 = float2(float3(1.0f, 2.0f, 3.0f)[0], float3(1.0f, 2.0f, 3.0f)[1]);
     QuicksortObject const x_1077 = *(tint_symbol_83);
-    tint_array<int, 10> const tint_symbol_30 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_30 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_31 = {.numbers=tint_symbol_30};
     *(tint_symbol_83) = tint_symbol_31;
     *(tint_symbol_83) = x_1077;
@@ -752,7 +752,7 @@
       float2 const x_601 = float2(x_563[0], x_563[1]);
       stack[x_147_save] = as_type<int>((1u + as_type<uint>(x_145)));
       tint_array<int, 10> const x_1093 = stack;
-      tint_array<int, 10> const tint_symbol_32 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      tint_array<int, 10> const tint_symbol_32 = tint_array<int, 10>{};
       stack = tint_symbol_32;
       stack = x_1093;
       int const x_148 = top;
@@ -761,7 +761,7 @@
       stack[x_114_save] = x_1094;
       float2 const x_602 = float2(x_565[1], x_599[1]);
       tint_array<int, 10> const x_1095 = stack;
-      tint_array<int, 10> const tint_symbol_33 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      tint_array<int, 10> const tint_symbol_33 = tint_array<int, 10>{};
       stack = tint_symbol_33;
       stack = x_1095;
       int const x_149 = as_type<int>((as_type<uint>(x_148) + as_type<uint>(as_type<int>(1u))));
@@ -797,7 +797,7 @@
       l_1 = x_1103;
       float2 const x_604 = float2(x_563[2], x_564[0]);
       QuicksortObject const x_1104 = *(tint_symbol_83);
-      tint_array<int, 10> const tint_symbol_34 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      tint_array<int, 10> const tint_symbol_34 = tint_array<int, 10>{};
       QuicksortObject const tint_symbol_35 = {.numbers=tint_symbol_34};
       *(tint_symbol_83) = tint_symbol_35;
       *(tint_symbol_83) = x_1104;
@@ -818,13 +818,13 @@
   uv = x_717;
   i_2 = 0;
   QuicksortObject const x_721 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_36 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_36 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_37 = {.numbers=tint_symbol_36};
   *(tint_symbol_84) = tint_symbol_37;
   *(tint_symbol_84) = x_721;
   if (true) {
     QuicksortObject const x_722 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_38 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_38 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_39 = {.numbers=tint_symbol_38};
     *(tint_symbol_84) = tint_symbol_39;
     *(tint_symbol_84) = x_722;
@@ -838,13 +838,13 @@
     color = x_725;
     float2 const x_432 = float2(x_431[1], x_431[1]);
     QuicksortObject const x_726 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_40 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_40 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_41 = {.numbers=tint_symbol_40};
     *(tint_symbol_84) = tint_symbol_41;
     *(tint_symbol_84) = x_726;
   }
   QuicksortObject const x_756 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_42 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_42 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_43 = {.numbers=tint_symbol_42};
   *(tint_symbol_84) = tint_symbol_43;
   *(tint_symbol_84) = x_756;
@@ -854,7 +854,7 @@
   i_2 = x_757;
   quicksort_(tint_symbol_84);
   QuicksortObject const x_758 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_44 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_44 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_45 = {.numbers=tint_symbol_44};
   *(tint_symbol_84) = tint_symbol_45;
   *(tint_symbol_84) = x_758;
@@ -869,7 +869,7 @@
   float2 const x_185 = float2(x_184[0], x_184[1]);
   float3 const x_448 = float3(x_185[1], x_446[1], x_446[1]);
   QuicksortObject const x_761 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_46 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_46 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_47 = {.numbers=tint_symbol_46};
   *(tint_symbol_84) = tint_symbol_47;
   *(tint_symbol_84) = x_761;
@@ -878,7 +878,7 @@
   uv = x_762;
   float2 const x_191 = (*(tint_symbol_86)).resolution;
   QuicksortObject const x_763 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_48 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_48 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_49 = {.numbers=tint_symbol_48};
   *(tint_symbol_84) = tint_symbol_49;
   *(tint_symbol_84) = x_763;
@@ -888,7 +888,7 @@
   color = x_764;
   float2 const x_192 = (x_185 / x_191);
   QuicksortObject const x_765 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_50 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_50 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_51 = {.numbers=tint_symbol_50};
   *(tint_symbol_84) = tint_symbol_51;
   *(tint_symbol_84) = x_765;
@@ -906,7 +906,7 @@
   color = x_768;
   float3 const x_451 = float3(x_185[0], x_185[1], x_446[1]);
   QuicksortObject const x_769 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_52 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_52 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_53 = {.numbers=tint_symbol_52};
   *(tint_symbol_84) = tint_symbol_53;
   *(tint_symbol_84) = x_769;
@@ -915,7 +915,7 @@
   (*(tint_symbol_84)).numbers[0u] = x_770;
   int const x_201 = (*(tint_symbol_84)).numbers[0u];
   QuicksortObject const x_771 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_54 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_54 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_55 = {.numbers=tint_symbol_54};
   *(tint_symbol_84) = tint_symbol_55;
   *(tint_symbol_84) = x_771;
@@ -931,7 +931,7 @@
   i_2 = 0;
   i_2 = x_774;
   QuicksortObject const x_775 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_56 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_56 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_57 = {.numbers=tint_symbol_56};
   *(tint_symbol_84) = tint_symbol_57;
   *(tint_symbol_84) = x_775;
@@ -950,7 +950,7 @@
   uv[0] = 0.0f;
   uv[0] = x_778;
   QuicksortObject const x_779 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_58 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_58 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_59 = {.numbers=tint_symbol_58};
   *(tint_symbol_84) = tint_symbol_59;
   *(tint_symbol_84) = x_779;
@@ -967,7 +967,7 @@
     uv[0] = x_782;
     int const x_216 = (*(tint_symbol_84)).numbers[1];
     QuicksortObject const x_783 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_60 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_60 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_61 = {.numbers=tint_symbol_60};
     *(tint_symbol_84) = tint_symbol_61;
     *(tint_symbol_84) = x_783;
@@ -976,7 +976,7 @@
     uv = float2(0.0f);
     uv = x_784;
     QuicksortObject const x_785 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_62 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_62 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_63 = {.numbers=tint_symbol_62};
     *(tint_symbol_84) = tint_symbol_63;
     *(tint_symbol_84) = x_785;
@@ -1096,7 +1096,7 @@
     color[0] = 0.0f;
     color[0] = x_816;
     QuicksortObject const x_817 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_64 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_64 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_65 = {.numbers=tint_symbol_64};
     *(tint_symbol_84) = tint_symbol_65;
     *(tint_symbol_84) = x_817;
@@ -1207,7 +1207,7 @@
     uv[0] = x_844;
     float3 const x_482 = float3(x_455[0], x_475[1], x_455[1]);
     QuicksortObject const x_845 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_66 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_66 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_67 = {.numbers=tint_symbol_66};
     *(tint_symbol_84) = tint_symbol_67;
     *(tint_symbol_84) = x_845;
@@ -1280,7 +1280,7 @@
     (*(tint_symbol_84)).numbers[6u] = x_863;
     float2 const x_490 = float2(x_480[2], x_480[2]);
     QuicksortObject const x_864 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_68 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_68 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_69 = {.numbers=tint_symbol_68};
     *(tint_symbol_84) = tint_symbol_69;
     *(tint_symbol_84) = x_864;
@@ -1299,7 +1299,7 @@
   color[0] = x_867;
   float const x_287 = uv[1];
   QuicksortObject const x_868 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_70 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_70 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_71 = {.numbers=tint_symbol_70};
   *(tint_symbol_84) = tint_symbol_71;
   *(tint_symbol_84) = x_868;
@@ -1461,7 +1461,7 @@
     uv[0] = 0.0f;
     uv[0] = x_910;
     QuicksortObject const x_911 = *(tint_symbol_84);
-    tint_array<int, 10> const tint_symbol_72 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    tint_array<int, 10> const tint_symbol_72 = tint_array<int, 10>{};
     QuicksortObject const tint_symbol_73 = {.numbers=tint_symbol_72};
     *(tint_symbol_84) = tint_symbol_73;
     *(tint_symbol_84) = x_911;
@@ -1515,12 +1515,12 @@
   uv[0] = 0.0f;
   uv[0] = x_923;
   QuicksortObject const x_924 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_74 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_74 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_75 = {.numbers=tint_symbol_74};
   *(tint_symbol_84) = tint_symbol_75;
   *(tint_symbol_84) = x_924;
   QuicksortObject const x_925 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_76 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_76 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_77 = {.numbers=tint_symbol_76};
   *(tint_symbol_84) = tint_symbol_77;
   *(tint_symbol_84) = x_925;
@@ -1541,7 +1541,7 @@
   uv[0] = x_929;
   *(tint_symbol_87) = x_330;
   QuicksortObject const x_930 = *(tint_symbol_84);
-  tint_array<int, 10> const tint_symbol_78 = tint_array<int, 10>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  tint_array<int, 10> const tint_symbol_78 = tint_array<int, 10>{};
   QuicksortObject const tint_symbol_79 = {.numbers=tint_symbol_78};
   *(tint_symbol_84) = tint_symbol_79;
   *(tint_symbol_84) = x_930;
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 132ba50..cff063b 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](tint_symbol_1, tint_symbol_2);
+  int init[2][3] = int[2][3](int[3](1, 2, 3), int[3](4, 5, 6));
 }
 
 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 88d2dd3..03352d4 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] = {tint_symbol, tint_symbol_1};
+  int init[2][3] = {{1, 2, 3}, {4, 5, 6}};
   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 7ad097e..9b02242 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_symbol_1, tint_symbol_2};
+  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}};
   return;
 }