tint/writer/spirv: Clean up accessor tests

Remove duplicate tests.
Use a common pattern of sanitizing, building and dumping the whole
module instead of calling individual methods. There's too much internal
state being tracked in the tests for my liking.

Split most tests into three:
* Const_* tests will check the emission of creation-time-constant
  expressions.
* Runtime_* tests will check the emission of runtime expressions, where
  indexing operates with a constant index.
* Dynamic_* tests will check the emission of runtime expressions, where
  indexing operates with a runtime index.

Bug: tint:1580
Change-Id: I0f92aaaa570cbd917d2b6937c6396605c6b542c9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94333
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/writer/spirv/builder_accessor_expression_test.cc b/src/tint/writer/spirv/builder_accessor_expression_test.cc
index c04ef6e..7ebed63 100644
--- a/src/tint/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_accessor_expression_test.cc
@@ -22,193 +22,742 @@
 
 using BuilderTest = TestHelper;
 
-TEST_F(BuilderTest, IndexAccessor_VectorRef_Literal) {
-    // var ary : vec3<f32>;
-    // ary[1]  -> ref<f32>
+TEST_F(BuilderTest, Const_IndexAccessor_Vector) {
+    // let ary = vec3<i32>(1, 2, 3);
+    // var x = ary[1i];
 
-    auto* var = Var("ary", ty.vec3<f32>());
+    auto* ary = Let("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
+    auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
+    WrapInFunction(ary, x);
 
-    auto* ary = Expr("ary");
-    auto* idx_expr = Expr(1_i);
+    spirv::Builder& b = SanitizeAndBuild();
 
-    auto* expr = IndexAccessor(ary, idx_expr);
-    WrapInFunction(var, expr);
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
 %6 = OpTypeInt 32 1
-%7 = OpConstant %6 1
-%8 = OpTypePointer Function %4
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%9 = OpAccessChain %8 %1 %7
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic) {
-    // var ary : vec3<f32>;
-    // var idx : i32;
-    // ary[idx]  -> ref<f32>
-
-    auto* var = Var("ary", ty.vec3<f32>());
-    auto* idx = Var("idx", ty.i32());
-
-    auto* ary = Expr("ary");
-    auto* idx_expr = Expr("idx");
-
-    auto* expr = IndexAccessor(ary, idx_expr);
-    WrapInFunction(var, idx, expr);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-    ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
-
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 12u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%8 = OpTypeInt 32 1
-%7 = OpTypePointer Function %8
-%9 = OpConstantNull %8
-%11 = OpTypePointer Function %4
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-%6 = OpVariable %7 Function %9
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%10 = OpLoad %8 %6
-%12 = OpAccessChain %11 %1 %10
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic2) {
-    // var ary : vec3<f32>;
-    // ary[1 + 2]  -> ref<f32>
-
-    auto* var = Var("ary", ty.vec3<f32>());
-
-    auto* ary = Expr("ary");
-
-    auto* expr = IndexAccessor(ary, Add(1_i, 2_i));
-    WrapInFunction(var, expr);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 3
 %7 = OpConstant %6 1
 %8 = OpConstant %6 2
-%10 = OpTypePointer Function %4
+%9 = OpConstant %6 3
+%10 = OpConstantComposite %5 %7 %8 %9
+%12 = OpTypePointer Function %6
+%13 = OpConstantNull %6
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%11 = OpVariable %12 Function %13
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%9 = OpIAdd %6 %7 %8
-%11 = OpAccessChain %10 %1 %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %11 %8
+OpReturn
 )");
+
+    Validate(b);
 }
 
-TEST_F(BuilderTest, IndexAccessor_ArrayRef_MultiLevel) {
-    auto* ary4 = ty.array(ty.vec3<f32>(), 4_u);
+TEST_F(BuilderTest, Runtime_IndexAccessor_Vector) {
+    // var ary : vec3<u32>;
+    // var x = ary[1i];
 
-    // var ary : array<vec3<f32>, 4u>
-    // ary[3i][2i];
+    auto* ary = Var("ary", ty.vec3<u32>());
+    auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
+    WrapInFunction(ary, x);
 
-    auto* var = Var("ary", ary4);
+    spirv::Builder& b = SanitizeAndBuild();
 
-    auto* expr = IndexAccessor(IndexAccessor("ary", 3_i), 2_i);
-    WrapInFunction(var, expr);
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 13u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeVector %5 3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 4
-%3 = OpTypeArray %4 %7
-%2 = OpTypePointer Function %3
-%8 = OpConstantNull %3
-%9 = OpTypeInt 32 1
-%10 = OpConstant %9 3
-%11 = OpConstant %9 2
-%12 = OpTypePointer Function %5
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 1
+%11 = OpConstant %10 1
+%12 = OpTypePointer Function %8
+%16 = OpConstantNull %8
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%15 = OpVariable %12 Function %16
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%13 = OpAccessChain %12 %1 %10 %11
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpStore %15 %14
+OpReturn
 )");
+
+    Validate(b);
 }
 
-TEST_F(BuilderTest, IndexAccessor_ArrayRef_ArrayWithSwizzle) {
-    auto* ary4 = ty.array(ty.vec3<f32>(), 4_u);
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Vector) {
+    // var ary : vec3<f32>;
+    // var idx : i32;
+    // var x = ary[idx];
 
-    // var a : array<vec3<f32>, 4u>;
-    // a[2i].xy;
+    auto* ary = Var("ary", ty.vec3<f32>());
+    auto* idx = Var("idx", ty.i32());
+    auto* x = Var("x", nullptr, IndexAccessor(ary, idx));
+    WrapInFunction(ary, idx, x);
 
-    auto* var = Var("ary", ary4);
+    spirv::Builder& b = SanitizeAndBuild();
 
-    auto* expr = MemberAccessor(IndexAccessor("ary", 2_i), "xy");
-    WrapInFunction(var, expr);
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 15u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeVector %5 3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 4
-%3 = OpTypeArray %4 %7
-%2 = OpTypePointer Function %3
-%8 = OpConstantNull %3
-%9 = OpTypeInt 32 1
-%10 = OpConstant %9 2
-%11 = OpTypePointer Function %4
-%13 = OpTypeVector %5 2
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeInt 32 1
+%11 = OpTypePointer Function %12
+%13 = OpConstantNull %12
+%15 = OpTypePointer Function %8
+%19 = OpConstantNull %8
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%10 = OpVariable %11 Function %13
+%18 = OpVariable %15 Function %19
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%14 = OpLoad %12 %10
+%16 = OpAccessChain %15 %5 %14
+%17 = OpLoad %8 %16
+OpStore %18 %17
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Vector2) {
+    // let ary : vec3<i32>(1, 2, 3);
+    // var x = ary[1i + 2i];
+
+    auto* ary = Let("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
+    auto* x = Var("x", nullptr, IndexAccessor(ary, Add(1_i, 2_i)));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeInt 32 1
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 1
+%8 = OpConstant %6 2
+%9 = OpConstant %6 3
+%10 = OpConstantComposite %5 %7 %8 %9
+%14 = OpTypePointer Function %6
+%15 = OpConstantNull %6
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%13 = OpVariable %14 Function %15
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%11 = OpIAdd %6 %7 %8
+%12 = OpVectorExtractDynamic %6 %10 %11
+OpStore %13 %12
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Vector2) {
+    // var ary : vec3<f32>;
+    // var x = ary[1i + 2i];
+
+    auto* ary = Var("ary", ty.vec3<f32>());
+    auto* x = Var("x", nullptr, IndexAccessor(ary, Add(1_i, 2_i)));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 1
+%11 = OpConstant %10 1
+%12 = OpConstant %10 2
+%14 = OpTypePointer Function %8
+%18 = OpConstantNull %8
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%17 = OpVariable %14 Function %18
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpIAdd %10 %11 %12
+%15 = OpAccessChain %14 %5 %13
+%16 = OpLoad %8 %15
+OpStore %17 %16
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Vector2) {
+    // var ary : vec3<f32>;
+    // var one = 1i;
+    // var x = ary[one + 2i];
+
+    auto* ary = Var("ary", ty.vec3<f32>());
+    auto* one = Var("one", nullptr, Expr(1_i));
+    auto* x = Var("x", nullptr, IndexAccessor(ary, Add(one, 2_i)));
+    WrapInFunction(ary, one, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 1
+%11 = OpConstant %10 1
+%13 = OpTypePointer Function %10
+%14 = OpConstantNull %10
+%16 = OpConstant %10 2
+%18 = OpTypePointer Function %8
+%22 = OpConstantNull %8
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+%12 = OpVariable %13 Function %14
+%21 = OpVariable %18 Function %22
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %12 %11
+%15 = OpLoad %10 %12
+%17 = OpIAdd %10 %15 %16
+%19 = OpAccessChain %18 %5 %17
+%20 = OpLoad %8 %19
+OpStore %21 %20
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Array_MultiLevel) {
+    // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
+    // var x = ary[1i][2i];
+
+    auto* ary =
+        Let("ary", nullptr,
+            array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 3
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 2
+%5 = OpTypeArray %6 %9
+%10 = OpConstant %7 1
+%11 = OpConstant %7 2
+%12 = OpConstant %7 3
+%13 = OpConstantComposite %6 %10 %11 %12
+%14 = OpConstant %7 4
+%15 = OpConstant %7 5
+%16 = OpConstant %7 6
+%17 = OpConstantComposite %6 %14 %15 %16
+%18 = OpConstantComposite %5 %13 %17
+%19 = OpTypeInt 32 1
+%20 = OpConstant %19 1
+%22 = OpConstant %19 2
+%25 = OpTypePointer Function %7
+%26 = OpConstantNull %7
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%12 = OpAccessChain %11 %1 %10
-%14 = OpLoad %4 %12
-%15 = OpVectorShuffle %13 %14 %14 0 1
+              R"(%21 = OpCompositeExtract %6 %18 1
+%23 = OpCompositeExtract %7 %21 2
+OpStore %24 %23
+OpReturn
 )");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Array_MultiLevel) {
+    // var ary : array<vec3<f32>, 4u>;
+    // var x = ary[1i][2i];
+
+    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 1
+%15 = OpConstant %13 2
+%16 = OpTypePointer Function %9
+%20 = OpConstantNull %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%19 = OpVariable %16 Function %20
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%17 = OpAccessChain %16 %5 %14 %15
+%18 = OpLoad %9 %17
+OpStore %19 %18
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Array_MultiLevel) {
+    // var ary : array<vec3<f32>, 4u>;
+    // var one = 1i;
+    // var x = ary[one][2i];
+
+    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* one = Var("one", nullptr, Expr(3_i));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, one), 2_i));
+    WrapInFunction(ary, one, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 3
+%16 = OpTypePointer Function %13
+%17 = OpConstantNull %13
+%19 = OpConstant %13 2
+%20 = OpTypePointer Function %9
+%24 = OpConstantNull %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%15 = OpVariable %16 Function %17
+%23 = OpVariable %20 Function %24
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %14
+%18 = OpLoad %13 %15
+%21 = OpAccessChain %20 %5 %18 %19
+%22 = OpLoad %9 %21
+OpStore %23 %22
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Array_ArrayWithSwizzle) {
+    // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
+    // var x = a[1i].xy;
+
+    auto* ary =
+        Let("ary", nullptr,
+            array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
+    auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 3
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 2
+%5 = OpTypeArray %6 %9
+%10 = OpConstant %7 1
+%11 = OpConstant %7 2
+%12 = OpConstant %7 3
+%13 = OpConstantComposite %6 %10 %11 %12
+%14 = OpConstant %7 4
+%15 = OpConstant %7 5
+%16 = OpConstant %7 6
+%17 = OpConstantComposite %6 %14 %15 %16
+%18 = OpConstantComposite %5 %13 %17
+%19 = OpTypeInt 32 1
+%20 = OpConstant %19 1
+%22 = OpTypeVector %7 2
+%25 = OpTypePointer Function %22
+%26 = OpConstantNull %22
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%21 = OpCompositeExtract %6 %18 1
+%23 = OpVectorShuffle %22 %21 %21 0 1
+OpStore %24 %23
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Array_ArrayWithSwizzle) {
+    // var ary : array<vec3<f32>, 4u>;
+    // var x = ary[1i].xy;
+
+    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
+    WrapInFunction(ary, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 1
+%15 = OpTypePointer Function %8
+%17 = OpTypeVector %9 2
+%21 = OpTypePointer Function %17
+%22 = OpConstantNull %17
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%20 = OpVariable %21 Function %22
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%16 = OpAccessChain %15 %5 %14
+%18 = OpLoad %8 %16
+%19 = OpVectorShuffle %17 %18 %18 0 1
+OpStore %20 %19
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Array_ArrayWithSwizzle) {
+    // var ary : array<vec3<f32>, 4u>;
+    // var one = 1i;
+    // var x = ary[one].xy;
+
+    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* one = Var("one", nullptr, Expr(1_i));
+    auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", one), "xy"));
+    WrapInFunction(ary, one, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 3
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 4
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%14 = OpConstant %13 1
+%16 = OpTypePointer Function %13
+%17 = OpConstantNull %13
+%19 = OpTypePointer Function %8
+%21 = OpTypeVector %9 2
+%25 = OpTypePointer Function %21
+%26 = OpConstantNull %21
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%15 = OpVariable %16 Function %17
+%24 = OpVariable %25 Function %26
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %14
+%18 = OpLoad %13 %15
+%20 = OpAccessChain %19 %5 %18
+%22 = OpLoad %8 %20
+%23 = OpVectorShuffle %21 %22 %22 0 1
+OpStore %24 %23
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Nested_Array_f32) {
+    // let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
+    //   array<f32, 2>(0.0, 0.5),
+    //   array<f32, 2>(-0.5, -0.5),
+    //   array<f32, 2>(0.5, -0.5));
+    // var x = pos[1u][0u];
+
+    auto* pos = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
+                    Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
+                              vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
+    WrapInFunction(pos, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 2
+%8 = OpTypeInt 32 0
+%9 = OpConstant %8 3
+%5 = OpTypeArray %6 %9
+%10 = OpConstantNull %7
+%11 = OpConstant %7 0.5
+%12 = OpConstantComposite %6 %10 %11
+%13 = OpConstant %7 -0.5
+%14 = OpConstantComposite %6 %13 %13
+%15 = OpConstantComposite %6 %11 %13
+%16 = OpConstantComposite %5 %12 %14 %15
+%17 = OpConstant %8 1
+%19 = OpConstantNull %8
+%22 = OpTypePointer Function %7
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%21 = OpVariable %22 Function %10
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%18 = OpCompositeExtract %6 %16 1
+%20 = OpCompositeExtract %7 %18 0
+OpStore %21 %20
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Nested_Array_f32) {
+    // var pos : array<array<f32, 2>, 3u>;
+    // var x = pos[1u][2u];
+
+    auto* pos = Var("pos", ty.array(ty.vec2<f32>(), 3_u));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 2_u));
+    WrapInFunction(pos, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 3
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpConstant %10 1
+%14 = OpConstant %10 2
+%15 = OpTypePointer Function %9
+%19 = OpConstantNull %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%18 = OpVariable %15 Function %19
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%16 = OpAccessChain %15 %5 %13 %14
+%17 = OpLoad %9 %16
+OpStore %18 %17
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Nested_Array_f32) {
+    // var pos : array<array<f32, 2>, 3u>;
+    // var one = 1u;
+    // var x = pos[one][2u];
+
+    auto* pos = Var("pos", ty.array(ty.vec2<f32>(), 3_u));
+    auto* one = Var("one", nullptr, Expr(2_u));
+    auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, "one"), 2_u));
+    WrapInFunction(pos, one, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 3
+%7 = OpTypeArray %8 %11
+%6 = OpTypePointer Function %7
+%12 = OpConstantNull %7
+%13 = OpConstant %10 2
+%15 = OpTypePointer Function %10
+%16 = OpConstantNull %10
+%18 = OpTypePointer Function %9
+%22 = OpConstantNull %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
+%14 = OpVariable %15 Function %16
+%21 = OpVariable %18 Function %22
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %14 %13
+%17 = OpLoad %10 %14
+%19 = OpAccessChain %18 %5 %17 %13
+%20 = OpLoad %9 %19
+OpStore %21 %20
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Const_IndexAccessor_Matrix) {
+    // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
+    // var x = a[1i]
+
+    auto* a = Let("a", ty.mat2x2<f32>(),
+                  Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
+                            Construct(ty.vec2<f32>(), 3_f, 4_f)));
+    auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
+    WrapInFunction(a, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeVector %7 2
+%5 = OpTypeMatrix %6 2
+%8 = OpConstant %7 1
+%9 = OpConstant %7 2
+%10 = OpConstantComposite %6 %8 %9
+%11 = OpConstant %7 3
+%12 = OpConstant %7 4
+%13 = OpConstantComposite %6 %11 %12
+%14 = OpConstantComposite %5 %10 %13
+%16 = OpTypePointer Function %6
+%17 = OpConstantNull %6
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%15 = OpVariable %16 Function %17
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %13
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Runtime_IndexAccessor_Matrix) {
+    // var a : mat2x2<f32>;
+    // var x = a[1i]
+
+    auto* a = Var("a", ty.mat2x2<f32>());
+    auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
+    WrapInFunction(a, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%7 = OpTypeMatrix %8 2
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 1
+%12 = OpConstant %11 1
+%13 = OpTypePointer Function %8
+%17 = OpConstantNull %8
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
+%16 = OpVariable %13 Function %17
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%14 = OpAccessChain %13 %5 %12
+%15 = OpLoad %8 %14
+OpStore %16 %15
+OpReturn
+)");
+
+    Validate(b);
+}
+
+TEST_F(BuilderTest, Dynamic_IndexAccessor_Matrix) {
+    // var a : mat2x2<f32>;
+    // var idx : i32
+    // var x = a[idx]
+
+    auto* a = Var("a", ty.mat2x2<f32>());
+    auto* idx = Var("idx", ty.i32());
+    auto* x = Var("x", nullptr, IndexAccessor("a", idx));
+    WrapInFunction(a, idx, x);
+
+    spirv::Builder& b = SanitizeAndBuild();
+
+    ASSERT_TRUE(b.Build()) << b.error();
+
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%7 = OpTypeMatrix %8 2
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%13 = OpTypeInt 32 1
+%12 = OpTypePointer Function %13
+%14 = OpConstantNull %13
+%16 = OpTypePointer Function %8
+%20 = OpConstantNull %8
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
+%11 = OpVariable %12 Function %14
+%19 = OpVariable %16 Function %20
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%15 = OpLoad %13 %11
+%17 = OpAccessChain %16 %5 %15
+%18 = OpLoad %8 %17
+OpStore %19 %18
+OpReturn
+)");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor) {
@@ -229,27 +778,28 @@
     auto* expr = MemberAccessor("ident", "b");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeStruct %8 %8
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 1
+%12 = OpTypePointer Function %8
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpReturn
+)");
 
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeStruct %4 %4
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
-%8 = OpTypePointer Function %4
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%9 = OpAccessChain %8 %1 %7
-)");
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested) {
@@ -274,29 +824,31 @@
     auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%9 = OpConstant %7 1
-%10 = OpTypePointer Function %5
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%12 = OpConstant %11 0
+%13 = OpConstant %11 1
+%14 = OpTypePointer Function %9
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%11 = OpAccessChain %10 %1 %8 %9
+              R"(%15 = OpAccessChain %14 %5 %12 %13
+%16 = OpLoad %9 %15
+OpReturn
 )");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_NonPointer) {
