tint: Rework TypesBuilder::array() to take attribute list

Instead of having the stride be yet another integer argument, make the
stride explicit by adding an attribute list parameter. This is more
consistent with other nodes.

Bug: tint:1810
Change-Id: I916d810f29afd172b878ded48b6701e8b299b13f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119040
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc
index 1c0ecca..a0263f3 100644
--- a/src/tint/inspector/inspector_test.cc
+++ b/src/tint/inspector/inspector_test.cc
@@ -2099,12 +2099,16 @@
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
     // Manually create uniform buffer to make sure it had a valid layout (array
     // with elem stride of 16, and that is 16-byte aligned within the struct)
-    auto* foo_struct_type = Structure(
-        "foo_type",
-        utils::Vector{
-            Member("0i32", ty.i32()),
-            Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), utils::Vector{MemberAlign(16_i)}),
-        });
+    auto* foo_struct_type = Structure("foo_type", utils::Vector{
+                                                      Member("0i32", ty.i32()),
+                                                      Member("b",
+                                                             ty.array<u32, 4>(utils::Vector{
+                                                                 Stride(16),
+                                                             }),
+                                                             utils::Vector{
+                                                                 MemberAlign(16_i),
+                                                             }),
+                                                  });
 
     AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
 
@@ -3442,7 +3446,9 @@
     // from the 4-element array with 16-byte stride.
     auto* wg_struct_type = MakeStructType("WgStruct", utils::Vector{
                                                           ty.i32(),
-                                                          ty.array(ty.i32(), 4_u, /*stride=*/16),
+                                                          ty.array<i32, 4>(utils::Vector{
+                                                              Stride(16),
+                                                          }),
                                                       });
     AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
     MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 4bfb8bb..396a060 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -829,85 +829,48 @@
         /// @param subtype the array element type
         /// @param n the array size. nullptr represents a runtime-array
         /// @param attrs the optional attributes for the array
-        /// @return the tint AST type for a array of size `n` of type `T`
-        template <typename EXPR = ast::Expression*>
+        /// @return the array of size `n` of type `T`
+        template <typename COUNT = std::nullptr_t>
         const ast::Array* array(
             const ast::Type* subtype,
-            EXPR&& n = nullptr,
+            COUNT&& n = nullptr,
             utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            return builder->create<ast::Array>(subtype, builder->Expr(std::forward<EXPR>(n)),
-                                               std::move(attrs));
+            return array(builder->source_, subtype, std::forward<COUNT>(n), std::move(attrs));
         }
 
         /// @param source the Source of the node
         /// @param subtype the array element type
         /// @param n the array size. nullptr represents a runtime-array
         /// @param attrs the optional attributes for the array
