writer/msl: Wrap each array type in a struct

This allows them to be used in various places that WGSL allows, such
as function return types and parameters, and as the type of the RHS of
an assignment.

Fixed: tint:814
Fixed: tint:820
Change-Id: Idb6a901b9a34e96bb9733cc158191e7b3bafaa0e
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/52844
Auto-Submit: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/test/array/assign_to_function_var.wgsl b/test/array/assign_to_function_var.wgsl
new file mode 100644
index 0000000..043fb8c
--- /dev/null
+++ b/test/array/assign_to_function_var.wgsl
@@ -0,0 +1,53 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+var<private> src_private : ArrayType;
+var<workgroup> src_workgroup : ArrayType;
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+
+  var dst : ArrayType;
+
+  // Assign from type constructor.
+  dst = ArrayType(1, 2, 3, 3);
+
+  // Assign from parameter.
+  dst = src_param;
+
+  // Assign from function call.
+  dst = ret_arr();
+
+  // Assign from constant.
+  let src_let : ArrayType = ArrayType();
+  dst = src_let;
+
+  // Assign from var, various storage classes.
+  dst = src_function;
+  dst = src_private;
+  dst = src_workgroup;
+
+  // Assign from struct.arr, various storage classes.
+  dst = ret_struct_arr().arr;
+  dst = src_uniform.arr;
+  dst = src_storage.arr;
+
+  // Nested assignment.
+  var dst_nested : array<array<array<i32, 2>, 3>, 4>;
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested = src_nested;
+}
diff --git a/test/array/assign_to_function_var.wgsl.expected.hlsl b/test/array/assign_to_function_var.wgsl.expected.hlsl
new file mode 100644
index 0000000..7d6165e
--- /dev/null
+++ b/test/array/assign_to_function_var.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/845
diff --git a/test/array/assign_to_function_var.wgsl.expected.msl b/test/array/assign_to_function_var.wgsl.expected.msl
new file mode 100644
index 0000000..0ae6e42
--- /dev/null
+++ b/test/array/assign_to_function_var.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/649
diff --git a/test/array/assign_to_function_var.wgsl.expected.spvasm b/test/array/assign_to_function_var.wgsl.expected.spvasm
new file mode 100644
index 0000000..806064b
--- /dev/null
+++ b/test/array/assign_to_function_var.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 60
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %src_private "src_private"
+               OpName %src_workgroup "src_workgroup"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %src_uniform "src_uniform"
+               OpName %src_storage "src_storage"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %ret_arr "ret_arr"
+               OpName %ret_struct_arr "ret_struct_arr"
+               OpName %foo "foo"
+               OpName %src_param "src_param"
+               OpName %src_function "src_function"
+               OpName %dst "dst"
+               OpName %dst_nested "dst_nested"
+               OpName %src_nested "src_nested"
+               OpDecorate %_arr_int_uint_4 ArrayStride 16
+               OpDecorate %S Block
+               OpMemberDecorate %S 0 Offset 0
+               OpDecorate %src_uniform DescriptorSet 0
+               OpDecorate %src_uniform Binding 0
+               OpDecorate %src_storage DescriptorSet 0
+               OpDecorate %src_storage Binding 1
+               OpDecorate %_arr_int_uint_2 ArrayStride 4
+               OpDecorate %_arr__arr_int_uint_2_uint_3 ArrayStride 8
+               OpDecorate %_arr__arr__arr_int_uint_2_uint_3_uint_4 ArrayStride 24
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+          %7 = OpConstantNull %_arr_int_uint_4
+%src_private = OpVariable %_ptr_Private__arr_int_uint_4 Private %7
+%_ptr_Workgroup__arr_int_uint_4 = OpTypePointer Workgroup %_arr_int_uint_4
+%src_workgroup = OpVariable %_ptr_Workgroup__arr_int_uint_4 Workgroup
+          %S = OpTypeStruct %_arr_int_uint_4
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+%src_uniform = OpVariable %_ptr_Uniform_S Uniform
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+%src_storage = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+         %19 = OpTypeFunction %_arr_int_uint_4
+         %22 = OpTypeFunction %S
+         %25 = OpConstantNull %S
+         %26 = OpTypeFunction %void %_arr_int_uint_4
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %36 = OpConstantComposite %_arr_int_uint_4 %int_1 %int_2 %int_3 %int_3
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_int_uint_4 = OpTypePointer Uniform %_arr_int_uint_4
+%_ptr_StorageBuffer__arr_int_uint_4 = OpTypePointer StorageBuffer %_arr_int_uint_4
+     %uint_2 = OpConstant %uint 2
+%_arr_int_uint_2 = OpTypeArray %int %uint_2
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_int_uint_2_uint_3 = OpTypeArray %_arr_int_uint_2 %uint_3
+%_arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypeArray %_arr__arr_int_uint_2_uint_3 %uint_4
+%_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer Function %_arr__arr__arr_int_uint_2_uint_3_uint_4
+         %57 = OpConstantNull %_arr__arr__arr_int_uint_2_uint_3_uint_4
+%unused_entry_point = OpFunction %void None %15
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+    %ret_arr = OpFunction %_arr_int_uint_4 None %19
+         %21 = OpLabel
+               OpReturnValue %7
+               OpFunctionEnd
+%ret_struct_arr = OpFunction %S None %22
+         %24 = OpLabel
+               OpReturnValue %25
+               OpFunctionEnd
+        %foo = OpFunction %void None %26
+  %src_param = OpFunctionParameter %_arr_int_uint_4
+         %29 = OpLabel
+%src_function = OpVariable %_ptr_Function__arr_int_uint_4 Function %7
+        %dst = OpVariable %_ptr_Function__arr_int_uint_4 Function %7
+ %dst_nested = OpVariable %_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 Function %57
+ %src_nested = OpVariable %_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 Function %57
+               OpStore %dst %36
+               OpStore %dst %src_param
+         %37 = OpFunctionCall %_arr_int_uint_4 %ret_arr
+               OpStore %dst %37
+               OpStore %dst %7
+         %38 = OpLoad %_arr_int_uint_4 %src_function
+               OpStore %dst %38
+         %39 = OpLoad %_arr_int_uint_4 %src_private
+               OpStore %dst %39
+         %40 = OpLoad %_arr_int_uint_4 %src_workgroup
+               OpStore %dst %40
+         %41 = OpFunctionCall %S %ret_struct_arr
+         %42 = OpCompositeExtract %_arr_int_uint_4 %41 0
+               OpStore %dst %42
+         %45 = OpAccessChain %_ptr_Uniform__arr_int_uint_4 %src_uniform %uint_0
+         %46 = OpLoad %_arr_int_uint_4 %45
+               OpStore %dst %46
+         %48 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %src_storage %uint_0
+         %49 = OpLoad %_arr_int_uint_4 %48
+               OpStore %dst %49
+         %59 = OpLoad %_arr__arr__arr_int_uint_2_uint_3_uint_4 %src_nested
+               OpStore %dst_nested %59
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/assign_to_function_var.wgsl.expected.wgsl b/test/array/assign_to_function_var.wgsl.expected.wgsl
new file mode 100644
index 0000000..7b23ed6
--- /dev/null
+++ b/test/array/assign_to_function_var.wgsl.expected.wgsl
@@ -0,0 +1,41 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+var<private> src_private : ArrayType;
+
+var<workgroup> src_workgroup : ArrayType;
+
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+  var dst : ArrayType;
+  dst = ArrayType(1, 2, 3, 3);
+  dst = src_param;
+  dst = ret_arr();
+  let src_let : ArrayType = ArrayType();
+  dst = src_let;
+  dst = src_function;
+  dst = src_private;
+  dst = src_workgroup;
+  dst = ret_struct_arr().arr;
+  dst = src_uniform.arr;
+  dst = src_storage.arr;
+  var dst_nested : array<array<array<i32, 2>, 3>, 4>;
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested = src_nested;
+}
diff --git a/test/array/assign_to_private_var.wgsl b/test/array/assign_to_private_var.wgsl
new file mode 100644
index 0000000..1c32ee3
--- /dev/null
+++ b/test/array/assign_to_private_var.wgsl
@@ -0,0 +1,53 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+var<private> src_private : ArrayType;
+var<workgroup> src_workgroup : ArrayType;
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+var<private> dst : ArrayType;
+var<private> dst_nested : array<array<array<i32, 2>, 3>, 4>;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+
+  // Assign from type constructor.
+  dst = ArrayType(1, 2, 3, 3);
+
+  // Assign from parameter.
+  dst = src_param;
+
+  // Assign from function call.
+  dst = ret_arr();
+
+  // Assign from constant.
+  let src_let : ArrayType = ArrayType();
+  dst = src_let;
+
+  // Assign from var, various storage classes.
+  dst = src_function;
+  dst = src_private;
+  dst = src_workgroup;
+
+  // Assign from struct.arr, various storage classes.
+  dst = ret_struct_arr().arr;
+  dst = src_uniform.arr;
+  dst = src_storage.arr;
+
+  // Nested assignment.
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested = src_nested;
+}
diff --git a/test/array/assign_to_private_var.wgsl.expected.hlsl b/test/array/assign_to_private_var.wgsl.expected.hlsl
new file mode 100644
index 0000000..7d6165e
--- /dev/null
+++ b/test/array/assign_to_private_var.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/845
diff --git a/test/array/assign_to_private_var.wgsl.expected.msl b/test/array/assign_to_private_var.wgsl.expected.msl
new file mode 100644
index 0000000..0ae6e42
--- /dev/null
+++ b/test/array/assign_to_private_var.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/649
diff --git a/test/array/assign_to_private_var.wgsl.expected.spvasm b/test/array/assign_to_private_var.wgsl.expected.spvasm
new file mode 100644
index 0000000..3ef5aa7
--- /dev/null
+++ b/test/array/assign_to_private_var.wgsl.expected.spvasm
@@ -0,0 +1,113 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %src_private "src_private"
+               OpName %src_workgroup "src_workgroup"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %src_uniform "src_uniform"
+               OpName %src_storage "src_storage"
+               OpName %dst "dst"
+               OpName %dst_nested "dst_nested"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %ret_arr "ret_arr"
+               OpName %ret_struct_arr "ret_struct_arr"
+               OpName %foo "foo"
+               OpName %src_param "src_param"
+               OpName %src_function "src_function"
+               OpName %src_nested "src_nested"
+               OpDecorate %_arr_int_uint_4 ArrayStride 16
+               OpDecorate %S Block
+               OpMemberDecorate %S 0 Offset 0
+               OpDecorate %src_uniform DescriptorSet 0
+               OpDecorate %src_uniform Binding 0
+               OpDecorate %src_storage DescriptorSet 0
+               OpDecorate %src_storage Binding 1
+               OpDecorate %_arr_int_uint_2 ArrayStride 4
+               OpDecorate %_arr__arr_int_uint_2_uint_3 ArrayStride 8
+               OpDecorate %_arr__arr__arr_int_uint_2_uint_3_uint_4 ArrayStride 24
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+          %7 = OpConstantNull %_arr_int_uint_4
+%src_private = OpVariable %_ptr_Private__arr_int_uint_4 Private %7
+%_ptr_Workgroup__arr_int_uint_4 = OpTypePointer Workgroup %_arr_int_uint_4
+%src_workgroup = OpVariable %_ptr_Workgroup__arr_int_uint_4 Workgroup
+          %S = OpTypeStruct %_arr_int_uint_4
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+%src_uniform = OpVariable %_ptr_Uniform_S Uniform
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+%src_storage = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+        %dst = OpVariable %_ptr_Private__arr_int_uint_4 Private %7
+     %uint_2 = OpConstant %uint 2
+%_arr_int_uint_2 = OpTypeArray %int %uint_2
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_int_uint_2_uint_3 = OpTypeArray %_arr_int_uint_2 %uint_3
+%_arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypeArray %_arr__arr_int_uint_2_uint_3 %uint_4
+%_ptr_Private__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer Private %_arr__arr__arr_int_uint_2_uint_3_uint_4
+         %23 = OpConstantNull %_arr__arr__arr_int_uint_2_uint_3_uint_4
+ %dst_nested = OpVariable %_ptr_Private__arr__arr__arr_int_uint_2_uint_3_uint_4 Private %23
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+         %28 = OpTypeFunction %_arr_int_uint_4
+         %31 = OpTypeFunction %S
+         %34 = OpConstantNull %S
+         %35 = OpTypeFunction %void %_arr_int_uint_4
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %44 = OpConstantComposite %_arr_int_uint_4 %int_1 %int_2 %int_3 %int_3
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_int_uint_4 = OpTypePointer Uniform %_arr_int_uint_4
+%_ptr_StorageBuffer__arr_int_uint_4 = OpTypePointer StorageBuffer %_arr_int_uint_4
+%_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer Function %_arr__arr__arr_int_uint_2_uint_3_uint_4
+%unused_entry_point = OpFunction %void None %24
+         %27 = OpLabel
+               OpReturn
+               OpFunctionEnd
+    %ret_arr = OpFunction %_arr_int_uint_4 None %28
+         %30 = OpLabel
+               OpReturnValue %7
+               OpFunctionEnd
+%ret_struct_arr = OpFunction %S None %31
+         %33 = OpLabel
+               OpReturnValue %34
+               OpFunctionEnd
+        %foo = OpFunction %void None %35
+  %src_param = OpFunctionParameter %_arr_int_uint_4
+         %38 = OpLabel
+%src_function = OpVariable %_ptr_Function__arr_int_uint_4 Function %7
+ %src_nested = OpVariable %_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 Function %23
+               OpStore %dst %44
+               OpStore %dst %src_param
+         %45 = OpFunctionCall %_arr_int_uint_4 %ret_arr
+               OpStore %dst %45
+               OpStore %dst %7
+         %46 = OpLoad %_arr_int_uint_4 %src_function
+               OpStore %dst %46
+         %47 = OpLoad %_arr_int_uint_4 %src_private
+               OpStore %dst %47
+         %48 = OpLoad %_arr_int_uint_4 %src_workgroup
+               OpStore %dst %48
+         %49 = OpFunctionCall %S %ret_struct_arr
+         %50 = OpCompositeExtract %_arr_int_uint_4 %49 0
+               OpStore %dst %50
+         %53 = OpAccessChain %_ptr_Uniform__arr_int_uint_4 %src_uniform %uint_0
+         %54 = OpLoad %_arr_int_uint_4 %53
+               OpStore %dst %54
+         %56 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %src_storage %uint_0
+         %57 = OpLoad %_arr_int_uint_4 %56
+               OpStore %dst %57
+         %60 = OpLoad %_arr__arr__arr_int_uint_2_uint_3_uint_4 %src_nested
+               OpStore %dst_nested %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/assign_to_private_var.wgsl.expected.wgsl b/test/array/assign_to_private_var.wgsl.expected.wgsl
new file mode 100644
index 0000000..af9c38e
--- /dev/null
+++ b/test/array/assign_to_private_var.wgsl.expected.wgsl
@@ -0,0 +1,43 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+var<private> src_private : ArrayType;
+
+var<workgroup> src_workgroup : ArrayType;
+
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+var<private> dst : ArrayType;
+
+var<private> dst_nested : array<array<array<i32, 2>, 3>, 4>;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+  dst = ArrayType(1, 2, 3, 3);
+  dst = src_param;
+  dst = ret_arr();
+  let src_let : ArrayType = ArrayType();
+  dst = src_let;
+  dst = src_function;
+  dst = src_private;
+  dst = src_workgroup;
+  dst = ret_struct_arr().arr;
+  dst = src_uniform.arr;
+  dst = src_storage.arr;
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested = src_nested;
+}
diff --git a/test/array/assign_to_storage_var.wgsl b/test/array/assign_to_storage_var.wgsl
new file mode 100644
index 0000000..5754a22
--- /dev/null
+++ b/test/array/assign_to_storage_var.wgsl
@@ -0,0 +1,58 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+[[block]]
+struct S_nested {
+  arr : array<array<array<i32, 2>, 3>, 4>;
+};
+
+var<private> src_private : ArrayType;
+var<workgroup> src_workgroup : ArrayType;
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+[[group(0), binding(2)]] var<storage> dst : [[access(read_write)]] S;
+[[group(0), binding(3)]] var<storage> dst_nested : [[access(read_write)]] S_nested;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+
+  // Assign from type constructor.
+  dst.arr = ArrayType(1, 2, 3, 3);
+
+  // Assign from parameter.
+  dst.arr = src_param;
+
+  // Assign from function call.
+  dst.arr = ret_arr();
+
+  // Assign from constant.
+  let src_let : ArrayType = ArrayType();
+  dst.arr = src_let;
+
+  // Assign from var, various storage classes.
+  dst.arr = src_function;
+  dst.arr = src_private;
+  dst.arr = src_workgroup;
+
+  // Assign from struct.arr, various storage classes.
+  dst.arr = ret_struct_arr().arr;
+  dst.arr = src_uniform.arr;
+  dst.arr = src_storage.arr;
+
+  // Nested assignment.
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested.arr = src_nested;
+}
diff --git a/test/array/assign_to_storage_var.wgsl.expected.hlsl b/test/array/assign_to_storage_var.wgsl.expected.hlsl
new file mode 100644
index 0000000..7d6165e
--- /dev/null
+++ b/test/array/assign_to_storage_var.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/845
diff --git a/test/array/assign_to_storage_var.wgsl.expected.msl b/test/array/assign_to_storage_var.wgsl.expected.msl
new file mode 100644
index 0000000..0ae6e42
--- /dev/null
+++ b/test/array/assign_to_storage_var.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/649
diff --git a/test/array/assign_to_storage_var.wgsl.expected.spvasm b/test/array/assign_to_storage_var.wgsl.expected.spvasm
new file mode 100644
index 0000000..67fa25e
--- /dev/null
+++ b/test/array/assign_to_storage_var.wgsl.expected.spvasm
@@ -0,0 +1,134 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 74
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %src_private "src_private"
+               OpName %src_workgroup "src_workgroup"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %src_uniform "src_uniform"
+               OpName %src_storage "src_storage"
+               OpName %dst "dst"
+               OpName %S_nested "S_nested"
+               OpMemberName %S_nested 0 "arr"
+               OpName %dst_nested "dst_nested"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %ret_arr "ret_arr"
+               OpName %ret_struct_arr "ret_struct_arr"
+               OpName %foo "foo"
+               OpName %src_param "src_param"
+               OpName %src_function "src_function"
+               OpName %src_nested "src_nested"
+               OpDecorate %_arr_int_uint_4 ArrayStride 16
+               OpDecorate %S Block
+               OpMemberDecorate %S 0 Offset 0
+               OpDecorate %src_uniform DescriptorSet 0
+               OpDecorate %src_uniform Binding 0
+               OpDecorate %src_storage DescriptorSet 0
+               OpDecorate %src_storage Binding 1
+               OpDecorate %dst DescriptorSet 0
+               OpDecorate %dst Binding 2
+               OpDecorate %S_nested Block
+               OpMemberDecorate %S_nested 0 Offset 0
+               OpDecorate %_arr_int_uint_2 ArrayStride 4
+               OpDecorate %_arr__arr_int_uint_2_uint_3 ArrayStride 8
+               OpDecorate %_arr__arr__arr_int_uint_2_uint_3_uint_4 ArrayStride 24
+               OpDecorate %dst_nested DescriptorSet 0
+               OpDecorate %dst_nested Binding 3
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+          %7 = OpConstantNull %_arr_int_uint_4
+%src_private = OpVariable %_ptr_Private__arr_int_uint_4 Private %7
+%_ptr_Workgroup__arr_int_uint_4 = OpTypePointer Workgroup %_arr_int_uint_4
+%src_workgroup = OpVariable %_ptr_Workgroup__arr_int_uint_4 Workgroup
+          %S = OpTypeStruct %_arr_int_uint_4
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+%src_uniform = OpVariable %_ptr_Uniform_S Uniform
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+%src_storage = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+        %dst = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+     %uint_2 = OpConstant %uint 2
+%_arr_int_uint_2 = OpTypeArray %int %uint_2
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_int_uint_2_uint_3 = OpTypeArray %_arr_int_uint_2 %uint_3
+%_arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypeArray %_arr__arr_int_uint_2_uint_3 %uint_4
+   %S_nested = OpTypeStruct %_arr__arr__arr_int_uint_2_uint_3_uint_4
+%_ptr_StorageBuffer_S_nested = OpTypePointer StorageBuffer %S_nested
+ %dst_nested = OpVariable %_ptr_StorageBuffer_S_nested StorageBuffer
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+         %28 = OpTypeFunction %_arr_int_uint_4
+         %31 = OpTypeFunction %S
+         %34 = OpConstantNull %S
+         %35 = OpTypeFunction %void %_arr_int_uint_4
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_int_uint_4 = OpTypePointer StorageBuffer %_arr_int_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %47 = OpConstantComposite %_arr_int_uint_4 %int_1 %int_2 %int_3 %int_3
+%_ptr_Uniform__arr_int_uint_4 = OpTypePointer Uniform %_arr_int_uint_4
+%_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer Function %_arr__arr__arr_int_uint_2_uint_3_uint_4
+         %70 = OpConstantNull %_arr__arr__arr_int_uint_2_uint_3_uint_4
+%_ptr_StorageBuffer__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer StorageBuffer %_arr__arr__arr_int_uint_2_uint_3_uint_4
+%unused_entry_point = OpFunction %void None %24
+         %27 = OpLabel
+               OpReturn
+               OpFunctionEnd
+    %ret_arr = OpFunction %_arr_int_uint_4 None %28
+         %30 = OpLabel
+               OpReturnValue %7
+               OpFunctionEnd
+%ret_struct_arr = OpFunction %S None %31
+         %33 = OpLabel
+               OpReturnValue %34
+               OpFunctionEnd
+        %foo = OpFunction %void None %35
+  %src_param = OpFunctionParameter %_arr_int_uint_4
+         %38 = OpLabel
+%src_function = OpVariable %_ptr_Function__arr_int_uint_4 Function %7
+ %src_nested = OpVariable %_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 Function %70
+         %43 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+               OpStore %43 %47
+         %48 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+               OpStore %48 %src_param
+         %49 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %50 = OpFunctionCall %_arr_int_uint_4 %ret_arr
+               OpStore %49 %50
+         %51 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+               OpStore %51 %7
+         %52 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %53 = OpLoad %_arr_int_uint_4 %src_function
+               OpStore %52 %53
+         %54 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %55 = OpLoad %_arr_int_uint_4 %src_private
+               OpStore %54 %55
+         %56 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %57 = OpLoad %_arr_int_uint_4 %src_workgroup
+               OpStore %56 %57
+         %58 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %59 = OpFunctionCall %S %ret_struct_arr
+         %60 = OpCompositeExtract %_arr_int_uint_4 %59 0
+               OpStore %58 %60
+         %61 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %63 = OpAccessChain %_ptr_Uniform__arr_int_uint_4 %src_uniform %uint_0
+         %64 = OpLoad %_arr_int_uint_4 %63
+               OpStore %61 %64
+         %65 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %dst %uint_0
+         %66 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %src_storage %uint_0
+         %67 = OpLoad %_arr_int_uint_4 %66
+               OpStore %65 %67
+         %72 = OpAccessChain %_ptr_StorageBuffer__arr__arr__arr_int_uint_2_uint_3_uint_4 %dst_nested %uint_0
+         %73 = OpLoad %_arr__arr__arr_int_uint_2_uint_3_uint_4 %src_nested
+               OpStore %72 %73
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/assign_to_storage_var.wgsl.expected.wgsl b/test/array/assign_to_storage_var.wgsl.expected.wgsl
new file mode 100644
index 0000000..6508595
--- /dev/null
+++ b/test/array/assign_to_storage_var.wgsl.expected.wgsl
@@ -0,0 +1,48 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+[[block]]
+struct S_nested {
+  arr : array<array<array<i32, 2>, 3>, 4>;
+};
+
+var<private> src_private : ArrayType;
+
+var<workgroup> src_workgroup : ArrayType;
+
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+[[group(0), binding(2)]] var<storage> dst : [[access(read_write)]] S;
+
+[[group(0), binding(3)]] var<storage> dst_nested : [[access(read_write)]] S_nested;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+  dst.arr = ArrayType(1, 2, 3, 3);
+  dst.arr = src_param;
+  dst.arr = ret_arr();
+  let src_let : ArrayType = ArrayType();
+  dst.arr = src_let;
+  dst.arr = src_function;
+  dst.arr = src_private;
+  dst.arr = src_workgroup;
+  dst.arr = ret_struct_arr().arr;
+  dst.arr = src_uniform.arr;
+  dst.arr = src_storage.arr;
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested.arr = src_nested;
+}
diff --git a/test/array/assign_to_subexpr.wgsl b/test/array/assign_to_subexpr.wgsl
new file mode 100644
index 0000000..c633eb7
--- /dev/null
+++ b/test/array/assign_to_subexpr.wgsl
@@ -0,0 +1,27 @@
+type ArrayType = array<i32, 4>;
+
+struct S {
+  arr : array<i32, 4>;
+};
+
+fn foo() {
+  let src : ArrayType = ArrayType();
+
+  var dst : ArrayType;
+  var dst_struct : S;
+  var dst_array : array<ArrayType, 2>;
+  let dst_ptr : ptr<function, ArrayType> = &dst;
+  let dst_struct_ptr : ptr<function, S> = &dst_struct;
+  let dst_array_ptr : ptr<function, array<ArrayType, 2>> = &dst_array;
+
+  // Assign to struct.member.
+  dst_struct.arr = src;
+
+  // Assign to array[index].
+  dst_array[1] = src;
+
+  // Assign via pointers.
+  *dst_ptr = src;
+  (*dst_struct_ptr).arr = src;
+  (*dst_array_ptr)[0] = src;
+}
diff --git a/test/array/assign_to_subexpr.wgsl.expected.hlsl b/test/array/assign_to_subexpr.wgsl.expected.hlsl
new file mode 100644
index 0000000..4d2b005
--- /dev/null
+++ b/test/array/assign_to_subexpr.wgsl.expected.hlsl
@@ -0,0 +1,21 @@
+struct S {
+  int arr[4];
+};
+
+void foo() {
+  const int src[4] = {0, 0, 0, 0};
+  int tint_symbol[4] = {0, 0, 0, 0};
+  S dst_struct = {{0, 0, 0, 0}};
+  int dst_array[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+  dst_struct.arr = src;
+  dst_array[1] = src;
+  tint_symbol = src;
+  dst_struct.arr = src;
+  dst_array[0] = src;
+}
+
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
diff --git a/test/array/assign_to_subexpr.wgsl.expected.msl b/test/array/assign_to_subexpr.wgsl.expected.msl
new file mode 100644
index 0000000..1d09d97
--- /dev/null
+++ b/test/array/assign_to_subexpr.wgsl.expected.msl
@@ -0,0 +1,28 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_array_wrapper_0 {
+  int array[4];
+};
+struct S {
+  tint_array_wrapper_0 arr;
+};
+struct tint_array_wrapper_1 {
+  tint_array_wrapper_0 array[2];
+};
+
+void foo() {
+  tint_array_wrapper_0 const src = {};
+  tint_array_wrapper_0 dst = {0};
+  S dst_struct = {};
+  tint_array_wrapper_1 dst_array = {{0}};
+  thread tint_array_wrapper_0* const dst_ptr = &(dst);
+  thread S* const dst_struct_ptr = &(dst_struct);
+  thread tint_array_wrapper_1* const dst_array_ptr = &(dst_array);
+  dst_struct.arr = src;
+  dst_array.array[1] = src;
+  *(dst_ptr) = src;
+  (*(dst_struct_ptr)).arr = src;
+  (*(dst_array_ptr)).array[0] = src;
+}
+
diff --git a/test/array/assign_to_subexpr.wgsl.expected.spvasm b/test/array/assign_to_subexpr.wgsl.expected.spvasm
new file mode 100644
index 0000000..7c4cd74
--- /dev/null
+++ b/test/array/assign_to_subexpr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; 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 %foo "foo"
+               OpName %dst "dst"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %dst_struct "dst_struct"
+               OpName %dst_array "dst_array"
+               OpDecorate %_arr_int_uint_4 ArrayStride 4
+               OpMemberDecorate %S 0 Offset 0
+               OpDecorate %_arr__arr_int_uint_4_uint_2 ArrayStride 16
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+         %11 = OpConstantNull %_arr_int_uint_4
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+          %S = OpTypeStruct %_arr_int_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+         %17 = OpConstantNull %S
+     %uint_2 = OpConstant %uint 2
+%_arr__arr_int_uint_4_uint_2 = OpTypeArray %_arr_int_uint_4 %uint_2
+%_ptr_Function__arr__arr_int_uint_4_uint_2 = OpTypePointer Function %_arr__arr_int_uint_4_uint_2
+         %22 = OpConstantNull %_arr__arr_int_uint_4_uint_2
+     %uint_0 = OpConstant %uint 0
+      %int_1 = OpConstant %int 1
+      %int_0 = OpConstant %int 0
+%unused_entry_point = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+        %foo = OpFunction %void None %1
+          %6 = OpLabel
+        %dst = OpVariable %_ptr_Function__arr_int_uint_4 Function %11
+ %dst_struct = OpVariable %_ptr_Function_S Function %17
+  %dst_array = OpVariable %_ptr_Function__arr__arr_int_uint_4_uint_2 Function %22
+         %27 = OpAccessChain %_ptr_Function__arr_int_uint_4 %dst_struct %uint_0
+               OpStore %27 %11
+         %29 = OpAccessChain %_ptr_Function__arr_int_uint_4 %dst_array %int_1
+               OpStore %29 %11
+               OpStore %dst %11
+         %32 = OpAccessChain %_ptr_Function__arr_int_uint_4 %dst_struct %uint_0
+               OpStore %32 %11
+         %35 = OpAccessChain %_ptr_Function__arr_int_uint_4 %dst_array %int_0
+               OpStore %35 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/assign_to_subexpr.wgsl.expected.wgsl b/test/array/assign_to_subexpr.wgsl.expected.wgsl
new file mode 100644
index 0000000..6ab4099
--- /dev/null
+++ b/test/array/assign_to_subexpr.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+type ArrayType = array<i32, 4>;
+
+struct S {
+  arr : array<i32, 4>;
+};
+
+fn foo() {
+  let src : ArrayType = ArrayType();
+  var dst : ArrayType;
+  var dst_struct : S;
+  var dst_array : array<ArrayType, 2>;
+  let dst_ptr : ptr<function, ArrayType> = &(dst);
+  let dst_struct_ptr : ptr<function, S> = &(dst_struct);
+  let dst_array_ptr : ptr<function, array<ArrayType, 2>> = &(dst_array);
+  dst_struct.arr = src;
+  dst_array[1] = src;
+  *(dst_ptr) = src;
+  (*(dst_struct_ptr)).arr = src;
+  (*(dst_array_ptr))[0] = src;
+}
diff --git a/test/array/assign_to_workgroup_var.wgsl b/test/array/assign_to_workgroup_var.wgsl
new file mode 100644
index 0000000..675daf6
--- /dev/null
+++ b/test/array/assign_to_workgroup_var.wgsl
@@ -0,0 +1,53 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+var<private> src_private : ArrayType;
+var<workgroup> src_workgroup : ArrayType;
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+var<workgroup> dst : ArrayType;
+var<workgroup> dst_nested : array<array<array<i32, 2>, 3>, 4>;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+
+  // Assign from type constructor.
+  dst = ArrayType(1, 2, 3, 3);
+
+  // Assign from parameter.
+  dst = src_param;
+
+  // Assign from function call.
+  dst = ret_arr();
+
+  // Assign from constant.
+  let src_let : ArrayType = ArrayType();
+  dst = src_let;
+
+  // Assign from var, various storage classes.
+  dst = src_function;
+  dst = src_private;
+  dst = src_workgroup;
+
+  // Assign from struct.arr, various storage classes.
+  dst = ret_struct_arr().arr;
+  dst = src_uniform.arr;
+  dst = src_storage.arr;
+
+  // Nested assignment.
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested = src_nested;
+}
diff --git a/test/array/assign_to_workgroup_var.wgsl.expected.hlsl b/test/array/assign_to_workgroup_var.wgsl.expected.hlsl
new file mode 100644
index 0000000..7d6165e
--- /dev/null
+++ b/test/array/assign_to_workgroup_var.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/845
diff --git a/test/array/assign_to_workgroup_var.wgsl.expected.msl b/test/array/assign_to_workgroup_var.wgsl.expected.msl
new file mode 100644
index 0000000..0ae6e42
--- /dev/null
+++ b/test/array/assign_to_workgroup_var.wgsl.expected.msl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/649
diff --git a/test/array/assign_to_workgroup_var.wgsl.expected.spvasm b/test/array/assign_to_workgroup_var.wgsl.expected.spvasm
new file mode 100644
index 0000000..e491f49
--- /dev/null
+++ b/test/array/assign_to_workgroup_var.wgsl.expected.spvasm
@@ -0,0 +1,113 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpName %src_private "src_private"
+               OpName %src_workgroup "src_workgroup"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %src_uniform "src_uniform"
+               OpName %src_storage "src_storage"
+               OpName %dst "dst"
+               OpName %dst_nested "dst_nested"
+               OpName %unused_entry_point "unused_entry_point"
+               OpName %ret_arr "ret_arr"
+               OpName %ret_struct_arr "ret_struct_arr"
+               OpName %foo "foo"
+               OpName %src_param "src_param"
+               OpName %src_function "src_function"
+               OpName %src_nested "src_nested"
+               OpDecorate %_arr_int_uint_4 ArrayStride 16
+               OpDecorate %S Block
+               OpMemberDecorate %S 0 Offset 0
+               OpDecorate %src_uniform DescriptorSet 0
+               OpDecorate %src_uniform Binding 0
+               OpDecorate %src_storage DescriptorSet 0
+               OpDecorate %src_storage Binding 1
+               OpDecorate %_arr_int_uint_2 ArrayStride 4
+               OpDecorate %_arr__arr_int_uint_2_uint_3 ArrayStride 8
+               OpDecorate %_arr__arr__arr_int_uint_2_uint_3_uint_4 ArrayStride 24
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+          %7 = OpConstantNull %_arr_int_uint_4
+%src_private = OpVariable %_ptr_Private__arr_int_uint_4 Private %7
+%_ptr_Workgroup__arr_int_uint_4 = OpTypePointer Workgroup %_arr_int_uint_4
+%src_workgroup = OpVariable %_ptr_Workgroup__arr_int_uint_4 Workgroup
+          %S = OpTypeStruct %_arr_int_uint_4
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+%src_uniform = OpVariable %_ptr_Uniform_S Uniform
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+%src_storage = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+        %dst = OpVariable %_ptr_Workgroup__arr_int_uint_4 Workgroup
+     %uint_2 = OpConstant %uint 2
+%_arr_int_uint_2 = OpTypeArray %int %uint_2
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_int_uint_2_uint_3 = OpTypeArray %_arr_int_uint_2 %uint_3
+%_arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypeArray %_arr__arr_int_uint_2_uint_3 %uint_4
+%_ptr_Workgroup__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer Workgroup %_arr__arr__arr_int_uint_2_uint_3_uint_4
+ %dst_nested = OpVariable %_ptr_Workgroup__arr__arr__arr_int_uint_2_uint_3_uint_4 Workgroup
+       %void = OpTypeVoid
+         %23 = OpTypeFunction %void
+         %27 = OpTypeFunction %_arr_int_uint_4
+         %30 = OpTypeFunction %S
+         %33 = OpConstantNull %S
+         %34 = OpTypeFunction %void %_arr_int_uint_4
+%_ptr_Function__arr_int_uint_4 = OpTypePointer Function %_arr_int_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %43 = OpConstantComposite %_arr_int_uint_4 %int_1 %int_2 %int_3 %int_3
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_int_uint_4 = OpTypePointer Uniform %_arr_int_uint_4
+%_ptr_StorageBuffer__arr_int_uint_4 = OpTypePointer StorageBuffer %_arr_int_uint_4
+%_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 = OpTypePointer Function %_arr__arr__arr_int_uint_2_uint_3_uint_4
+         %59 = OpConstantNull %_arr__arr__arr_int_uint_2_uint_3_uint_4
+%unused_entry_point = OpFunction %void None %23
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+    %ret_arr = OpFunction %_arr_int_uint_4 None %27
+         %29 = OpLabel
+               OpReturnValue %7
+               OpFunctionEnd
+%ret_struct_arr = OpFunction %S None %30
+         %32 = OpLabel
+               OpReturnValue %33
+               OpFunctionEnd
+        %foo = OpFunction %void None %34
+  %src_param = OpFunctionParameter %_arr_int_uint_4
+         %37 = OpLabel
+%src_function = OpVariable %_ptr_Function__arr_int_uint_4 Function %7
+ %src_nested = OpVariable %_ptr_Function__arr__arr__arr_int_uint_2_uint_3_uint_4 Function %59
+               OpStore %dst %43
+               OpStore %dst %src_param
+         %44 = OpFunctionCall %_arr_int_uint_4 %ret_arr
+               OpStore %dst %44
+               OpStore %dst %7
+         %45 = OpLoad %_arr_int_uint_4 %src_function
+               OpStore %dst %45
+         %46 = OpLoad %_arr_int_uint_4 %src_private
+               OpStore %dst %46
+         %47 = OpLoad %_arr_int_uint_4 %src_workgroup
+               OpStore %dst %47
+         %48 = OpFunctionCall %S %ret_struct_arr
+         %49 = OpCompositeExtract %_arr_int_uint_4 %48 0
+               OpStore %dst %49
+         %52 = OpAccessChain %_ptr_Uniform__arr_int_uint_4 %src_uniform %uint_0
+         %53 = OpLoad %_arr_int_uint_4 %52
+               OpStore %dst %53
+         %55 = OpAccessChain %_ptr_StorageBuffer__arr_int_uint_4 %src_storage %uint_0
+         %56 = OpLoad %_arr_int_uint_4 %55
+               OpStore %dst %56
+         %60 = OpLoad %_arr__arr__arr_int_uint_2_uint_3_uint_4 %src_nested
+               OpStore %dst_nested %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/assign_to_workgroup_var.wgsl.expected.wgsl b/test/array/assign_to_workgroup_var.wgsl.expected.wgsl
new file mode 100644
index 0000000..8816948
--- /dev/null
+++ b/test/array/assign_to_workgroup_var.wgsl.expected.wgsl
@@ -0,0 +1,43 @@
+type ArrayType = [[stride(16)]] array<i32, 4>;
+
+[[block]]
+struct S {
+  arr : ArrayType;
+};
+
+var<private> src_private : ArrayType;
+
+var<workgroup> src_workgroup : ArrayType;
+
+[[group(0), binding(0)]] var<uniform> src_uniform : S;
+
+[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+
+var<workgroup> dst : ArrayType;
+
+var<workgroup> dst_nested : array<array<array<i32, 2>, 3>, 4>;
+
+fn ret_arr() -> ArrayType {
+  return ArrayType();
+}
+
+fn ret_struct_arr() -> S {
+  return S();
+}
+
+fn foo(src_param : ArrayType) {
+  var src_function : ArrayType;
+  dst = ArrayType(1, 2, 3, 3);
+  dst = src_param;
+  dst = ret_arr();
+  let src_let : ArrayType = ArrayType();
+  dst = src_let;
+  dst = src_function;
+  dst = src_private;
+  dst = src_workgroup;
+  dst = ret_struct_arr().arr;
+  dst = src_uniform.arr;
+  dst = src_storage.arr;
+  var src_nested : array<array<array<i32, 2>, 3>, 4>;
+  dst_nested = src_nested;
+}
diff --git a/test/array/function_parameter.wgsl b/test/array/function_parameter.wgsl
new file mode 100644
index 0000000..0b301e7
--- /dev/null
+++ b/test/array/function_parameter.wgsl
@@ -0,0 +1,21 @@
+fn f1(a : array<f32, 4>) -> f32 {
+  return a[3];
+}
+
+fn f2(a : array<array<f32, 4>, 3>) -> f32 {
+  return a[2][3];
+}
+
+fn f3(a : array<array<array<f32, 4>, 3>, 2>) -> f32 {
+  return a[1][2][3];
+}
+
+[[stage(compute)]]
+fn main() {
+  let a1 : array<f32, 4> = array<f32, 4>();
+  let a2 : array<array<f32, 4>, 3> = array<array<f32, 4>, 3>();
+  let a3 : array<array<array<f32, 4>, 3>, 2> = array<array<array<f32, 4>, 3>, 2>();
+  let v1 : f32 = f1(a1);
+  let v2 : f32 = f2(a2);
+  let v3 : f32 = f3(a3);
+}
diff --git a/test/array/function_parameter.wgsl.expected.hlsl b/test/array/function_parameter.wgsl.expected.hlsl
new file mode 100644
index 0000000..028cce9
--- /dev/null
+++ b/test/array/function_parameter.wgsl.expected.hlsl
@@ -0,0 +1,23 @@
+float f1(float a[4]) {
+  return a[3];
+}
+
+float f2(float a[3][4]) {
+  return a[2][3];
+}
+
+float f3(float a[2][3][4]) {
+  return a[1][2][3];
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float a1[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+  const float a2[3][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}};
+  const float a3[2][3][4] = {{{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}}, {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}}};
+  const float v1 = f1(a1);
+  const float v2 = f2(a2);
+  const float v3 = f3(a3);
+  return;
+}
+
diff --git a/test/array/function_parameter.wgsl.expected.msl b/test/array/function_parameter.wgsl.expected.msl
new file mode 100644
index 0000000..5c999da
--- /dev/null
+++ b/test/array/function_parameter.wgsl.expected.msl
@@ -0,0 +1,35 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_array_wrapper_0 {
+  float array[4];
+};
+struct tint_array_wrapper_1 {
+  tint_array_wrapper_0 array[3];
+};
+struct tint_array_wrapper_2 {
+  tint_array_wrapper_1 array[2];
+};
+
+float f1(tint_array_wrapper_0 const a) {
+  return a.array[3];
+}
+
+float f2(tint_array_wrapper_1 const a) {
+  return a.array[2].array[3];
+}
+
+float f3(tint_array_wrapper_2 const a) {
+  return a.array[1].array[2].array[3];
+}
+
+kernel void tint_symbol() {
+  tint_array_wrapper_0 const a1 = {};
+  tint_array_wrapper_1 const a2 = {};
+  tint_array_wrapper_2 const a3 = {};
+  float const v1 = f1(a1);
+  float const v2 = f2(a2);
+  float const v3 = f3(a3);
+  return;
+}
+
diff --git a/test/array/function_parameter.wgsl.expected.spvasm b/test/array/function_parameter.wgsl.expected.spvasm
new file mode 100644
index 0000000..406d4b0
--- /dev/null
+++ b/test/array/function_parameter.wgsl.expected.spvasm
@@ -0,0 +1,67 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %f1 "f1"
+               OpName %a "a"
+               OpName %f2 "f2"
+               OpName %a_0 "a"
+               OpName %f3 "f3"
+               OpName %a_1 "a"
+               OpName %main "main"
+               OpDecorate %_arr_float_uint_4 ArrayStride 4
+               OpDecorate %_arr__arr_float_uint_4_uint_3 ArrayStride 16
+               OpDecorate %_arr__arr__arr_float_uint_4_uint_3_uint_2 ArrayStride 48
+      %float = OpTypeFloat 32
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_float_uint_4 = OpTypeArray %float %uint_4
+          %1 = OpTypeFunction %float %_arr_float_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_float_uint_4_uint_3 = OpTypeArray %_arr_float_uint_4 %uint_3
+         %12 = OpTypeFunction %float %_arr__arr_float_uint_4_uint_3
+      %int_2 = OpConstant %int 2
+     %uint_2 = OpConstant %uint 2
+%_arr__arr__arr_float_uint_4_uint_3_uint_2 = OpTypeArray %_arr__arr_float_uint_4_uint_3 %uint_2
+         %21 = OpTypeFunction %float %_arr__arr__arr_float_uint_4_uint_3_uint_2
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %31 = OpTypeFunction %void
+         %35 = OpConstantNull %_arr_float_uint_4
+         %36 = OpConstantNull %_arr__arr_float_uint_4_uint_3
+         %37 = OpConstantNull %_arr__arr__arr_float_uint_4_uint_3_uint_2
+         %f1 = OpFunction %float None %1
+          %a = OpFunctionParameter %_arr_float_uint_4
+          %8 = OpLabel
+         %11 = OpCompositeExtract %float %a 3
+               OpReturnValue %11
+               OpFunctionEnd
+         %f2 = OpFunction %float None %12
+        %a_0 = OpFunctionParameter %_arr__arr_float_uint_4_uint_3
+         %17 = OpLabel
+         %19 = OpCompositeExtract %_arr_float_uint_4 %a_0 2
+         %20 = OpCompositeExtract %float %19 3
+               OpReturnValue %20
+               OpFunctionEnd
+         %f3 = OpFunction %float None %21
+        %a_1 = OpFunctionParameter %_arr__arr__arr_float_uint_4_uint_3_uint_2
+         %26 = OpLabel
+         %28 = OpCompositeExtract %_arr__arr_float_uint_4_uint_3 %a_1 1
+         %29 = OpCompositeExtract %_arr_float_uint_4 %28 2
+         %30 = OpCompositeExtract %float %29 3
+               OpReturnValue %30
+               OpFunctionEnd
+       %main = OpFunction %void None %31
+         %34 = OpLabel
+         %38 = OpFunctionCall %float %f1 %35
+         %39 = OpFunctionCall %float %f2 %36
+         %40 = OpFunctionCall %float %f3 %37
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/function_parameter.wgsl.expected.wgsl b/test/array/function_parameter.wgsl.expected.wgsl
new file mode 100644
index 0000000..0b301e7
--- /dev/null
+++ b/test/array/function_parameter.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+fn f1(a : array<f32, 4>) -> f32 {
+  return a[3];
+}
+
+fn f2(a : array<array<f32, 4>, 3>) -> f32 {
+  return a[2][3];
+}
+
+fn f3(a : array<array<array<f32, 4>, 3>, 2>) -> f32 {
+  return a[1][2][3];
+}
+
+[[stage(compute)]]
+fn main() {
+  let a1 : array<f32, 4> = array<f32, 4>();
+  let a2 : array<array<f32, 4>, 3> = array<array<f32, 4>, 3>();
+  let a3 : array<array<array<f32, 4>, 3>, 2> = array<array<array<f32, 4>, 3>, 2>();
+  let v1 : f32 = f1(a1);
+  let v2 : f32 = f2(a2);
+  let v3 : f32 = f3(a3);
+}
diff --git a/test/array/function_return_type.wgsl b/test/array/function_return_type.wgsl
new file mode 100644
index 0000000..ba2a3a9
--- /dev/null
+++ b/test/array/function_return_type.wgsl
@@ -0,0 +1,18 @@
+fn f1() -> array<f32, 4> {
+  return array<f32, 4>();
+}
+
+fn f2() -> array<array<f32, 4>, 3> {
+  return array<array<f32, 4>, 3>(f1(), f1(), f1());
+}
+
+fn f3() -> array<array<array<f32, 4>, 3>, 2> {
+  return array<array<array<f32, 4>, 3>, 2>(f2(), f2());
+}
+
+[[stage(compute)]]
+fn main() {
+  let a1 : array<f32, 4> = f1();
+  let a2 : array<array<f32, 4>, 3> = f2();
+  let a3 : array<array<array<f32, 4>, 3>, 2> = f3();
+}
diff --git a/test/array/function_return_type.wgsl.expected.hlsl b/test/array/function_return_type.wgsl.expected.hlsl
new file mode 100644
index 0000000..7d6165e
--- /dev/null
+++ b/test/array/function_return_type.wgsl.expected.hlsl
@@ -0,0 +1 @@
+SKIP: crbug.com/tint/845
diff --git a/test/array/function_return_type.wgsl.expected.msl b/test/array/function_return_type.wgsl.expected.msl
new file mode 100644
index 0000000..709f410
--- /dev/null
+++ b/test/array/function_return_type.wgsl.expected.msl
@@ -0,0 +1,35 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_array_wrapper_0 {
+  float array[4];
+};
+struct tint_array_wrapper_1 {
+  tint_array_wrapper_0 array[3];
+};
+struct tint_array_wrapper_2 {
+  tint_array_wrapper_1 array[2];
+};
+
+tint_array_wrapper_0 f1() {
+  tint_array_wrapper_0 const tint_symbol_1 = {};
+  return tint_symbol_1;
+}
+
+tint_array_wrapper_1 f2() {
+  tint_array_wrapper_1 const tint_symbol_2 = {f1(), f1(), f1()};
+  return tint_symbol_2;
+}
+
+tint_array_wrapper_2 f3() {
+  tint_array_wrapper_2 const tint_symbol_3 = {f2(), f2()};
+  return tint_symbol_3;
+}
+
+kernel void tint_symbol() {
+  tint_array_wrapper_0 const a1 = f1();
+  tint_array_wrapper_1 const a2 = f2();
+  tint_array_wrapper_2 const a3 = f3();
+  return;
+}
+
diff --git a/test/array/function_return_type.wgsl.expected.spvasm b/test/array/function_return_type.wgsl.expected.spvasm
new file mode 100644
index 0000000..a1a6115
--- /dev/null
+++ b/test/array/function_return_type.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 33
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %f1 "f1"
+               OpName %f2 "f2"
+               OpName %f3 "f3"
+               OpName %main "main"
+               OpDecorate %_arr_float_uint_4 ArrayStride 4
+               OpDecorate %_arr__arr_float_uint_4_uint_3 ArrayStride 16
+               OpDecorate %_arr__arr__arr_float_uint_4_uint_3_uint_2 ArrayStride 48
+      %float = OpTypeFloat 32
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_float_uint_4 = OpTypeArray %float %uint_4
+          %1 = OpTypeFunction %_arr_float_uint_4
+          %8 = OpConstantNull %_arr_float_uint_4
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_float_uint_4_uint_3 = OpTypeArray %_arr_float_uint_4 %uint_3
+          %9 = OpTypeFunction %_arr__arr_float_uint_4_uint_3
+     %uint_2 = OpConstant %uint 2
+%_arr__arr__arr_float_uint_4_uint_3_uint_2 = OpTypeArray %_arr__arr_float_uint_4_uint_3 %uint_2
+         %18 = OpTypeFunction %_arr__arr__arr_float_uint_4_uint_3_uint_2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+         %f1 = OpFunction %_arr_float_uint_4 None %1
+          %7 = OpLabel
+               OpReturnValue %8
+               OpFunctionEnd
+         %f2 = OpFunction %_arr__arr_float_uint_4_uint_3 None %9
+         %13 = OpLabel
+         %14 = OpFunctionCall %_arr_float_uint_4 %f1
+         %15 = OpFunctionCall %_arr_float_uint_4 %f1
+         %16 = OpFunctionCall %_arr_float_uint_4 %f1
+         %17 = OpCompositeConstruct %_arr__arr_float_uint_4_uint_3 %14 %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+         %f3 = OpFunction %_arr__arr__arr_float_uint_4_uint_3_uint_2 None %18
+         %22 = OpLabel
+         %23 = OpFunctionCall %_arr__arr_float_uint_4_uint_3 %f2
+         %24 = OpFunctionCall %_arr__arr_float_uint_4_uint_3 %f2
+         %25 = OpCompositeConstruct %_arr__arr__arr_float_uint_4_uint_3_uint_2 %23 %24
+               OpReturnValue %25
+               OpFunctionEnd
+       %main = OpFunction %void None %26
+         %29 = OpLabel
+         %30 = OpFunctionCall %_arr_float_uint_4 %f1
+         %31 = OpFunctionCall %_arr__arr_float_uint_4_uint_3 %f2
+         %32 = OpFunctionCall %_arr__arr__arr_float_uint_4_uint_3_uint_2 %f3
+               OpReturn
+               OpFunctionEnd
diff --git a/test/array/function_return_type.wgsl.expected.wgsl b/test/array/function_return_type.wgsl.expected.wgsl
new file mode 100644
index 0000000..ba2a3a9
--- /dev/null
+++ b/test/array/function_return_type.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+fn f1() -> array<f32, 4> {
+  return array<f32, 4>();
+}
+
+fn f2() -> array<array<f32, 4>, 3> {
+  return array<array<f32, 4>, 3>(f1(), f1(), f1());
+}
+
+fn f3() -> array<array<array<f32, 4>, 3>, 2> {
+  return array<array<array<f32, 4>, 3>, 2>(f2(), f2());
+}
+
+[[stage(compute)]]
+fn main() {
+  let a1 : array<f32, 4> = f1();
+  let a2 : array<array<f32, 4>, 3> = f2();
+  let a3 : array<array<array<f32, 4>, 3>, 2> = f3();
+}
diff --git a/test/array/type_constructor.wgsl.expected.msl b/test/array/type_constructor.wgsl.expected.msl
index 77696be..791d6a6 100644
--- a/test/array/type_constructor.wgsl.expected.msl
+++ b/test/array/type_constructor.wgsl.expected.msl
@@ -1 +1,53 @@
-SKIP: crbug.com/tint/814
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_array_wrapper_0 {
+  int array[4];
+};
+struct tint_array_wrapper_1 {
+  tint_array_wrapper_0 array[3];
+};
+struct tint_array_wrapper_2 {
+  tint_array_wrapper_1 array[2];
+};
+struct tint_array_wrapper_3 {
+  tint_array_wrapper_0 array[2];
+};
+
+kernel void tint_symbol() {
+  int const x = 42;
+  tint_array_wrapper_0 const empty = {};
+  tint_array_wrapper_0 const nonempty = {1, 2, 3, 4};
+  tint_array_wrapper_0 const nonempty_with_expr = {1, x, (x + 1), nonempty.array[3]};
+  tint_array_wrapper_2 const nested_empty = {};
+  tint_array_wrapper_0 const tint_symbol_1 = {1, 2, 3, 4};
+  tint_array_wrapper_0 const tint_symbol_2 = {5, 6, 7, 8};
+  tint_array_wrapper_0 const tint_symbol_3 = {9, 10, 11, 12};
+  tint_array_wrapper_1 const tint_symbol_4 = {tint_symbol_1, tint_symbol_2, tint_symbol_3};
+  tint_array_wrapper_0 const tint_symbol_5 = {13, 14, 15, 16};
+  tint_array_wrapper_0 const tint_symbol_6 = {17, 18, 19, 20};
+  tint_array_wrapper_0 const tint_symbol_7 = {21, 22, 23, 24};
+  tint_array_wrapper_1 const tint_symbol_8 = {tint_symbol_5, tint_symbol_6, tint_symbol_7};
+  tint_array_wrapper_2 const nested_nonempty = {tint_symbol_4, tint_symbol_8};
+  tint_array_wrapper_0 const tint_symbol_9 = {1, 2, x, (x + 1)};
+  tint_array_wrapper_0 const tint_symbol_10 = {5, 6, nonempty.array[2], (nonempty.array[3] + 1)};
+  tint_array_wrapper_1 const tint_symbol_11 = {tint_symbol_9, tint_symbol_10, nonempty};
+  tint_array_wrapper_2 const nested_nonempty_with_expr = {tint_symbol_11, nested_nonempty.array[1]};
+  tint_array_wrapper_0 const tint_symbol_12 = {};
+  int const subexpr_empty = tint_symbol_12.array[1];
+  tint_array_wrapper_0 const tint_symbol_13 = {1, 2, 3, 4};
+  int const subexpr_nonempty = tint_symbol_13.array[2];
+  tint_array_wrapper_0 const tint_symbol_14 = {1, x, (x + 1), nonempty.array[3]};
+  int const subexpr_nonempty_with_expr = tint_symbol_14.array[2];
+  tint_array_wrapper_3 const tint_symbol_15 = {};
+  tint_array_wrapper_0 const subexpr_nested_empty = tint_symbol_15.array[1];
+  tint_array_wrapper_0 const tint_symbol_16 = {1, 2, 3, 4};
+  tint_array_wrapper_0 const tint_symbol_17 = {5, 6, 7, 8};
+  tint_array_wrapper_3 const tint_symbol_18 = {tint_symbol_16, tint_symbol_17};
+  tint_array_wrapper_0 const subexpr_nested_nonempty = tint_symbol_18.array[1];
+  tint_array_wrapper_0 const tint_symbol_19 = {1, x, (x + 1), nonempty.array[3]};
+  tint_array_wrapper_3 const tint_symbol_20 = {tint_symbol_19, nested_nonempty.array[1].array[2]};
+  tint_array_wrapper_0 const subexpr_nested_nonempty_with_expr = tint_symbol_20.array[1];
+  return;
+}
+