@@ -317,21 +869,23 @@
     auto* expr = MemberAccessor("ident", "b");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 5u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeStruct %2 %2
-%3 = OpConstantNull %2
-%4 = OpConstantComposite %1 %3 %3
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 32
+%5 = OpTypeStruct %6 %6
+%7 = OpConstantNull %6
+%8 = OpConstantComposite %5 %7 %7
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%5 = OpCompositeExtract %2 %4 1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%9 = OpCompositeExtract %6 %8 1
+OpReturn
 )");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
@@ -357,24 +911,27 @@
     auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
-%2 = OpTypeStruct %3 %3
-%1 = OpTypeStruct %2
-%4 = OpConstantNull %3
-%5 = OpConstantComposite %2 %4 %4
-%6 = OpConstantComposite %1 %5
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%7 = OpTypeFloat 32
+%6 = OpTypeStruct %7 %7
+%5 = OpTypeStruct %6
+%8 = OpConstantNull %7
+%9 = OpConstantComposite %6 %8 %8
+%10 = OpConstantComposite %5 %9
 )");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%7 = OpCompositeExtract %2 %6 0
-%8 = OpCompositeExtract %3 %7 1
+              R"(%11 = OpCompositeExtract %6 %10 0
+%12 = OpCompositeExtract %7 %11 1
+OpReturn
 )");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