-        /// @return the tint AST type for a array of size `n` of type `T`
-        template <typename EXPR = ast::Expression*>
+        /// @return the array of size `n` of type `T`
+        template <typename COUNT = std::nullptr_t>
         const ast::Array* array(
             const Source& source,
             const ast::Type* subtype,
-            EXPR&& n = nullptr,
+            COUNT&& n = nullptr,
             utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            return builder->create<ast::Array>(
-                source, subtype, builder->Expr(std::forward<EXPR>(n)), std::move(attrs));
-        }
-
-        /// @param subtype the array element type
-        /// @param n the array size. nullptr represents a runtime-array
-        /// @param stride the array stride. 0 represents implicit stride
-        /// @return the tint AST type for a array of size `n` of type `T`
-        template <typename EXPR>
-        const ast::Array* array(const ast::Type* subtype, EXPR&& n, uint32_t stride) const {
-            utils::Vector<const ast::Attribute*, 2> attrs;
-            if (stride) {
-                attrs.Push(builder->create<ast::StrideAttribute>(stride));
+            if constexpr (std::is_same_v<traits::Decay<COUNT>, std::nullptr_t>) {
+                return builder->create<ast::Array>(source, subtype, nullptr, std::move(attrs));
+            } else {
+                return builder->create<ast::Array>(
+                    source, subtype, builder->Expr(std::forward<COUNT>(n)), std::move(attrs));
             }
-            return array(subtype, std::forward<EXPR>(n), std::move(attrs));
         }
 
-        /// @param source the Source of the node
-        /// @param subtype the array element type
-        /// @param n the array size. nullptr represents a runtime-array
-        /// @param stride the array stride. 0 represents implicit stride
-        /// @return the tint AST type for a array of size `n` of type `T`
-        template <typename EXPR>
-        const ast::Array* array(const Source& source,
-                                const ast::Type* subtype,
-                                EXPR&& n,
-                                uint32_t stride) const {
-            utils::Vector<const ast::Attribute*, 2> attrs;
-            if (stride) {
-                attrs.Push(builder->create<ast::StrideAttribute>(stride));
-            }
-            return array(source, subtype, std::forward<EXPR>(n), std::move(attrs));
-        }
-
-        /// @return the tint AST type for a runtime-sized array of type `T`
+        /// @param attrs the optional attributes for the array
+        /// @return the runtime-sized array of type `T`
         template <typename T>
-        const ast::Array* array() const {
-            return array(Of<T>(), nullptr);
+        const ast::Array* array(
+            utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
+            return array(Of<T>(), nullptr, std::move(attrs));
         }
 
-        /// @return the tint AST type for an array of size `N` of type `T`
+        /// @param attrs the optional attributes for the array
+        /// @return the array of size `N` of type `T`
         template <typename T, int N>
-        const ast::Array* array() const {
-            return array(Of<T>(), builder->Expr(tint::u32(N)));
-        }
-
-        /// @param stride the array stride
-        /// @return the tint AST type for a runtime-sized array of type `T`
-        template <typename T>
-        const ast::Array* array(uint32_t stride) const {
-            return array(Of<T>(), nullptr, stride);
-        }
-
-        /// @param stride the array stride
-        /// @return the tint AST type for an array of size `N` of type `T`
-        template <typename T, int N>
-        const ast::Array* array(uint32_t stride) const {
-            return array(Of<T>(), builder->Expr(tint::u32(N)), stride);
+        const ast::Array* array(
+            utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
+            return array(Of<T>(), tint::u32(N), std::move(attrs));
         }
 
         /// Creates a type name
@@ -2457,6 +2420,13 @@
         return create<ast::StructMemberAlignAttribute>(source_, Expr(std::forward<EXPR>(val)));
     }
 
+    /// Creates a ast::StrideAttribute
+    /// @param stride the array stride
+    /// @returns the ast::StrideAttribute attribute
+    const ast::StrideAttribute* Stride(uint32_t stride) {
+        return create<ast::StrideAttribute>(source_, stride);
+    }
+
     /// Creates the ast::GroupAttribute
     /// @param value group attribute index expresion
     /// @returns the group attribute pointer
diff --git a/src/tint/reader/spirv/parser_type.cc b/src/tint/reader/spirv/parser_type.cc
index 10fd5b0..e1f2bbf 100644
--- a/src/tint/reader/spirv/parser_type.cc
+++ b/src/tint/reader/spirv/parser_type.cc
@@ -210,9 +210,17 @@
 
 const ast::Type* Array::Build(ProgramBuilder& b) const {
     if (size > 0) {
-        return b.ty.array(type->Build(b), u32(size), stride);
+        if (stride > 0) {
+            return b.ty.array(type->Build(b), u32(size), utils::Vector{b.Stride(stride)});
+        } else {
+            return b.ty.array(type->Build(b), u32(size));
+        }
     } else {
-        return b.ty.array(type->Build(b), nullptr, stride);
+        if (stride > 0) {
+            return b.ty.array(type->Build(b), nullptr, utils::Vector{b.Stride(stride)});
+        } else {
+            return b.ty.array(type->Build(b), nullptr);
+        }
     }
 }
 
diff --git a/src/tint/resolver/address_space_layout_validation_test.cc b/src/tint/resolver/address_space_layout_validation_test.cc
index e62bafb..4a2411b 100644
--- a/src/tint/resolver/address_space_layout_validation_test.cc
+++ b/src/tint/resolver/address_space_layout_validation_test.cc
@@ -161,7 +161,7 @@
     //
     // @group(0) @binding(0)
     // var<uniform> a : Outer;
-    Alias("Inner", ty.array(ty.f32(), 10_u, 16));
+    Alias("Inner", ty.array<f32, 10>(utils::Vector{Stride(16)}));
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
@@ -194,7 +194,7 @@
     //
     // @group(0) @binding(0)
     // var<uniform> a : Outer;
-    Alias("Inner", ty.array(ty.f32(), 10_u, 16));
+    Alias("Inner", ty.array<f32, 10>(utils::Vector{Stride(16)}));
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
@@ -396,7 +396,7 @@
     // @group(0) @binding(0)
     // var<uniform> a : Outer;
 
-    Alias("Inner", ty.array(ty.f32(), 10_u));
+    Alias("Inner", ty.array<f32, 10>());
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
@@ -518,7 +518,7 @@
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
-                  Member("inner", ty.array(Source{{34, 56}}, ty.array(ty.f32(), 4_u), 4_u)),
+                  Member("inner", ty.array(Source{{34, 56}}, ty.array<f32, 4>(), 4_u)),
               });
 
     GlobalVar(Source{{78, 90}}, "a", ty("Outer"), type::AddressSpace::kUniform, Group(0_a),
@@ -546,7 +546,7 @@
     // @group(0) @binding(0)
     // var<uniform> a : Outer;
 
-    Alias("Inner", ty.array(ty.f32(), 10_u, 16));
+    Alias("Inner", ty.array<f32, 10>(utils::Vector{Stride(16)}));
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
diff --git a/src/tint/resolver/assignment_validation_test.cc b/src/tint/resolver/assignment_validation_test.cc
index f868d42..642340b 100644
--- a/src/tint/resolver/assignment_validation_test.cc
+++ b/src/tint/resolver/assignment_validation_test.cc
@@ -70,7 +70,7 @@
 
     GlobalConst("len", Expr(4_u));
 
-    auto* a = Var("a", ty.array(ty.f32(), 4_u));
+    auto* a = Var("a", ty.array<f32, 4>());
     auto* b = Var("b", ty.array(ty.f32(), "len"));
 
     auto* assign = Assign(Source{{12, 34}}, "a", "b");
@@ -89,7 +89,7 @@
 
     GlobalConst("len", Expr(5_u));
 
-    auto* a = Var("a", ty.array(ty.f32(), 4_u));
+    auto* a = Var("a", ty.array<f32, 4>());
     auto* b = Var("b", ty.array(ty.f32(), "len"));
 
     auto* assign = Assign(Source{{12, 34}}, "a", "b");
diff --git a/src/tint/resolver/atomics_validation_test.cc b/src/tint/resolver/atomics_validation_test.cc
index f8f66a7..f57cf0b 100644
--- a/src/tint/resolver/atomics_validation_test.cc
+++ b/src/tint/resolver/atomics_validation_test.cc
@@ -173,7 +173,7 @@
     // var<private> g : S0;
 
     auto* atomic_array = Alias("AtomicArray", ty.atomic(ty.i32()));
-    auto* array_i32_4 = ty.array(ty.i32(), 4_u);
+    auto* array_i32_4 = ty.array<i32, 4>();
     auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8_u);
     auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4_u);
 
