Add struct index accessor tests

This CL adds end-to-end tests for struct member accessors.

Change-Id: I73546beccd3569a6e80e7054df0e1de32e7e0f95
Bug: tint:1718
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162241
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index f7c4c0c..0b4aa8c 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -498,8 +498,11 @@
     void EmitAccess(StringStream& out, const core::ir::Access* a) {
         EmitValue(out, a->Object());
 
-        auto* current_type = a->Result()->Type();
+        auto* current_type = a->Object()->Type();
         for (auto* index : a->Indices()) {
+            TINT_ASSERT(current_type);
+
+            current_type = current_type->UnwrapPtr();
             Switch(
                 current_type,  //
                 [&](const core::type::Struct* s) {
@@ -512,6 +515,7 @@
                     out << "[";
                     EmitValue(out, index);
                     out << "]";
+                    current_type = current_type->Element(0);
                 });
         }
     }
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl b/test/tint/expressions/index/let/array_nested_struct.wgsl
new file mode 100644
index 0000000..bc44dfb
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: array<u32, 4>,
+}
+
+fn f() -> u32 {
+  let a :array<S, 2> = array<S, 2>();
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b943cff
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  const S a[2] = (S[2])0;
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b943cff
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  const S a[2] = (S[2])0;
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.glsl b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..b856b2b
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a[2] = S[2](S(0, uint[4](0u, 0u, 0u, 0u)), S(0, uint[4](0u, 0u, 0u, 0u)));
+  return a[1].n[1];
+}
+
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.ir.msl b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.ir.msl
new file mode 100644
index 0000000..ae3e8ca
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.ir.msl
@@ -0,0 +1,23 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  tint_array<S, 2> const a = tint_array<S, 2>{};
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.msl b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.msl
new file mode 100644
index 0000000..ca55d75
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  tint_array<S, 2> const a = tint_array<S, 2>{};
+  return a[1].n[1];
+}
+
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.spvasm b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..291c153
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 20
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpDecorate %_arr_uint_uint_4 ArrayStride 4
+               OpDecorate %_arr_S_uint_2 ArrayStride 20
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %uint_4 = OpConstant %uint 4
+%_arr_uint_uint_4 = OpTypeArray %uint %uint_4
+          %S = OpTypeStruct %int %_arr_uint_uint_4
+     %uint_2 = OpConstant %uint 2
+%_arr_S_uint_2 = OpTypeArray %S %uint_2
+         %15 = OpConstantNull %_arr_S_uint_2
+      %int_1 = OpConstant %int 1
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+         %17 = OpCompositeExtract %S %15 1
+         %18 = OpCompositeExtract %_arr_uint_uint_4 %17 1
+         %19 = OpCompositeExtract %uint %18 1
+               OpReturnValue %19
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.wgsl b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..03f9966
--- /dev/null
+++ b/test/tint/expressions/index/let/array_nested_struct.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : array<u32, 4>,
+}
+
+fn f() -> u32 {
+  let a : array<S, 2> = array<S, 2>();
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/let/let/param/array.wgsl.expected.ir.msl b/test/tint/expressions/index/let/let/param/array.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/let/let/param/array.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/let/param/array.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/let/let/param/matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/let/let/param/matrix.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/let/let/param/matrix.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/let/param/matrix.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/let/let/param/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/let/let/param/vector.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/let/let/param/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/let/param/vector.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/let/param/array.wgsl.expected.ir.msl b/test/tint/expressions/index/let/param/array.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/let/param/array.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/param/array.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/let/param/matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/let/param/matrix.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/let/param/matrix.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/param/matrix.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/let/param/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/let/param/vector.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/let/param/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/param/vector.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/let/struct.wgsl b/test/tint/expressions/index/let/struct.wgsl
new file mode 100644
index 0000000..cc65835
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: u32,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n;
+}
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a3565e6
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n;
+}
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a3565e6
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n;
+}
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.glsl b/test/tint/expressions/index/let/struct.wgsl.expected.glsl
new file mode 100644
index 0000000..934dd7d
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S a = S(0, 0u);
+  return a.n;
+}
+
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.ir.msl b/test/tint/expressions/index/let/struct.wgsl.expected.ir.msl
new file mode 100644
index 0000000..aa981c1
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.ir.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+using namespace metal;
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n;
+}
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.msl b/test/tint/expressions/index/let/struct.wgsl.expected.msl
new file mode 100644
index 0000000..a235160
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n;
+}
+
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.spvasm b/test/tint/expressions/index/let/struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..a275bc9
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.spvasm
@@ -0,0 +1,32 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 13
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+          %S = OpTypeStruct %int %uint
+         %11 = OpConstantNull %S
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+         %12 = OpCompositeExtract %uint %11 1
+               OpReturnValue %12
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/struct.wgsl.expected.wgsl b/test/tint/expressions/index/let/struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..4522d77
--- /dev/null
+++ b/test/tint/expressions/index/let/struct.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : u32,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n;
+}
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl b/test/tint/expressions/index/let/struct_nested_array.wgsl
new file mode 100644
index 0000000..21c1290
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: array<u32, 4>,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cc19f64
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cc19f64
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.glsl b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.glsl
new file mode 100644
index 0000000..f5cf752
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a = S(0, uint[4](0u, 0u, 0u, 0u));
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.ir.msl b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.ir.msl
new file mode 100644
index 0000000..07573ca
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.ir.msl
@@ -0,0 +1,23 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.msl b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.msl
new file mode 100644
index 0000000..db9976f
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.spvasm b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..29a8159
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpDecorate %_arr_uint_uint_4 ArrayStride 4
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %uint_4 = OpConstant %uint 4
+%_arr_uint_uint_4 = OpTypeArray %uint %uint_4
+          %S = OpTypeStruct %int %_arr_uint_uint_4
+         %13 = OpConstantNull %S
+      %int_2 = OpConstant %int 2
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+         %14 = OpCompositeExtract %_arr_uint_uint_4 %13 1
+         %16 = OpCompositeExtract %uint %14 2
+               OpReturnValue %16
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.wgsl b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..4ef43a5
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_array.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : array<u32, 4>,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl
new file mode 100644
index 0000000..b091f76
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl
@@ -0,0 +1,13 @@
+struct T {
+  k: array<u32, 2>,
+}
+
+struct S {
+  m: i32,
+  n: array<T, 4>,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e772346
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  uint k[2];
+};
+struct S {
+  int m;
+  T n[4];
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e772346
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  uint k[2];
+};
+struct S {
+  int m;
+  T n[4];
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.glsl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.glsl
new file mode 100644
index 0000000..eca1692
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct T {
+  uint k[2];
+};
+
+struct S {
+  int m;
+  T n[4];
+};
+
+uint f() {
+  S a = S(0, T[4](T(uint[2](0u, 0u)), T(uint[2](0u, 0u)), T(uint[2](0u, 0u)), T(uint[2](0u, 0u))));
+  return a.n[2].k[1];
+}
+
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.ir.msl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.ir.msl
new file mode 100644
index 0000000..a98c652
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.ir.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct T {
+  tint_array<uint, 2> k;
+};
+struct S {
+  int m;
+  tint_array<T, 4> n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.msl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.msl
new file mode 100644
index 0000000..db07026
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+struct T {
+  tint_array<uint, 2> k;
+};
+
+struct S {
+  int m;
+  tint_array<T, 4> n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n[2].k[1];
+}
+
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.spvasm b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.spvasm
new file mode 100644
index 0000000..d81d5df
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %T "T"
+               OpMemberName %T 0 "k"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %T 0 Offset 0
+               OpDecorate %_arr_uint_uint_2 ArrayStride 4
+               OpDecorate %_arr_T_uint_4 ArrayStride 8
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %uint_2 = OpConstant %uint 2
+%_arr_uint_uint_2 = OpTypeArray %uint %uint_2
+          %T = OpTypeStruct %_arr_uint_uint_2
+     %uint_4 = OpConstant %uint 4
+%_arr_T_uint_4 = OpTypeArray %T %uint_4
+          %S = OpTypeStruct %int %_arr_T_uint_4
+         %16 = OpConstantNull %S
+      %int_2 = OpConstant %int 2
+      %int_1 = OpConstant %int 1
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+         %17 = OpCompositeExtract %_arr_T_uint_4 %16 1
+         %19 = OpCompositeExtract %T %17 2
+         %20 = OpCompositeExtract %_arr_uint_uint_2 %19 0
+         %22 = OpCompositeExtract %uint %20 1
+               OpReturnValue %22
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.wgsl b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.wgsl
new file mode 100644
index 0000000..3c397eb
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_multiple.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+struct T {
+  k : array<u32, 2>,
+}
+
+struct S {
+  m : i32,
+  n : array<T, 4>,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl b/test/tint/expressions/index/let/struct_nested_struct.wgsl
new file mode 100644
index 0000000..e04b623
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl
@@ -0,0 +1,14 @@
+struct T {
+  o: f32,
+  p: u32
+}
+
+struct S {
+  m: i32,
+  n: T,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..aec3d39
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  float o;
+  uint p;
+};
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..aec3d39
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  float o;
+  uint p;
+};
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.glsl b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..4f4b62b
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct T {
+  float o;
+  uint p;
+};
+
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S a = S(0, T(0.0f, 0u));
+  return a.n.p;
+}
+
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.ir.msl b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.ir.msl
new file mode 100644
index 0000000..1afdde3
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.ir.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+using namespace metal;
+struct T {
+  float o;
+  uint p;
+};
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.msl b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.msl
new file mode 100644
index 0000000..339343e
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.msl
@@ -0,0 +1,18 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct T {
+  float o;
+  uint p;
+};
+
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n.p;
+}
+
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.spvasm b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..2296b1d
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %T "T"
+               OpMemberName %T 0 "o"
+               OpMemberName %T 1 "p"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %T 0 Offset 0
+               OpMemberDecorate %T 1 Offset 4
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+          %T = OpTypeStruct %float %uint
+          %S = OpTypeStruct %int %T
+         %13 = OpConstantNull %S
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+         %14 = OpCompositeExtract %T %13 1
+         %15 = OpCompositeExtract %uint %14 1
+               OpReturnValue %15
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.wgsl b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..e02efac
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_nested_struct.wgsl.expected.wgsl
@@ -0,0 +1,14 @@
+struct T {
+  o : f32,
+  p : u32,
+}
+
+struct S {
+  m : i32,
+  n : T,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl b/test/tint/expressions/index/let/struct_with_matrix.wgsl
new file mode 100644
index 0000000..fda93f1
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: mat4x4f,
+}
+
+fn f() -> f32 {
+  let a = S();
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3b07e38
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S a = (S)0;
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3b07e38
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S a = (S)0;
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.glsl b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.glsl
new file mode 100644
index 0000000..ef7edb8
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  mat4 n;
+};
+
+float f() {
+  S a = S(0, mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f)));
+  return a.n[2][1];
+}
+
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.ir.msl
new file mode 100644
index 0000000..1975889
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.ir.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+using namespace metal;
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S const a = S{};
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.msl b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.msl
new file mode 100644
index 0000000..66f21aa
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S const a = S{};
+  return a.n[2][1];
+}
+
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.spvasm b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.spvasm
new file mode 100644
index 0000000..5d9347f
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+          %5 = OpTypeFunction %float
+        %int = OpTypeInt 32 1
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float
+         %13 = OpConstantNull %S
+      %int_2 = OpConstant %int 2
+      %int_1 = OpConstant %int 1
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %float None %5
+          %8 = OpLabel
+         %14 = OpCompositeExtract %mat4v4float %13 1
+         %16 = OpCompositeExtract %v4float %14 2
+         %18 = OpCompositeExtract %float %16 1
+               OpReturnValue %18
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.wgsl b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.wgsl
new file mode 100644
index 0000000..091048a
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_matrix.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : mat4x4f,
+}
+
+fn f() -> f32 {
+  let a = S();
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl b/test/tint/expressions/index/let/struct_with_vector.wgsl
new file mode 100644
index 0000000..9d448d8
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: vec3u,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..86d74ba
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..86d74ba
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  const S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.glsl b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.glsl
new file mode 100644
index 0000000..bd84f8b
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uvec3 n;
+};
+
+uint f() {
+  S a = S(0, uvec3(0u));
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.ir.msl b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.ir.msl
new file mode 100644
index 0000000..cf345ee
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.ir.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+using namespace metal;
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.msl b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.msl
new file mode 100644
index 0000000..f2f3b80
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  S const a = S{};
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.spvasm b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.spvasm
new file mode 100644
index 0000000..182479c
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %v3uint = OpTypeVector %uint 3
+          %S = OpTypeStruct %int %v3uint
+         %12 = OpConstantNull %S
+      %int_2 = OpConstant %int 2
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+         %13 = OpCompositeExtract %v3uint %12 1
+         %15 = OpCompositeExtract %uint %13 2
+               OpReturnValue %15
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.wgsl b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.wgsl
new file mode 100644
index 0000000..a113598
--- /dev/null
+++ b/test/tint/expressions/index/let/struct_with_vector.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : vec3u,
+}
+
+fn f() -> u32 {
+  let a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl b/test/tint/expressions/index/let/var/literal/array.wgsl
index c1781aa..cdd1c8f 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl
@@ -1,5 +1,5 @@
 fn f() -> i32 {
-  var a = array<i32, 8>(1, 2, 3, 4, 5, 6, 7, 8);
-  let i = 1;
+  let a = array<i32, 8>(1, 2, 3, 4, 5, 6, 7, 8);
+  var i = 1;
   return a[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.dxc.hlsl
index 4c1df88..4c04477 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.dxc.hlsl
@@ -4,7 +4,7 @@
 }
 
 int f() {
-  int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
-  const int i = 1;
+  const int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+  int i = 1;
   return a[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.fxc.hlsl
index 4c1df88..4c04477 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.fxc.hlsl
@@ -4,7 +4,7 @@
 }
 
 int f() {
-  int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
-  const int i = 1;
+  const int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+  int i = 1;
   return a[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.ir.msl b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.ir.msl
index 3942da9..c9ba348 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.ir.msl
@@ -14,7 +14,7 @@
 
 
 int f() {
-  tint_array<int, 8> a = tint_array<int, 8>{1, 2, 3, 4, 5, 6, 7, 8};
-  int const i = 1;
+  tint_array<int, 8> const a = tint_array<int, 8>{1, 2, 3, 4, 5, 6, 7, 8};
+  int i = 1;
   return a[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.msl b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.msl
index a435dac..462ae1a 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.msl
@@ -15,8 +15,8 @@
 };
 
 int f() {
-  tint_array<int, 8> a = tint_array<int, 8>{1, 2, 3, 4, 5, 6, 7, 8};
-  int const i = 1;
+  tint_array<int, 8> const a = tint_array<int, 8>{1, 2, 3, 4, 5, 6, 7, 8};
+  int i = 1;
   return a[i];
 }
 
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.spvasm b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.spvasm
index 565f53e..b156bd3 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 27
+; Bound: 30
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,7 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
-               OpName %a "a"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpDecorate %_arr_int_uint_8 ArrayStride 4
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
@@ -27,18 +28,22 @@
       %int_7 = OpConstant %int 7
       %int_8 = OpConstant %int 8
          %20 = OpConstantComposite %_arr_int_uint_8 %int_1 %int_2 %int_3 %int_4 %int_5 %int_6 %int_7 %int_8
-%_ptr_Function__arr_int_uint_8 = OpTypePointer Function %_arr_int_uint_8
-         %23 = OpConstantNull %_arr_int_uint_8
 %_ptr_Function_int = OpTypePointer Function %int
+         %23 = OpConstantNull %int
+%_ptr_Function__arr_int_uint_8 = OpTypePointer Function %_arr_int_uint_8
+         %26 = OpConstantNull %_arr_int_uint_8
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %int None %5
           %8 = OpLabel
-          %a = OpVariable %_ptr_Function__arr_int_uint_8 Function %23
-               OpStore %a %20
-         %25 = OpAccessChain %_ptr_Function_int %a %int_1
-         %26 = OpLoad %int %25
-               OpReturnValue %26
+          %i = OpVariable %_ptr_Function_int Function %23
+%var_for_index = OpVariable %_ptr_Function__arr_int_uint_8 Function %26
+               OpStore %i %int_1
+               OpStore %var_for_index %20
+         %27 = OpLoad %int %i
+         %28 = OpAccessChain %_ptr_Function_int %var_for_index %27
+         %29 = OpLoad %int %28
+               OpReturnValue %29
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.wgsl b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.wgsl
index c1781aa..cdd1c8f 100644
--- a/test/tint/expressions/index/let/var/literal/array.wgsl.expected.wgsl
+++ b/test/tint/expressions/index/let/var/literal/array.wgsl.expected.wgsl
@@ -1,5 +1,5 @@
 fn f() -> i32 {
-  var a = array<i32, 8>(1, 2, 3, 4, 5, 6, 7, 8);
-  let i = 1;
+  let a = array<i32, 8>(1, 2, 3, 4, 5, 6, 7, 8);
+  var i = 1;
   return a[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl b/test/tint/expressions/index/let/var/literal/matrix.wgsl
index a20885c..5599198 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl
@@ -1,5 +1,5 @@
 fn f() -> vec3<f32> {
-  var m = mat3x3<f32>(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
-  let i = 1;
+  let m = mat3x3<f32>(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+  var i = 1;
   return m[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.dxc.hlsl
index fac0dab..8428d9f 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.dxc.hlsl
@@ -4,7 +4,7 @@
 }
 
 float3 f() {
-  float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  const int i = 1;
+  const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  int i = 1;
   return m[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.fxc.hlsl
index fac0dab..8428d9f 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.fxc.hlsl
@@ -4,7 +4,7 @@
 }
 
 float3 f() {
-  float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  const int i = 1;
+  const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  int i = 1;
   return m[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.ir.msl
index 11f6252..11877c2 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.ir.msl
@@ -2,7 +2,7 @@
 using namespace metal;
 
 float3 f() {
-  float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  int const i = 1;
+  float3x3 const m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  int i = 1;
   return m[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.msl b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.msl
index 0536bc1..298cde8 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.msl
@@ -2,8 +2,8 @@
 
 using namespace metal;
 float3 f() {
-  float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
-  int const i = 1;
+  float3x3 const m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  int i = 1;
   return m[i];
 }
 
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.spvasm b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.spvasm
index be19a25..1372694 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 32
+; Bound: 36
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,7 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
-               OpName %m "m"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
       %float = OpTypeFloat 32
@@ -29,10 +30,12 @@
     %float_9 = OpConstant %float 9
          %22 = OpConstantComposite %v3float %float_7 %float_8 %float_9
          %23 = OpConstantComposite %mat3v3float %14 %18 %22
-%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
-         %26 = OpConstantNull %mat3v3float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
+%_ptr_Function_int = OpTypePointer Function %int
+         %28 = OpConstantNull %int
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+         %31 = OpConstantNull %mat3v3float
 %_ptr_Function_v3float = OpTypePointer Function %v3float
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
@@ -40,9 +43,12 @@
                OpFunctionEnd
           %f = OpFunction %v3float None %5
           %9 = OpLabel
-          %m = OpVariable %_ptr_Function_mat3v3float Function %26
-               OpStore %m %23
-         %30 = OpAccessChain %_ptr_Function_v3float %m %int_1
-         %31 = OpLoad %v3float %30
-               OpReturnValue %31
+          %i = OpVariable %_ptr_Function_int Function %28
+%var_for_index = OpVariable %_ptr_Function_mat3v3float Function %31
+               OpStore %i %int_1
+               OpStore %var_for_index %23
+         %32 = OpLoad %int %i
+         %34 = OpAccessChain %_ptr_Function_v3float %var_for_index %32
+         %35 = OpLoad %v3float %34
+               OpReturnValue %35
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.wgsl b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.wgsl
index a20885c..5599198 100644
--- a/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.wgsl
+++ b/test/tint/expressions/index/let/var/literal/matrix.wgsl.expected.wgsl
@@ -1,5 +1,5 @@
 fn f() -> vec3<f32> {
-  var m = mat3x3<f32>(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
-  let i = 1;
+  let m = mat3x3<f32>(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+  var i = 1;
   return m[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl b/test/tint/expressions/index/let/var/literal/vector.wgsl
index 74962a8..eb78b29 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl
@@ -1,5 +1,5 @@
 fn f() -> f32 {
-  var v = vec3<f32>(1.0, 2.0, 3.0);
-  let i = 1;
+  let v = vec3<f32>(1.0, 2.0, 3.0);
+  var i = 1;
   return v[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.dxc.hlsl
index 90a7801..19313aa 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.dxc.hlsl
@@ -4,7 +4,7 @@
 }
 
 float f() {
-  float3 v = float3(1.0f, 2.0f, 3.0f);
-  const int i = 1;
+  const float3 v = float3(1.0f, 2.0f, 3.0f);
+  int i = 1;
   return v[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.fxc.hlsl
index 90a7801..19313aa 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.fxc.hlsl
@@ -4,7 +4,7 @@
 }
 
 float f() {
-  float3 v = float3(1.0f, 2.0f, 3.0f);
-  const int i = 1;
+  const float3 v = float3(1.0f, 2.0f, 3.0f);
+  int i = 1;
   return v[i];
 }
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.ir.msl
index 78e3fb3..24357aa 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.ir.msl
@@ -1,9 +1,8 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:265 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+float f() {
+  float3 const v = float3(1.0f, 2.0f, 3.0f);
+  int i = 1;
+  return v[i];
+}
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.msl b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.msl
index 07ca4fb..3ff740d 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.msl
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.msl
@@ -2,8 +2,8 @@
 
 using namespace metal;
 float f() {
-  float3 v = float3(1.0f, 2.0f, 3.0f);
-  int const i = 1;
+  float3 const v = float3(1.0f, 2.0f, 3.0f);
+  int i = 1;
   return v[i];
 }
 
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.spvasm b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.spvasm
index fe71fc3..f624d54 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.spvasm
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 21
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,7 +9,7 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %unused_entry_point "unused_entry_point"
                OpName %f "f"
-               OpName %v "v"
+               OpName %i "i"
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
       %float = OpTypeFloat 32
@@ -19,20 +19,19 @@
     %float_2 = OpConstant %float 2
     %float_3 = OpConstant %float 3
          %13 = OpConstantComposite %v3float %float_1 %float_2 %float_3
-%_ptr_Function_v3float = OpTypePointer Function %v3float
-         %16 = OpConstantNull %v3float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
-%_ptr_Function_float = OpTypePointer Function %float
+%_ptr_Function_int = OpTypePointer Function %int
+         %18 = OpConstantNull %int
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
           %f = OpFunction %float None %5
           %8 = OpLabel
-          %v = OpVariable %_ptr_Function_v3float Function %16
-               OpStore %v %13
-         %20 = OpAccessChain %_ptr_Function_float %v %int_1
-         %21 = OpLoad %float %20
-               OpReturnValue %21
+          %i = OpVariable %_ptr_Function_int Function %18
+               OpStore %i %int_1
+         %19 = OpLoad %int %i
+         %20 = OpVectorExtractDynamic %float %13 %19
+               OpReturnValue %20
                OpFunctionEnd
diff --git a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.wgsl b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.wgsl
index 74962a8..eb78b29 100644
--- a/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.wgsl
+++ b/test/tint/expressions/index/let/var/literal/vector.wgsl.expected.wgsl
@@ -1,5 +1,5 @@
 fn f() -> f32 {
-  var v = vec3<f32>(1.0, 2.0, 3.0);
-  let i = 1;
+  let v = vec3<f32>(1.0, 2.0, 3.0);
+  var i = 1;
   return v[i];
 }
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl b/test/tint/expressions/index/var/array_nested_struct.wgsl
new file mode 100644
index 0000000..df20ff3
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: array<u32, 4>,
+}
+
+fn f() -> u32 {
+  var a :array<S, 2> = array<S, 2>();
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e7231ea
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a[2] = (S[2])0;
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e7231ea
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a[2] = (S[2])0;
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.glsl b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..b856b2b
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a[2] = S[2](S(0, uint[4](0u, 0u, 0u, 0u)), S(0, uint[4](0u, 0u, 0u, 0u)));
+  return a[1].n[1];
+}
+
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.ir.msl b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.ir.msl
new file mode 100644
index 0000000..20342f4
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.ir.msl
@@ -0,0 +1,23 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  tint_array<S, 2> a = tint_array<S, 2>{};
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.msl b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.msl
new file mode 100644
index 0000000..fb30518
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  tint_array<S, 2> a = tint_array<S, 2>{};
+  return a[1].n[1];
+}
+
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.spvasm b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..3b16061
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpDecorate %_arr_uint_uint_4 ArrayStride 4
+               OpDecorate %_arr_S_uint_2 ArrayStride 20
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %uint_4 = OpConstant %uint 4
+%_arr_uint_uint_4 = OpTypeArray %uint %uint_4
+          %S = OpTypeStruct %int %_arr_uint_uint_4
+     %uint_2 = OpConstant %uint 2
+%_arr_S_uint_2 = OpTypeArray %S %uint_2
+         %15 = OpConstantNull %_arr_S_uint_2
+%_ptr_Function__arr_S_uint_2 = OpTypePointer Function %_arr_S_uint_2
+      %int_1 = OpConstant %int 1
+     %uint_1 = OpConstant %uint 1
+%_ptr_Function_uint = OpTypePointer Function %uint
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function__arr_S_uint_2 Function %15
+               OpStore %a %15
+         %21 = OpAccessChain %_ptr_Function_uint %a %int_1 %uint_1 %int_1
+         %22 = OpLoad %uint %21
+               OpReturnValue %22
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.wgsl b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..35313ef
--- /dev/null
+++ b/test/tint/expressions/index/var/array_nested_struct.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : array<u32, 4>,
+}
+
+fn f() -> u32 {
+  var a : array<S, 2> = array<S, 2>();
+  return a[1].n[1];
+}
diff --git a/test/tint/expressions/index/var/let/literal/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/var/let/literal/vector.wgsl.expected.ir.msl
index 78e3fb3..f03c5aa 100644
--- a/test/tint/expressions/index/var/let/literal/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/let/literal/vector.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:265 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:264 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/let/param/array.wgsl.expected.ir.msl b/test/tint/expressions/index/var/let/param/array.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/var/let/param/array.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/let/param/array.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/let/param/matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/var/let/param/matrix.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/var/let/param/matrix.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/let/param/matrix.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/let/param/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/var/let/param/vector.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/var/let/param/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/let/param/vector.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/literal/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/var/literal/vector.wgsl.expected.ir.msl
index 78e3fb3..f03c5aa 100644
--- a/test/tint/expressions/index/var/literal/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/literal/vector.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:265 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:264 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/param/array.wgsl.expected.ir.msl b/test/tint/expressions/index/var/param/array.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/var/param/array.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/param/array.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/param/matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/var/param/matrix.wgsl.expected.ir.msl
index c72e77b..cee46b6 100644
--- a/test/tint/expressions/index/var/param/matrix.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/param/matrix.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:305 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:304 internal compiler error: Switch() matched no cases. Type: tint::core::ir::FunctionParam
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/param/vector.wgsl.expected.ir.msl b/test/tint/expressions/index/var/param/vector.wgsl.expected.ir.msl
index 78e3fb3..f03c5aa 100644
--- a/test/tint/expressions/index/var/param/vector.wgsl.expected.ir.msl
+++ b/test/tint/expressions/index/var/param/vector.wgsl.expected.ir.msl
@@ -1,6 +1,6 @@
 SKIP: FAILED
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:265 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:264 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
diff --git a/test/tint/expressions/index/var/struct.wgsl b/test/tint/expressions/index/var/struct.wgsl
new file mode 100644
index 0000000..2f231ab
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: u32,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n;
+}
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..17aaf4b
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n;
+}
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..17aaf4b
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n;
+}
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.glsl b/test/tint/expressions/index/var/struct.wgsl.expected.glsl
new file mode 100644
index 0000000..934dd7d
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S a = S(0, 0u);
+  return a.n;
+}
+
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.ir.msl b/test/tint/expressions/index/var/struct.wgsl.expected.ir.msl
new file mode 100644
index 0000000..b317612
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.ir.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+using namespace metal;
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n;
+}
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.msl b/test/tint/expressions/index/var/struct.wgsl.expected.msl
new file mode 100644
index 0000000..456ae3c
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+  uint n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n;
+}
+
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.spvasm b/test/tint/expressions/index/var/struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..23c59df
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+          %S = OpTypeStruct %int %uint
+         %11 = OpConstantNull %S
+%_ptr_Function_S = OpTypePointer Function %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Function_uint = OpTypePointer Function %uint
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function_S Function %11
+               OpStore %a %11
+         %16 = OpAccessChain %_ptr_Function_uint %a %uint_1
+         %17 = OpLoad %uint %16
+               OpReturnValue %17
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/struct.wgsl.expected.wgsl b/test/tint/expressions/index/var/struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..ec088cb
--- /dev/null
+++ b/test/tint/expressions/index/var/struct.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : u32,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n;
+}
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl b/test/tint/expressions/index/var/struct_nested_array.wgsl
new file mode 100644
index 0000000..96a2743
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: array<u32, 4>,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f13545c
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f13545c
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.glsl b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.glsl
new file mode 100644
index 0000000..f5cf752
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uint n[4];
+};
+
+uint f() {
+  S a = S(0, uint[4](0u, 0u, 0u, 0u));
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.ir.msl b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.ir.msl
new file mode 100644
index 0000000..b9073ba
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.ir.msl
@@ -0,0 +1,23 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.msl b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.msl
new file mode 100644
index 0000000..5910131
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+struct S {
+  int m;
+  tint_array<uint, 4> n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.spvasm b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.spvasm
new file mode 100644
index 0000000..67d3ed2
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpDecorate %_arr_uint_uint_4 ArrayStride 4
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %uint_4 = OpConstant %uint 4
+%_arr_uint_uint_4 = OpTypeArray %uint %uint_4
+          %S = OpTypeStruct %int %_arr_uint_uint_4
+         %13 = OpConstantNull %S
+%_ptr_Function_S = OpTypePointer Function %S
+     %uint_1 = OpConstant %uint 1
+      %int_2 = OpConstant %int 2
+%_ptr_Function_uint = OpTypePointer Function %uint
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function_S Function %13
+               OpStore %a %13
+         %19 = OpAccessChain %_ptr_Function_uint %a %uint_1 %int_2
+         %20 = OpLoad %uint %19
+               OpReturnValue %20
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.wgsl b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.wgsl
new file mode 100644
index 0000000..5fbaa94
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_array.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : array<u32, 4>,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl
new file mode 100644
index 0000000..46befb5
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl
@@ -0,0 +1,13 @@
+struct T {
+  k: array<u32, 2>,
+}
+
+struct S {
+  m: i32,
+  n: array<T, 4>,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a5b59af
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  uint k[2];
+};
+struct S {
+  int m;
+  T n[4];
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a5b59af
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  uint k[2];
+};
+struct S {
+  int m;
+  T n[4];
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.glsl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.glsl
new file mode 100644
index 0000000..eca1692
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct T {
+  uint k[2];
+};
+
+struct S {
+  int m;
+  T n[4];
+};
+
+uint f() {
+  S a = S(0, T[4](T(uint[2](0u, 0u)), T(uint[2](0u, 0u)), T(uint[2](0u, 0u)), T(uint[2](0u, 0u))));
+  return a.n[2].k[1];
+}
+
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.ir.msl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.ir.msl
new file mode 100644
index 0000000..9794d96
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.ir.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct T {
+  tint_array<uint, 2> k;
+};
+struct S {
+  int m;
+  tint_array<T, 4> n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.msl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.msl
new file mode 100644
index 0000000..f332f74
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.msl
@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+struct T {
+  tint_array<uint, 2> k;
+};
+
+struct S {
+  int m;
+  tint_array<T, 4> n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n[2].k[1];
+}
+
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.spvasm b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.spvasm
new file mode 100644
index 0000000..14f8c56
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.spvasm
@@ -0,0 +1,52 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 26
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %T "T"
+               OpMemberName %T 0 "k"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %T 0 Offset 0
+               OpDecorate %_arr_uint_uint_2 ArrayStride 4
+               OpDecorate %_arr_T_uint_4 ArrayStride 8
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %uint_2 = OpConstant %uint 2
+%_arr_uint_uint_2 = OpTypeArray %uint %uint_2
+          %T = OpTypeStruct %_arr_uint_uint_2
+     %uint_4 = OpConstant %uint 4
+%_arr_T_uint_4 = OpTypeArray %T %uint_4
+          %S = OpTypeStruct %int %_arr_T_uint_4
+         %16 = OpConstantNull %S
+%_ptr_Function_S = OpTypePointer Function %S
+     %uint_1 = OpConstant %uint 1
+      %int_2 = OpConstant %int 2
+     %uint_0 = OpConstant %uint 0
+      %int_1 = OpConstant %int 1
+%_ptr_Function_uint = OpTypePointer Function %uint
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function_S Function %16
+               OpStore %a %16
+         %24 = OpAccessChain %_ptr_Function_uint %a %uint_1 %int_2 %uint_0 %int_1
+         %25 = OpLoad %uint %24
+               OpReturnValue %25
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.wgsl b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.wgsl
new file mode 100644
index 0000000..90656d5
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_multiple.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+struct T {
+  k : array<u32, 2>,
+}
+
+struct S {
+  m : i32,
+  n : array<T, 4>,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n[2].k[1];
+}
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl b/test/tint/expressions/index/var/struct_nested_struct.wgsl
new file mode 100644
index 0000000..ae218c1
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl
@@ -0,0 +1,14 @@
+struct T {
+  o: f32,
+  p: u32
+}
+
+struct S {
+  m: i32,
+  n: T,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..780a691
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  float o;
+  uint p;
+};
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..780a691
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct T {
+  float o;
+  uint p;
+};
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.glsl b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.glsl
new file mode 100644
index 0000000..4f4b62b
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct T {
+  float o;
+  uint p;
+};
+
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S a = S(0, T(0.0f, 0u));
+  return a.n.p;
+}
+
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.ir.msl b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.ir.msl
new file mode 100644
index 0000000..da45dfb
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.ir.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+using namespace metal;
+struct T {
+  float o;
+  uint p;
+};
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.msl b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.msl
new file mode 100644
index 0000000..eed59d0
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.msl
@@ -0,0 +1,18 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct T {
+  float o;
+  uint p;
+};
+
+struct S {
+  int m;
+  T n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n.p;
+}
+
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.spvasm b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..61ef10d
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 20
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %T "T"
+               OpMemberName %T 0 "o"
+               OpMemberName %T 1 "p"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %T 0 Offset 0
+               OpMemberDecorate %T 1 Offset 4
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+          %T = OpTypeStruct %float %uint
+          %S = OpTypeStruct %int %T
+         %13 = OpConstantNull %S
+%_ptr_Function_S = OpTypePointer Function %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Function_uint = OpTypePointer Function %uint
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function_S Function %13
+               OpStore %a %13
+         %18 = OpAccessChain %_ptr_Function_uint %a %uint_1 %uint_1
+         %19 = OpLoad %uint %18
+               OpReturnValue %19
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.wgsl b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..f44104c
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_nested_struct.wgsl.expected.wgsl
@@ -0,0 +1,14 @@
+struct T {
+  o : f32,
+  p : u32,
+}
+
+struct S {
+  m : i32,
+  n : T,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n.p;
+}
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl b/test/tint/expressions/index/var/struct_with_matrix.wgsl
new file mode 100644
index 0000000..713fb14
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: mat4x4f,
+}
+
+fn f() -> f32 {
+  var a = S();
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3b07e38
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S a = (S)0;
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3b07e38
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S a = (S)0;
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.glsl b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.glsl
new file mode 100644
index 0000000..ef7edb8
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  mat4 n;
+};
+
+float f() {
+  S a = S(0, mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f)));
+  return a.n[2][1];
+}
+
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.ir.msl b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.ir.msl
new file mode 100644
index 0000000..f03c5aa
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.ir.msl
@@ -0,0 +1,9 @@
+SKIP: FAILED
+
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:264 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
+********************************************************************
+*  The tint shader compiler has encountered an unexpected error.   *
+*                                                                  *
+*  Please help us fix this issue by submitting a bug report at     *
+*  crbug.com/tint with the source program that triggered the bug.  *
+********************************************************************
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.msl b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.msl
new file mode 100644
index 0000000..47a1ae9
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+  float4x4 n;
+};
+
+float f() {
+  S a = S{};
+  return a.n[2][1];
+}
+
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.spvasm b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.spvasm
new file mode 100644
index 0000000..72f012d
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 23
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+          %5 = OpTypeFunction %float
+        %int = OpTypeInt 32 1
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float
+         %13 = OpConstantNull %S
+%_ptr_Function_S = OpTypePointer Function %S
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+      %int_2 = OpConstant %int 2
+      %int_1 = OpConstant %int 1
+%_ptr_Function_float = OpTypePointer Function %float
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %float None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function_S Function %13
+               OpStore %a %13
+         %21 = OpAccessChain %_ptr_Function_float %a %uint_1 %int_2 %int_1
+         %22 = OpLoad %float %21
+               OpReturnValue %22
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.wgsl b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.wgsl
new file mode 100644
index 0000000..1bf8d52
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_matrix.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : mat4x4f,
+}
+
+fn f() -> f32 {
+  var a = S();
+  return a.n[2][1];
+}
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl b/test/tint/expressions/index/var/struct_with_vector.wgsl
new file mode 100644
index 0000000..d108aaf
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m: i32,
+  n: vec3u,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.dxc.hlsl b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..003bbc6
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.dxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.fxc.hlsl b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..003bbc6
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  S a = (S)0;
+  return a.n[2];
+}
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.glsl b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.glsl
new file mode 100644
index 0000000..bd84f8b
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  int m;
+  uvec3 n;
+};
+
+uint f() {
+  S a = S(0, uvec3(0u));
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.ir.msl b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.ir.msl
new file mode 100644
index 0000000..f03c5aa
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.ir.msl
@@ -0,0 +1,9 @@
+SKIP: FAILED
+
+<dawn>/src/tint/lang/msl/writer/printer/printer.cc:264 internal compiler error: Switch() matched no cases. Type: tint::core::ir::LoadVectorElement
+********************************************************************
+*  The tint shader compiler has encountered an unexpected error.   *
+*                                                                  *
+*  Please help us fix this issue by submitting a bug report at     *
+*  crbug.com/tint with the source program that triggered the bug.  *
+********************************************************************
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.msl b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.msl
new file mode 100644
index 0000000..f9b288c
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+  uint3 n;
+};
+
+uint f() {
+  S a = S{};
+  return a.n[2];
+}
+
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.spvasm b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.spvasm
new file mode 100644
index 0000000..16a6b7b
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 20
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpMemberName %S 1 "n"
+               OpName %a "a"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+          %5 = OpTypeFunction %uint
+        %int = OpTypeInt 32 1
+     %v3uint = OpTypeVector %uint 3
+          %S = OpTypeStruct %int %v3uint
+         %12 = OpConstantNull %S
+%_ptr_Function_S = OpTypePointer Function %S
+     %uint_1 = OpConstant %uint 1
+      %int_2 = OpConstant %int 2
+%_ptr_Function_uint = OpTypePointer Function %uint
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %uint None %5
+          %8 = OpLabel
+          %a = OpVariable %_ptr_Function_S Function %12
+               OpStore %a %12
+         %18 = OpAccessChain %_ptr_Function_uint %a %uint_1 %int_2
+         %19 = OpLoad %uint %18
+               OpReturnValue %19
+               OpFunctionEnd
diff --git a/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.wgsl b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.wgsl
new file mode 100644
index 0000000..202ab7b
--- /dev/null
+++ b/test/tint/expressions/index/var/struct_with_vector.wgsl.expected.wgsl
@@ -0,0 +1,9 @@
+struct S {
+  m : i32,
+  n : vec3u,
+}
+
+fn f() -> u32 {
+  var a = S();
+  return a.n[2];
+}