@@ -401,28 +958,30 @@
     auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%9 = OpTypePointer Function %5
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%12 = OpConstant %11 0
+%13 = OpTypePointer Function %9
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%10 = OpAccessChain %9 %1 %8 %8
+              R"(%14 = OpAccessChain %13 %5 %12 %12
+%15 = OpLoad %9 %14
+OpReturn
 )");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
@@ -446,30 +1005,31 @@
     auto* expr = Assign(MemberAccessor(MemberAccessor("ident", "inner"), "a"), Expr(2_f));
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 0
-%9 = OpTypePointer Function %5
-%11 = OpConstant %5 2
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%11 = OpTypeInt 32 0
+%12 = OpConstant %11 0
+%13 = OpTypePointer Function %9
+%15 = OpConstant %9 2
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%10 = OpAccessChain %9 %1 %8 %8
-OpStore %10 %11
+              R"(%14 = OpAccessChain %13 %5 %12 %12
+OpStore %14 %15
+OpReturn
 )");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
@@ -497,33 +1057,33 @@
     auto* expr = Assign("store", rhs);
     WrapInFunction(var, store, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-    ASSERT_TRUE(b.GenerateFunctionVariable(store)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
-%4 = OpTypeStruct %5 %5
-%3 = OpTypeStruct %4
-%2 = OpTypePointer Function %3
-%6 = OpConstantNull %3
-%8 = OpTypePointer Function %5
-%9 = OpConstantNull %5
-%10 = OpTypeInt 32 0
-%11 = OpConstant %10 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%9 = OpTypeFloat 32
+%8 = OpTypeStruct %9 %9
+%7 = OpTypeStruct %8
+%6 = OpTypePointer Function %7
+%10 = OpConstantNull %7
+%12 = OpTypePointer Function %9
+%13 = OpConstantNull %9
+%14 = OpTypeInt 32 0
+%15 = OpConstant %14 0
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %6
-%7 = OpVariable %8 Function %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
+%11 = OpVariable %12 Function %13
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%12 = OpAccessChain %8 %1 %11 %11
-%13 = OpLoad %5 %12
-OpStore %7 %13
+              R"(%16 = OpAccessChain %12 %5 %15 %15
+%17 = OpLoad %9 %16
+OpStore %11 %17
+OpReturn
 )");
+
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Swizzle_Single) {
@@ -534,27 +1094,28 @@
     auto* expr = MemberAccessor("ident", "y");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeInt 32 0
+%11 = OpConstant %10 1
+%12 = OpTypePointer Function %8
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
+%14 = OpLoad %8 %13
+OpReturn
+)");
 
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
-%8 = OpTypePointer Function %4
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%9 = OpAccessChain %8 %1 %7
-)");
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Swizzle_MultipleNames) {
@@ -565,26 +1126,26 @@
     auto* expr = MemberAccessor("ident", "yx");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%10 = OpTypeVector %8 2
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%11 = OpLoad %7 %5
+%12 = OpVectorShuffle %10 %11 %11 1 0
+OpReturn
+)");
 
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeVector %4 2
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%7 = OpLoad %3 %1
-%8 = OpVectorShuffle %6 %7 %7 1 0
-)");
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Swizzle_of_Swizzle) {
@@ -595,27 +1156,27 @@
     auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "xz");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeVector %8 2
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
+%11 = OpVectorShuffle %7 %10 %10 1 0 2
+%13 = OpVectorShuffle %12 %11 %11 0 2
+OpReturn
+)");
 
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%8 = OpTypeVector %4 2
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%6 = OpLoad %3 %1
-%7 = OpVectorShuffle %3 %6 %6 1 0 2
-%9 = OpVectorShuffle %8 %7 %7 0 2
-)");
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Member_of_Swizzle) {
@@ -626,26 +1187,26 @@
     auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "x");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