@@ -272,7 +272,7 @@
     // var<storage, read> g : S0;
 
     auto* atomic_array = Alias("AtomicArray", ty.atomic(ty.i32()));
-    auto* array_i32_4 = ty.array(ty.i32(), 4_u);
+    auto* array_i32_4 = ty.array<i32, 4>();
     auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8_u);
     auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4_u);
 
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index 4dfc3a3..a584915 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -1286,7 +1286,7 @@
     GlobalVar(Sym(), ty.i32());
     GlobalVar(Sym(), ty.u32());
     GlobalVar(Sym(), ty.f32());
-    GlobalVar(Sym(), ty.array(T, V, 4));
+    GlobalVar(Sym(), ty.array(T, V));
     GlobalVar(Sym(), ty.vec3(T));
     GlobalVar(Sym(), ty.mat3x2(T));
     GlobalVar(Sym(), ty.pointer(T, type::AddressSpace::kPrivate));
diff --git a/src/tint/resolver/increment_decrement_validation_test.cc b/src/tint/resolver/increment_decrement_validation_test.cc
index 9f41f3a..7cca736 100644
--- a/src/tint/resolver/increment_decrement_validation_test.cc
+++ b/src/tint/resolver/increment_decrement_validation_test.cc
@@ -72,9 +72,9 @@
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ThroughArray) {
-    // var a : array<i32, 4_u>;
+    // var a : array<i32, 4u>;
     // a[1i]++;
-    auto* var_a = Var("a", ty.array(ty.i32(), 4_u));
+    auto* var_a = Var("a", ty.array<i32, 4>());
     WrapInFunction(var_a, Increment(Source{{12, 34}}, IndexAccessor("a", 1_i)));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index f3a2a6d..f6c8ef2 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -134,7 +134,7 @@
 INSTANTIATE_TEST_SUITE_P(ResolverTest, ResolverInferredTypeParamTest, testing::ValuesIn(all_cases));
 
 TEST_F(ResolverInferredTypeTest, InferArray_Pass) {
-    auto* type = ty.array(ty.u32(), 10_u);
+    auto* type = ty.array<u32, 10>();
     auto* expected_type = create<type::Array>(
         create<type::U32>(), create<type::ConstantArrayCount>(10u), 4u, 4u * 10u, 4u, 4u);
 
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index 728525d..21425da 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -2063,8 +2063,8 @@
 
 // Test for crbug.com/tint/728
 TEST_F(ResolverTest, ASTNodesAreReached) {
-    Structure("A", utils::Vector{Member("x", ty.array<f32, 4>(4))});
-    Structure("B", utils::Vector{Member("x", ty.array<f32, 4>(4))});
+    Structure("A", utils::Vector{Member("x", ty.array<f32, 4>(utils::Vector{Stride(4)}))});
+    Structure("B", utils::Vector{Member("x", ty.array<f32, 4>(utils::Vector{Stride(4)}))});
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
diff --git a/src/tint/resolver/root_identifier_test.cc b/src/tint/resolver/root_identifier_test.cc
index 656b0a8..6e81e42 100644
--- a/src/tint/resolver/root_identifier_test.cc
+++ b/src/tint/resolver/root_identifier_test.cc
@@ -199,7 +199,7 @@
     // {
     //   a[2i]
     // }
-    auto* a = GlobalVar("a", ty.array(ty.f32(), 4_u), type::AddressSpace::kPrivate);
+    auto* a = GlobalVar("a", ty.array<f32, 4>(), type::AddressSpace::kPrivate);
     auto* expr = IndexAccessor(a, 2_i);
     WrapInFunction(expr);
 
diff --git a/src/tint/resolver/struct_layout_test.cc b/src/tint/resolver/struct_layout_test.cc
index 7c50a3e..8d9dee9 100644
--- a/src/tint/resolver/struct_layout_test.cc
+++ b/src/tint/resolver/struct_layout_test.cc
@@ -177,10 +177,10 @@
     Enable(ast::Extension::kF16);
 
     auto* s = Structure("S", utils::Vector{
-                                 Member("a", ty.array<i32, 3>(/*stride*/ 8)),
-                                 Member("b", ty.array<f32, 5>(/*stride*/ 16)),
-                                 Member("c", ty.array<f16, 7>(/*stride*/ 4)),
-                                 Member("d", ty.array<f32, 1>(/*stride*/ 32)),
+                                 Member("a", ty.array<i32, 3>(utils::Vector{Stride(8)})),
+                                 Member("b", ty.array<f32, 5>(utils::Vector{Stride(16)})),
+                                 Member("c", ty.array<f16, 7>(utils::Vector{Stride(4)})),
+                                 Member("d", ty.array<f32, 1>(utils::Vector{Stride(32)})),
                              });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -236,7 +236,7 @@
 
 TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
     auto* s = Structure("S", utils::Vector{
-                                 Member("c", ty.array<f32>(/*stride*/ 32)),
+                                 Member("c", ty.array<f32>(utils::Vector{Stride(32)})),
                              });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -256,8 +256,8 @@
 }
 
 TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
-    auto* inner = ty.array<i32, 2>(/*stride*/ 16);  // size: 32
-    auto* outer = ty.array(inner, 12_u);            // size: 12 * 32
+    auto* inner = ty.array<i32, 2>(utils::Vector{Stride(16)});  // size: 32
+    auto* outer = ty.array(inner, 12_u);                        // size: 12 * 32
     auto* s = Structure("S", utils::Vector{
                                  Member("c", outer),
                              });
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index d8c1630..b4e83c3 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -383,7 +383,8 @@
 
 TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
     // var<private> a : @stride(8000000) array<f32, 65535>;
-    GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 65535_a), 8000000),
+    GlobalVar("a",
+              ty.array(ty.f32(), Expr(Source{{12, 34}}, 65535_a), utils::Vector{Stride(8000000)}),
               type::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -874,7 +875,8 @@
 
 TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableTypeWithStride) {
     auto* ptr_ty = ty.pointer<u32>(Source{{12, 34}}, type::AddressSpace::kUniform);
-    GlobalVar("arr", ty.array(ptr_ty, 4_i, 16), type::AddressSpace::kPrivate);
+    GlobalVar("arr", ty.array(ptr_ty, 4_i, utils::Vector{Stride(16)}),
+              type::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
diff --git a/src/tint/transform/decompose_strided_array_test.cc b/src/tint/transform/decompose_strided_array_test.cc
index 042acd7..72bc1b1 100644
--- a/src/tint/transform/decompose_strided_array_test.cc
+++ b/src/tint/transform/decompose_strided_array_test.cc
@@ -47,7 +47,11 @@
     // var<private> arr : @stride(4) array<f32, 4u>
 
     ProgramBuilder b;
-    b.GlobalVar("arr", b.ty.array<f32, 4u>(4), type::AddressSpace::kPrivate);
+    b.GlobalVar("arr",
+                b.ty.array<f32, 4u>(utils::Vector{
+                    b.Stride(4),
+                }),
+                type::AddressSpace::kPrivate);
     EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
@@ -55,7 +59,11 @@
     // var<private> arr : @stride(16) array<f32, 4u>
 
     ProgramBuilder b;
-    b.GlobalVar("arr", b.ty.array<f32, 4u>(16), type::AddressSpace::kPrivate);
+    b.GlobalVar("arr",
+                b.ty.array<f32, 4u>(utils::Vector{
+                    b.Stride(16),
+                }),
+                type::AddressSpace::kPrivate);
     EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
@@ -78,10 +86,18 @@
     // }
 
     ProgramBuilder b;
-    b.GlobalVar("arr", b.ty.array<f32, 4u>(4), type::AddressSpace::kPrivate);
+    b.GlobalVar("arr",
+                b.ty.array<f32, 4u>(utils::Vector{
+                    b.Stride(4),
+                }),
+                type::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Decl(b.Let("a", b.ty.array<f32, 4u>(4), b.Expr("arr"))),
+               b.Decl(b.Let("a",
+                            b.ty.array<f32, 4u>(utils::Vector{
+                                b.Stride(4),
+                            }),
+                            b.Expr("arr"))),
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
            },
            utils::Vector{
@@ -114,10 +130,18 @@
     // }
 
     ProgramBuilder b;
-    b.GlobalVar("arr", b.ty.array<f32, 4u>(32), type::AddressSpace::kPrivate);
+    b.GlobalVar("arr",
+                b.ty.array<f32, 4u>(utils::Vector{
+                    b.Stride(32),
+                }),
+                type::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.Expr("arr"))),
+               b.Decl(b.Let("a",
+                            b.ty.array<f32, 4u>(utils::Vector{
+                                b.Stride(32),
+                            }),
+                            b.Expr("arr"))),
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
            },
            utils::Vector{
@@ -157,11 +181,17 @@
     //   let b : f32 = s.a[1];
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(32),
+                                                           }))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("a",
+                            b.ty.array<f32, 4u>(utils::Vector{
+                                b.Stride(32),
+                            }),
+                            b.MemberAccessor("s", "a"))),
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
            },
            utils::Vector{
@@ -205,12 +235,20 @@
     //   let b : f32 = s.a[1][2];
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16))});
+    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array(b.ty.vec4<f32>(), 4_u,
+                                                                      utils::Vector{
+                                                                          b.Stride(16),
+                                                                      }))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func(
         "f", utils::Empty, b.ty.void_(),
         utils::Vector{
-            b.Decl(b.Let("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16), b.MemberAccessor("s", "a"))),
+            b.Decl(b.Let("a",
+                         b.ty.array(b.ty.vec4<f32>(), 4_u,
+                                    utils::Vector{
+                                        b.Stride(16),
+                                    }),
+                         b.MemberAccessor("s", "a"))),
             b.Decl(b.Let("b", b.ty.f32(),
                          b.IndexAccessor(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 2_i))),
         },
@@ -251,11 +289,17 @@
     //   let b : f32 = s.a[1];
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(32),
+                                                           }))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("a",
+                            b.ty.array<f32, 4u>(utils::Vector{
+                                b.Stride(32),
+                            }),
+                            b.MemberAccessor("s", "a"))),
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
            },
            utils::Vector{
@@ -299,11 +343,17 @@
     //   let b : f32 = s.a[1];
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(4))});
+    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(4),
+                                                           }))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Decl(b.Let("a", b.ty.array<f32, 4u>(4), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("a",
+                            b.ty.array<f32, 4u>(utils::Vector{
+                                b.Stride(4),
+                            }),
+                            b.MemberAccessor("s", "a"))),
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
            },
            utils::Vector{
@@ -343,14 +393,20 @@
     //   s.a[1i] = 5.0;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(32),
+                                                           }))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty.array<f32, 4u>(32))),
-               b.Assign(b.MemberAccessor("s", "a"),
-                        b.Call(b.ty.array<f32, 4u>(32), 1_f, 2_f, 3_f, 4_f)),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty.array<f32, 4u>(utils::Vector{
+                                                        b.Stride(32),
+                                                    }))),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(32),
+                                                           }),
+                                                           1_f, 2_f, 3_f, 4_f)),
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
            },
            utils::Vector{
@@ -397,14 +453,22 @@
     //   s.a[1] = 5.0;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(4))});
+    auto* S = b.Structure("S", utils::Vector{
+                                   b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
+                                                     b.Stride(4),
+                                                 })),
+                               });
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
-               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty.array<f32, 4u>(4))),
-               b.Assign(b.MemberAccessor("s", "a"),
-                        b.Call(b.ty.array<f32, 4u>(4), 1_f, 2_f, 3_f, 4_f)),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty.array<f32, 4u>(utils::Vector{
+                                                        b.Stride(4),
+                                                    }))),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(4),
+                                                           }),
+                                                           1_f, 2_f, 3_f, 4_f)),
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
            },
            utils::Vector{
@@ -449,7 +513,9 @@
     //   (*b)[1] = 5.0;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(32))});
+    auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty.array<f32, 4u>(utils::Vector{
+                                                               b.Stride(32),
+                                                           }))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
@@ -458,7 +524,10 @@
                b.Decl(b.Let("b", b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
                b.Decl(b.Let("c", b.Deref("b"))),
                b.Decl(b.Let("d", b.IndexAccessor(b.Deref("b"), 1_i))),
-               b.Assign(b.Deref("b"), b.Call(b.ty.array<f32, 4u>(32), 1_f, 2_f, 3_f, 4_f)),
+               b.Assign(b.Deref("b"), b.Call(b.ty.array<f32, 4u>(utils::Vector{
+                                                 b.Stride(32),
+                                             }),
+                                             1_f, 2_f, 3_f, 4_f)),
                b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), 5_f),
            },
            utils::Vector{
@@ -509,7 +578,9 @@
     //   s.a[1] = 5.0;
     // }
     ProgramBuilder b;
-    b.Alias("ARR", b.ty.array<f32, 4u>(32));
+    b.Alias("ARR", b.ty.array<f32, 4u>(utils::Vector{
+                       b.Stride(32),
+                   }));
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty("ARR"))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
@@ -517,8 +588,8 @@
            utils::Vector{
                b.Decl(b.Let("a", b.ty("ARR"), b.MemberAccessor("s", "a"))),
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
-               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty("ARR"))),
-               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty("ARR"), 1_f, 2_f, 3_f, 4_f)),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call("ARR")),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call("ARR", 1_f, 2_f, 3_f, 4_f)),
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
            },
            utils::Vector{
@@ -574,18 +645,29 @@
     // }
 
     ProgramBuilder b;
-    b.Alias("ARR_A", b.ty.array<f32, 2>(8));
-    b.Alias("ARR_B",
-            b.ty.array(                              //
-                b.ty.array(b.ty("ARR_A"), 3_u, 16),  //
-                4_u, 128));
+    b.Alias("ARR_A", b.ty.array<f32, 2>(utils::Vector{
+                         b.Stride(8),
+                     }));
+    b.Alias("ARR_B", b.ty.array(  //
+                         b.ty.array(b.ty("ARR_A"), 3_u,
+                                    utils::Vector{
+                                        b.Stride(16),
+                                    }),
+                         4_u,
+                         utils::Vector{
+                             b.Stride(128),
+                         }));
     auto* S = b.Structure("S", utils::Vector{b.Member("a", b.ty("ARR_B"))});
     b.GlobalVar("s", b.ty.Of(S), type::AddressSpace::kStorage, type::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("a", b.ty("ARR_B"), b.MemberAccessor("s", "a"))),
-               b.Decl(b.Let("b", b.ty.array(b.ty("ARR_A"), 3_u, 16),
+               b.Decl(b.Let("b",
+                            b.ty.array(b.ty("ARR_A"), 3_u,
+                                       utils::Vector{
+                                           b.Stride(16),
+                                       }),
                             b.IndexAccessor(                 //
                                 b.MemberAccessor("s", "a"),  //
                                 3_i))),
@@ -603,7 +685,7 @@
                                         3_i),
                                     2_i),
                                 1_i))),