+%11 = OpVectorShuffle %7 %10 %10 1 0 2
+%12 = OpCompositeExtract %8 %11 0
+OpReturn
+)");
 
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%6 = OpLoad %3 %1
-%7 = OpVectorShuffle %3 %6 %6 1 0 2
-%8 = OpCompositeExtract %4 %7 0
-)");
+    Validate(b);
 }
 
 TEST_F(BuilderTest, MemberAccessor_Array_of_Swizzle) {
@@ -656,28 +1217,28 @@
     auto* expr = IndexAccessor(MemberAccessor("ident", "yxz"), 1_i);
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
+    spirv::Builder& b = SanitizeAndBuild();
 
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+%6 = OpTypePointer Function %7
+%9 = OpConstantNull %7
+%12 = OpTypeInt 32 1
+%13 = OpConstant %12 1
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
+)");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
+%11 = OpVectorShuffle %7 %10 %10 1 0 2
+%14 = OpCompositeExtract %8 %11 1
+OpReturn
+)");
 
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%8 = OpTypeInt 32 1
-%9 = OpConstant %8 1
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %5
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%6 = OpLoad %3 %1
-%7 = OpVectorShuffle %3 %6 %6 1 0 2
-%10 = OpCompositeExtract %4 %7 1
-)");
+    Validate(b);
 }
 
 TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
@@ -709,323 +1270,37 @@
         "yx");
     WrapInFunction(var, expr);
 
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 22u);
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeFloat 32
-%8 = OpTypeVector %9 3
-%7 = OpTypeStruct %8
-%6 = OpTypeStruct %7
-%10 = OpTypeInt 32 0
-%11 = OpConstant %10 3
-%5 = OpTypeArray %6 %11
-%4 = OpTypeStruct %5
-%12 = OpConstant %10 2
-%3 = OpTypeArray %4 %12
-%2 = OpTypePointer Function %3
-%13 = OpConstantNull %3
-%14 = OpTypeInt 32 1
-%15 = OpConstantNull %14
-%16 = OpConstant %10 0
-%17 = OpConstant %14 2
-%18 = OpTypePointer Function %8
-%20 = OpTypeVector %9 2
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%1 = OpVariable %2 Function %13
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%19 = OpAccessChain %18 %1 %15 %16 %17 %16 %16
-%21 = OpLoad %8 %19
-%22 = OpVectorShuffle %20 %21 %21 1 0
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_Of_Vec) {
-    // let pos : array<vec2<f32>, 3u> = array<vec2<f32>, 3u>(
-    //   vec2<f32>(0.0, 0.5),
-    //   vec2<f32>(-0.5, -0.5),
-    //   vec2<f32>(0.5, -0.5));
-    // pos[1u]
-
-    auto* var = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
-                    Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
-                              vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
-
-    auto* expr = IndexAccessor("pos", 1_u);
-    WrapInFunction(var, expr);
-
     spirv::Builder& b = SanitizeAndBuild();
 
-    ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build()) << b.error();
 
     EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%8 = OpTypeInt 32 0