-               b.Assign(b.MemberAccessor("s", "a"), b.Call(b.ty("ARR_B"))),
+               b.Assign(b.MemberAccessor("s", "a"), b.Call("ARR_B")),
                b.Assign(b.IndexAccessor(                         //
                             b.IndexAccessor(                     //
                                 b.IndexAccessor(                 //
diff --git a/src/tint/transform/decompose_strided_matrix.cc b/src/tint/transform/decompose_strided_matrix.cc
index d5a4ea2..8b72ac2 100644
--- a/src/tint/transform/decompose_strided_matrix.cc
+++ b/src/tint/transform/decompose_strided_matrix.cc
@@ -40,7 +40,10 @@
     /// @returns a new ast::Array that holds an vector column for each row of the
     /// matrix.
     const ast::Array* array(ProgramBuilder* b) const {
-        return b->ty.array(b->ty.vec<f32>(matrix->rows()), u32(matrix->columns()), stride);
+        return b->ty.array(b->ty.vec<f32>(matrix->rows()), u32(matrix->columns()),
+                           utils::Vector{
+                               b->Stride(stride),
+                           });
     }
 
     /// Equality operator
diff --git a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
index 358373b..ebccf27 100644
--- a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
@@ -359,7 +359,7 @@
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array<i32, 5>(4)),
+        Member("a", ty.array<i32, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -404,7 +404,7 @@
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array<i32, 5>(4)),
+        Member("a", ty.array<i32, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -454,7 +454,7 @@
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array<i32, 5>(4)),
+        Member("a", ty.array<i32, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -507,7 +507,7 @@
                                      });
 
     SetupStorageBuffer(utils::Vector{
-        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+        Member("c", ty.array(ty.Of(inner), 4_u)),
     });
 
     SetupFunction(utils::Vector{
@@ -566,7 +566,7 @@
                                      });
 
     SetupStorageBuffer(utils::Vector{
-        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+        Member("c", ty.array(ty.Of(inner), 4_u)),
     });
 
     SetupFunction(utils::Vector{
@@ -628,7 +628,7 @@
                                      });
 
     SetupStorageBuffer(utils::Vector{
-        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+        Member("c", ty.array(ty.Of(inner), 4_u)),
     });
 
     SetupFunction(utils::Vector{
@@ -689,7 +689,7 @@
                                      });
 
     SetupStorageBuffer(utils::Vector{
-        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+        Member("c", ty.array(ty.Of(inner), 4_u)),
     });
 
     SetupFunction(utils::Vector{
@@ -750,7 +750,7 @@
                                      });
 
     SetupStorageBuffer(utils::Vector{
-        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+        Member("c", ty.array(ty.Of(inner), 4_u)),
     });
 
     SetupFunction(utils::Vector{
@@ -810,7 +810,7 @@
                                      });
 
     SetupStorageBuffer(utils::Vector{
-        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+        Member("c", ty.array(ty.Of(inner), 4_u)),
     });
 
     SetupFunction(utils::Vector{
diff --git a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
index f232811..051d8e0 100644
--- a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
@@ -25,7 +25,7 @@
 using GlslSanitizerTest = TestHelper;
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
 
@@ -64,7 +64,7 @@
 TEST_F(GlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member(0, "z", ty.f32()),
-                                         Member(4, "a", ty.array<f32>(4)),
+                                         Member(4, "a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
@@ -104,7 +104,7 @@
 }
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength_ViaLets) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
 
diff --git a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
index d4dc440..94f96a8 100644
--- a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -1299,7 +1299,7 @@
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array(ty.i32(), 5_i)),
+        Member("a", ty.array<i32, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -1468,7 +1468,7 @@
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array(ty.i32(), 5_i)),
+        Member("a", ty.array<i32, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -1545,7 +1545,7 @@
 
     SetupStorageBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array(ty.i32(), 5_i)),
+        Member("a", ty.array<i32, 5>()),
     });
 
     SetupFunction(utils::Vector{
diff --git a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
index cede53c..961a27b 100644
--- a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -25,7 +25,7 @@
 using HlslSanitizerTest = TestHelper;
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
 
@@ -58,7 +58,7 @@
 TEST_F(HlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member(0, "z", ty.f32()),
-                                         Member(4, "a", ty.array<f32>(4)),
+                                         Member(4, "a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
@@ -91,7 +91,7 @@
 }
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_ViaLets) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
 
@@ -128,7 +128,7 @@
 }
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>())});
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
     GlobalVar("c", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(2_a),
diff --git a/src/tint/writer/msl/generator_impl_sanitizer_test.cc b/src/tint/writer/msl/generator_impl_sanitizer_test.cc
index 1a0ce77..fda5296 100644
--- a/src/tint/writer/msl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/msl/generator_impl_sanitizer_test.cc
@@ -27,7 +27,9 @@
 using MslSanitizerTest = TestHelper;
 
 TEST_F(MslSanitizerTest, Call_ArrayLength) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{
+                                         Member(0, "a", ty.array<f32>()),
+                                     });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
 