-%9 = OpConstant %8 3
-%5 = OpTypeArray %6 %9
-%10 = OpConstantNull %7
-%11 = OpConstant %7 0.5
-%12 = OpConstantComposite %6 %10 %11
-%13 = OpConstant %7 -0.5
-%14 = OpConstantComposite %6 %13 %13
-%15 = OpConstantComposite %6 %11 %13
-%16 = OpConstantComposite %5 %12 %14 %15
-%17 = OpConstant %8 1
+%13 = OpTypeFloat 32
+%12 = OpTypeVector %13 3
+%11 = OpTypeStruct %12
+%10 = OpTypeStruct %11
+%14 = OpTypeInt 32 0
+%15 = OpConstant %14 3
+%9 = OpTypeArray %10 %15
+%8 = OpTypeStruct %9
+%16 = OpConstant %14 2
+%7 = OpTypeArray %8 %16
+%6 = OpTypePointer Function %7
+%17 = OpConstantNull %7
+%18 = OpTypeInt 32 1
+%19 = OpConstantNull %18
+%20 = OpConstant %14 0
+%21 = OpConstant %18 2
+%22 = OpTypePointer Function %12
+%24 = OpTypeVector %13 2
 )");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%18 = OpCompositeExtract %6 %16 1
-OpReturn
-)");
-
-    Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Of_Array_Of_f32) {
-    // let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
-    //   array<f32, 2>(0.0, 0.5),
-    //   array<f32, 2>(-0.5, -0.5),
-    //   array<f32, 2>(0.5, -0.5));
-    // pos[2u][1u]
-
-    auto* var = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
-                    Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
-                              vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
-
-    auto* expr = IndexAccessor(IndexAccessor("pos", 2_u), 1_u);
-    WrapInFunction(var, expr);
-
-    spirv::Builder& b = SanitizeAndBuild();
-
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%8 = OpTypeInt 32 0
-%9 = OpConstant %8 3
-%5 = OpTypeArray %6 %9
-%10 = OpConstantNull %7
-%11 = OpConstant %7 0.5
-%12 = OpConstantComposite %6 %10 %11
-%13 = OpConstant %7 -0.5
-%14 = OpConstantComposite %6 %13 %13
-%15 = OpConstantComposite %6 %11 %13
-%16 = OpConstantComposite %5 %12 %14 %15
-%17 = OpConstant %8 2
-%19 = OpConstant %8 1
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%18 = OpCompositeExtract %6 %16 2
-%20 = OpCompositeExtract %7 %18 1
-OpReturn
-)");
-
-    Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Vec_Literal) {
-    // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
-    // pos[1]
-
-    auto* var = Let("pos", ty.vec2<f32>(), vec2<f32>(0_f, 0.5_f));
-
-    auto* expr = IndexAccessor("pos", 1_u);
-    WrapInFunction(var, expr);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstantNull %2
-%4 = OpConstant %2 0.5
-%5 = OpConstantComposite %1 %3 %4
-%6 = OpTypeInt 32 0
-%7 = OpConstant %6 1
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%8 = OpCompositeExtract %2 %5 1
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_Vec_Dynamic) {
-    // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
-    // idx : i32
-    // pos[idx]
-
-    auto* var = Let("pos", ty.vec2<f32>(), vec2<f32>(0_f, 0.5_f));
-    auto* idx = Var("idx", ty.i32());
-    auto* expr = IndexAccessor("pos", idx);
-
-    WrapInFunction(var, idx, expr);
-
-    spirv::Builder& b = Build();
-
-    b.push_function(Function{});
-    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-    ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
-    EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u) << b.error();
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstantNull %2
-%4 = OpConstant %2 0.5
-%5 = OpConstantComposite %1 %3 %4
-%8 = OpTypeInt 32 1
-%7 = OpTypePointer Function %8
-%9 = OpConstantNull %8
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%6 = OpVariable %7 Function %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %17
 )");
     EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%10 = OpLoad %8 %6
-%11 = OpVectorExtractDynamic %2 %5 %10
-)");
-}
-
-TEST_F(BuilderTest, IndexAccessor_Array_Literal) {
-    // let a : array<f32, 3u>;
-    // a[2i]
-
-    auto* var = Let("a", ty.array<f32, 3>(), Construct(ty.array<f32, 3>(), 0_f, 0.5_f, 1_f));
-    auto* expr = IndexAccessor("a", 2_i);
-    WrapInFunction(var, expr);
-
-    spirv::Builder& b = SanitizeAndBuild();
-
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%6 = OpTypeFloat 32
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 3
-%5 = OpTypeArray %6 %8
-%9 = OpConstantNull %6
-%10 = OpConstant %6 0.5
-%11 = OpConstant %6 1
-%12 = OpConstantComposite %5 %9 %10 %11
-%13 = OpTypeInt 32 1
-%14 = OpConstant %13 2
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(%15 = OpCompositeExtract %6 %12 2
-OpReturn
-)");
-
-    Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Array_Dynamic) {
-    // let a : array<f32, 3>;
-    // idx : i32
-    // a[idx]
-
-    auto* var = Let("a", ty.array<f32, 3>(), Construct(ty.array<f32, 3>(), 0_f, 0.5_f, 1_f));
-
-    auto* idx = Var("idx", ty.i32());
-    auto* expr = IndexAccessor("a", idx);
-
-    WrapInFunction(var, idx, expr);
-
-    spirv::Builder& b = SanitizeAndBuild();
-
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%6 = OpTypeFloat 32
-%7 = OpTypeInt 32 0
-%8 = OpConstant %7 3
-%5 = OpTypeArray %6 %8
-%9 = OpConstantNull %6
-%10 = OpConstant %6 0.5
-%11 = OpConstant %6 1
-%12 = OpConstantComposite %5 %9 %10 %11
-%15 = OpTypeInt 32 1
-%14 = OpTypePointer Function %15
-%16 = OpConstantNull %15
-%18 = OpTypePointer Function %5
-%19 = OpConstantNull %5
-%21 = OpTypePointer Function %6
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%13 = OpVariable %14 Function %16
-%17 = OpVariable %18 Function %19
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(OpStore %17 %12
-%20 = OpLoad %15 %13
-%22 = OpAccessChain %21 %17 %20
-%23 = OpLoad %6 %22
-OpReturn
-)");
-
-    Validate(b);
-}
-
-TEST_F(BuilderTest, IndexAccessor_Matrix_Dynamic) {
-    // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
-    // idx : i32
-    // a[idx]
-
-    auto* var = Let("a", ty.mat2x2<f32>(),
-                    Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
-                              Construct(ty.vec2<f32>(), 3_f, 4_f)));
-
-    auto* idx = Var("idx", ty.i32());
-    auto* expr = IndexAccessor("a", idx);
-
-    WrapInFunction(var, idx, expr);
-
-    spirv::Builder& b = SanitizeAndBuild();
-
-    ASSERT_TRUE(b.Build());
-
-    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%7 = OpTypeFloat 32
-%6 = OpTypeVector %7 2
-%5 = OpTypeMatrix %6 2
-%8 = OpConstant %7 1
-%9 = OpConstant %7 2
-%10 = OpConstantComposite %6 %8 %9
-%11 = OpConstant %7 3
-%12 = OpConstant %7 4
-%13 = OpConstantComposite %6 %11 %12
-%14 = OpConstantComposite %5 %10 %13
-%17 = OpTypeInt 32 1
-%16 = OpTypePointer Function %17
-%18 = OpConstantNull %17
-%20 = OpTypePointer Function %5
-%21 = OpConstantNull %5
-%23 = OpTypePointer Function %6
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-              R"(%15 = OpVariable %16 Function %18
-%19 = OpVariable %20 Function %21
-)");
-    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-              R"(OpStore %19 %14
-%22 = OpLoad %17 %15
-%24 = OpAccessChain %23 %19 %22
-%25 = OpLoad %6 %24
+              R"(%23 = OpAccessChain %22 %5 %19 %20 %21 %20 %20
+%25 = OpLoad %12 %23
+%26 = OpVectorShuffle %24 %25 %25 1 0
 OpReturn
 )");