@@ -80,7 +82,7 @@
 TEST_F(MslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member(0, "z", ty.f32()),
-                                         Member(4, "a", ty.array<f32>(4)),
+                                         Member(4, "a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
@@ -134,7 +136,9 @@
 }
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ViaLets) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{
+                                         Member(0, "a", ty.array<f32>()),
+                                     });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
 
@@ -191,7 +195,9 @@
 }
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{
+                                         Member(0, "a", ty.array<f32>()),
+                                     });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(0_a));
     GlobalVar("c", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(2_a),
@@ -250,7 +256,9 @@
 }
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniformMissingBinding) {
-    auto* s = Structure("my_struct", utils::Vector{Member(0, "a", ty.array<f32>(4))});
+    auto* s = Structure("my_struct", utils::Vector{
+                                         Member(0, "a", ty.array<f32>()),
+                                     });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(0_a));
     GlobalVar("c", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(2_a),
diff --git a/src/tint/writer/spirv/builder_builtin_test.cc b/src/tint/writer/spirv/builder_builtin_test.cc
index 057aa7d..63c3990 100644
--- a/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_test.cc
@@ -276,7 +276,7 @@
 
 TEST_F(BuiltinBuilderTest, Call_ArrayLength) {
     auto* s = Structure("my_struct", utils::Vector{
-                                         Member("a", ty.array<f32>(4)),
+                                         Member("a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
@@ -320,7 +320,7 @@
 TEST_F(BuiltinBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
     auto* s = Structure("my_struct", utils::Vector{
                                          Member("z", ty.f32()),
-                                         Member(4, "a", ty.array<f32>(4)),
+                                         Member(4, "a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
@@ -363,7 +363,7 @@
 
 TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets) {
     auto* s = Structure("my_struct", utils::Vector{
-                                         Member("a", ty.array<f32>(4)),
+                                         Member("a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
@@ -422,7 +422,7 @@
     //   arrayLength(&*p3);
     // }
     auto* s = Structure("my_struct", utils::Vector{
-                                         Member("a", ty.array<f32>(4)),
+                                         Member("a", ty.array<f32>()),
                                      });
     GlobalVar("b", ty.Of(s), type::AddressSpace::kStorage, type::Access::kRead, Binding(1_a),
               Group(2_a));
diff --git a/src/tint/writer/spirv/builder_type_test.cc b/src/tint/writer/spirv/builder_type_test.cc
index d80bdc4..81c51a2 100644
--- a/src/tint/writer/spirv/builder_type_test.cc
+++ b/src/tint/writer/spirv/builder_type_test.cc
@@ -61,7 +61,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateArray) {
-    auto* ary = ty.array(ty.i32(), 4_u);
+    auto* ary = ty.array<i32, 4>();
     GlobalVar("a", ary, type::AddressSpace::kPrivate);
 
     spirv::Builder& b = Build();
@@ -78,7 +78,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
-    auto* ary = ty.array(ty.i32(), 4_u, 16u);
+    auto* ary = ty.array<i32, 4>(utils::Vector{Stride(16)});
     GlobalVar("a", ary, type::AddressSpace::kPrivate);
 
     spirv::Builder& b = Build();
@@ -98,7 +98,7 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
-    auto* ary = ty.array(ty.i32(), 4_u);
+    auto* ary = ty.array<i32, 4>();
     GlobalVar("a", ary, type::AddressSpace::kPrivate);
 
     spirv::Builder& b = Build();
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index cd2c7f0..ee798b8 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -49,7 +49,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Array_Attribute) {
-    auto* a = ty.array(ty.bool_(), 4_u, 16u);
+    auto* a = ty.array(ty.bool_(), 4_u, utils::Vector{Stride(16)});
     Alias("make_type_reachable", a);
 
     GeneratorImpl& gen = Build();