Replace Type::(Is|As)Array with Castable

Change-Id: I8d9b916f5977121380325d373c4e2f805b691fae
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34264
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/type/access_control_type_test.cc b/src/ast/type/access_control_type_test.cc
index 523bd36..652e3b8 100644
--- a/src/ast/type/access_control_type_test.cc
+++ b/src/ast/type/access_control_type_test.cc
@@ -50,7 +50,7 @@
   Type* ty = &at;
   EXPECT_TRUE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/alias_type_test.cc b/src/ast/type/alias_type_test.cc
index e54b165..67e7473 100644
--- a/src/ast/type/alias_type_test.cc
+++ b/src/ast/type/alias_type_test.cc
@@ -51,7 +51,7 @@
   Type* ty = &at;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_TRUE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/array_type.cc b/src/ast/type/array_type.cc
index 4a7b64d..4bdaf1b 100644
--- a/src/ast/type/array_type.cc
+++ b/src/ast/type/array_type.cc
@@ -32,10 +32,6 @@
 
 ArrayType::~ArrayType() = default;
 
-bool ArrayType::IsArray() const {
-  return true;
-}
-
 uint64_t ArrayType::MinBufferBindingSize(MemoryLayout mem_layout) const {
   if (!has_array_stride()) {
     // Arrays in buffers are required to have a stride.
diff --git a/src/ast/type/array_type.h b/src/ast/type/array_type.h
index 8633f18..5341bf5 100644
--- a/src/ast/type/array_type.h
+++ b/src/ast/type/array_type.h
@@ -41,8 +41,6 @@
   ArrayType(ArrayType&&);
   ~ArrayType() override;
 
-  /// @returns true if the type is an array type
-  bool IsArray() const override;
   /// @returns true if this is a runtime array.
   /// i.e. the size is determined at runtime
   bool IsRuntimeArray() const { return size_ == 0; }
diff --git a/src/ast/type/array_type_test.cc b/src/ast/type/array_type_test.cc
index 12c486c..84cb3bd 100644
--- a/src/ast/type/array_type_test.cc
+++ b/src/ast/type/array_type_test.cc
@@ -35,7 +35,7 @@
   ArrayType arr{&u32, 3};
   EXPECT_EQ(arr.type(), &u32);
   EXPECT_EQ(arr.size(), 3u);
-  EXPECT_TRUE(arr.IsArray());
+  EXPECT_TRUE(arr.Is<ArrayType>());
   EXPECT_FALSE(arr.IsRuntimeArray());
 }
 
@@ -44,7 +44,7 @@
   ArrayType arr{&u32};
   EXPECT_EQ(arr.type(), &u32);
   EXPECT_EQ(arr.size(), 0u);
-  EXPECT_TRUE(arr.IsArray());
+  EXPECT_TRUE(arr.Is<ArrayType>());
   EXPECT_TRUE(arr.IsRuntimeArray());
 }
 
@@ -55,7 +55,7 @@
   Type* ty = &arr;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_TRUE(ty->IsArray());
+  EXPECT_TRUE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/bool_type_test.cc b/src/ast/type/bool_type_test.cc
index 3775a2c..2b674b2 100644
--- a/src/ast/type/bool_type_test.cc
+++ b/src/ast/type/bool_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 
 namespace tint {
 namespace ast {
@@ -29,7 +30,7 @@
   Type* ty = &b;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_TRUE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/depth_texture_type_test.cc b/src/ast/type/depth_texture_type_test.cc
index a06af27..0d19918 100644
--- a/src/ast/type/depth_texture_type_test.cc
+++ b/src/ast/type/depth_texture_type_test.cc
@@ -17,6 +17,7 @@
 #include "src/ast/test_helper.h"
 
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 
 namespace tint {
 namespace ast {
@@ -30,7 +31,7 @@
   Type* ty = &d;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/f32_type_test.cc b/src/ast/type/f32_type_test.cc
index 93cd1ca..f48c070 100644
--- a/src/ast/type/f32_type_test.cc
+++ b/src/ast/type/f32_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 
 namespace tint {
 namespace ast {
@@ -29,7 +30,7 @@
   Type* ty = &f;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_TRUE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/i32_type_test.cc b/src/ast/type/i32_type_test.cc
index 11dbd96..7e7b086 100644
--- a/src/ast/type/i32_type_test.cc
+++ b/src/ast/type/i32_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 
 namespace tint {
 namespace ast {
@@ -29,7 +30,7 @@
   Type* ty = &i;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_TRUE(ty->IsI32());
diff --git a/src/ast/type/matrix_type_test.cc b/src/ast/type/matrix_type_test.cc
index 1990dcc..bc2791e 100644
--- a/src/ast/type/matrix_type_test.cc
+++ b/src/ast/type/matrix_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/i32_type.h"
 
 namespace tint {
@@ -39,7 +40,7 @@
   Type* ty = &m;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/multisampled_texture_type_test.cc b/src/ast/type/multisampled_texture_type_test.cc
index 7a7a54d..f11e8ce 100644
--- a/src/ast/type/multisampled_texture_type_test.cc
+++ b/src/ast/type/multisampled_texture_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/f32_type.h"
 
 namespace tint {
@@ -31,7 +32,7 @@
   Type* ty = &s;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/pointer_type_test.cc b/src/ast/type/pointer_type_test.cc
index 9014cce..8aeb8cd 100644
--- a/src/ast/type/pointer_type_test.cc
+++ b/src/ast/type/pointer_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/i32_type.h"
 
 namespace tint {
@@ -38,7 +39,7 @@
   Type* ty = &p;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/sampled_texture_type_test.cc b/src/ast/type/sampled_texture_type_test.cc
index a8f41d7..dd08506 100644
--- a/src/ast/type/sampled_texture_type_test.cc
+++ b/src/ast/type/sampled_texture_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/f32_type.h"
 
 namespace tint {
@@ -31,7 +32,7 @@
   Type* ty = &s;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/sampler_type_test.cc b/src/ast/type/sampler_type_test.cc
index 2189e92..db11115 100644
--- a/src/ast/type/sampler_type_test.cc
+++ b/src/ast/type/sampler_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 
 namespace tint {
 namespace ast {
@@ -40,7 +41,7 @@
   Type* ty = &s;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/storage_texture_type_test.cc b/src/ast/type/storage_texture_type_test.cc
index ed6bbe0..47afe0d 100644
--- a/src/ast/type/storage_texture_type_test.cc
+++ b/src/ast/type/storage_texture_type_test.cc
@@ -19,6 +19,7 @@
 #include "src/ast/identifier_expression.h"
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/type_determiner.h"
 
 namespace tint {
@@ -34,7 +35,7 @@
   Type* ty = &s;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/struct_type_test.cc b/src/ast/type/struct_type_test.cc
index 05378ea..3c1ba83 100644
--- a/src/ast/type/struct_type_test.cc
+++ b/src/ast/type/struct_type_test.cc
@@ -47,7 +47,7 @@
   Type* ty = &s;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/type.cc b/src/ast/type/type.cc
index 41634fb..45dcc0f 100644
--- a/src/ast/type/type.cc
+++ b/src/ast/type/type.cc
@@ -66,10 +66,6 @@
   return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
 }
 
-bool Type::IsArray() const {
-  return false;
-}
-
 bool Type::IsBool() const {
   return false;
 }
@@ -166,11 +162,6 @@
   return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
 }
 
-const ArrayType* Type::AsArray() const {
-  assert(IsArray());
-  return static_cast<const ArrayType*>(this);
-}
-
 const BoolType* Type::AsBool() const {
   assert(IsBool());
   return static_cast<const BoolType*>(this);
@@ -226,11 +217,6 @@
   return static_cast<const VoidType*>(this);
 }
 
-ArrayType* Type::AsArray() {
-  assert(IsArray());
-  return static_cast<ArrayType*>(this);
-}
-
 BoolType* Type::AsBool() {
   assert(IsBool());
   return static_cast<BoolType*>(this);
diff --git a/src/ast/type/type.h b/src/ast/type/type.h
index 04905c9..7993f42 100644
--- a/src/ast/type/type.h
+++ b/src/ast/type/type.h
@@ -23,7 +23,6 @@
 namespace ast {
 namespace type {
 
-class ArrayType;
 class BoolType;
 class F32Type;
 class I32Type;
@@ -46,8 +45,6 @@
   Type(Type&&);
   ~Type() override;
 
-  /// @returns true if the type is an array type
-  virtual bool IsArray() const;
   /// @returns true if the type is a bool type
   virtual bool IsBool() const;
   /// @returns true if the type is an f32 type
@@ -125,8 +122,6 @@
   /// @returns true if this type is an integer scalar or vector
   bool is_integer_scalar_or_vector();
 
-  /// @returns the type as an array type
-  const ArrayType* AsArray() const;
   /// @returns the type as a bool type
   const BoolType* AsBool() const;
   /// @returns the type as a f32 type
@@ -150,8 +145,6 @@
   /// @returns the type as a void type
   const VoidType* AsVoid() const;
 
-  /// @returns the type as an array type
-  ArrayType* AsArray();
   /// @returns the type as a bool type
   BoolType* AsBool();
   /// @returns the type as a f32 type
diff --git a/src/ast/type/u32_type_test.cc b/src/ast/type/u32_type_test.cc
index 1a2450f..d764f38 100644
--- a/src/ast/type/u32_type_test.cc
+++ b/src/ast/type/u32_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 
 namespace tint {
 namespace ast {
@@ -29,7 +30,7 @@
   Type* ty = &u;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/ast/type/vector_type_test.cc b/src/ast/type/vector_type_test.cc
index c8a4188..cbbdd73 100644
--- a/src/ast/type/vector_type_test.cc
+++ b/src/ast/type/vector_type_test.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/test_helper.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/i32_type.h"
 
 namespace tint {
@@ -38,7 +39,7 @@
   Type* ty = &v;
   EXPECT_FALSE(ty->Is<AccessControlType>());
   EXPECT_FALSE(ty->Is<AliasType>());
-  EXPECT_FALSE(ty->IsArray());
+  EXPECT_FALSE(ty->Is<ArrayType>());
   EXPECT_FALSE(ty->IsBool());
   EXPECT_FALSE(ty->IsF32());
   EXPECT_FALSE(ty->IsI32());
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index 7e7bb15..2eba14f 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -383,8 +383,8 @@
       base_type = texture_type->AsSampled()->type()->UnwrapIfNeeded();
     }
 
-    if (base_type->IsArray()) {
-      base_type = base_type->AsArray()->type();
+    if (base_type->Is<ast::type::ArrayType>()) {
+      base_type = base_type->As<ast::type::ArrayType>()->type();
     } else if (base_type->IsMatrix()) {
       base_type = base_type->AsMatrix()->type();
     } else if (base_type->IsVector()) {
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index d0b86e0..3fe9599 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1371,8 +1371,8 @@
     return create<ast::TypeConstructorExpression>(type,
                                                   std::move(ast_components));
   }
-  if (type->IsArray()) {
-    auto* arr_ty = type->AsArray();
+  if (type->Is<ast::type::ArrayType>()) {
+    auto* arr_ty = type->As<ast::type::ArrayType>();
     ast::ExpressionList ast_components;
     for (size_t i = 0; i < arr_ty->size(); ++i) {
       ast_components.emplace_back(MakeNullValue(arr_ty->type()));
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index b5e331d..b1e2110 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -35,6 +35,7 @@
 #include "src/ast/module.h"
 #include "src/ast/struct_member_decoration.h"
 #include "src/ast/type/alias_type.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/type.h"
 #include "src/reader/reader.h"
 #include "src/reader/spirv/entry_point_info.h"
diff --git a/src/reader/spirv/parser_impl_convert_type_test.cc b/src/reader/spirv/parser_impl_convert_type_test.cc
index d403ee4..3239b0a 100644
--- a/src/reader/spirv/parser_impl_convert_type_test.cc
+++ b/src/reader/spirv/parser_impl_convert_type_test.cc
@@ -338,8 +338,8 @@
 
   auto* type = p->ConvertType(10);
   ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->IsArray());
-  auto* arr_type = type->AsArray();
+  EXPECT_TRUE(type->Is<ast::type::ArrayType>());
+  auto* arr_type = type->As<ast::type::ArrayType>();
   EXPECT_TRUE(arr_type->IsRuntimeArray());
   ASSERT_NE(arr_type, nullptr);
   EXPECT_EQ(arr_type->size(), 0u);
@@ -374,7 +374,7 @@
   EXPECT_TRUE(p->BuildInternalModule());
   auto* type = p->ConvertType(10);
   ASSERT_NE(type, nullptr);
-  auto* arr_type = type->AsArray();
+  auto* arr_type = type->As<ast::type::ArrayType>();
   EXPECT_TRUE(arr_type->IsRuntimeArray());
   ASSERT_NE(arr_type, nullptr);
   EXPECT_EQ(arr_type->array_stride(), 64u);
@@ -420,8 +420,8 @@
 
   auto* type = p->ConvertType(10);
   ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->IsArray());
-  auto* arr_type = type->AsArray();
+  EXPECT_TRUE(type->Is<ast::type::ArrayType>());
+  auto* arr_type = type->As<ast::type::ArrayType>();
   EXPECT_FALSE(arr_type->IsRuntimeArray());
   ASSERT_NE(arr_type, nullptr);
   EXPECT_EQ(arr_type->size(), 42u);
@@ -508,8 +508,8 @@
 
   auto* type = p->ConvertType(10);
   ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->IsArray());
-  auto* arr_type = type->AsArray();
+  EXPECT_TRUE(type->Is<ast::type::ArrayType>());
+  auto* arr_type = type->As<ast::type::ArrayType>();
   ASSERT_NE(arr_type, nullptr);
   ASSERT_EQ(arr_type->array_stride(), 8u);
   EXPECT_TRUE(arr_type->has_array_stride());
diff --git a/src/reader/wgsl/parser_impl_global_decl_test.cc b/src/reader/wgsl/parser_impl_global_decl_test.cc
index de5bcf7..01f3635 100644
--- a/src/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_decl_test.cc
@@ -191,8 +191,8 @@
   EXPECT_FALSE(str->IsBlockDecorated());
 
   const auto* ty = str->impl()->members()[0]->type();
-  ASSERT_TRUE(ty->IsArray());
-  const auto* arr = ty->AsArray();
+  ASSERT_TRUE(ty->Is<ast::type::ArrayType>());
+  const auto* arr = ty->As<ast::type::ArrayType>();
   EXPECT_TRUE(arr->has_array_stride());
   EXPECT_EQ(arr->array_stride(), 4u);
 }
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index 9f9f8e9..96352ad 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -351,9 +351,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsArray());
+  ASSERT_TRUE(t->Is<ast::type::ArrayType>());
 
-  auto* a = t->AsArray();
+  auto* a = t->As<ast::type::ArrayType>();
   ASSERT_FALSE(a->IsRuntimeArray());
   ASSERT_EQ(a->size(), 5u);
   ASSERT_TRUE(a->type()->IsF32());
@@ -367,9 +367,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsArray());
+  ASSERT_TRUE(t->Is<ast::type::ArrayType>());
 
-  auto* a = t->AsArray();
+  auto* a = t->As<ast::type::ArrayType>();
   ASSERT_FALSE(a->IsRuntimeArray());
   ASSERT_EQ(a->size(), 5u);
   ASSERT_TRUE(a->type()->IsF32());
@@ -384,9 +384,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsArray());
+  ASSERT_TRUE(t->Is<ast::type::ArrayType>());
 
-  auto* a = t->AsArray();
+  auto* a = t->As<ast::type::ArrayType>();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsF32());
   ASSERT_TRUE(a->has_array_stride());
@@ -400,9 +400,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsArray());
+  ASSERT_TRUE(t->Is<ast::type::ArrayType>());
 
-  auto* a = t->AsArray();
+  auto* a = t->As<ast::type::ArrayType>();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsF32());
 
@@ -421,9 +421,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsArray());
+  ASSERT_TRUE(t->Is<ast::type::ArrayType>());
 
-  auto* a = t->AsArray();
+  auto* a = t->As<ast::type::ArrayType>();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsF32());
 
@@ -524,9 +524,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsArray());
+  ASSERT_TRUE(t->Is<ast::type::ArrayType>());
 
-  auto* a = t->AsArray();
+  auto* a = t->As<ast::type::ArrayType>();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsU32());
 }
diff --git a/src/transform/bound_array_accessors_transform.cc b/src/transform/bound_array_accessors_transform.cc
index b41d02b..41d4459 100644
--- a/src/transform/bound_array_accessors_transform.cc
+++ b/src/transform/bound_array_accessors_transform.cc
@@ -184,13 +184,15 @@
   }
 
   auto* ret_type = expr->array()->result_type()->UnwrapAll();
-  if (!ret_type->IsArray() && !ret_type->IsMatrix() && !ret_type->IsVector()) {
+  if (!ret_type->Is<ast::type::ArrayType>() && !ret_type->IsMatrix() &&
+      !ret_type->IsVector()) {
     return true;
   }
 
-  if (ret_type->IsVector() || ret_type->IsArray()) {
-    uint32_t size = ret_type->IsVector() ? ret_type->AsVector()->size()
-                                         : ret_type->AsArray()->size();
+  if (ret_type->IsVector() || ret_type->Is<ast::type::ArrayType>()) {
+    uint32_t size = ret_type->IsVector()
+                        ? ret_type->AsVector()->size()
+                        : ret_type->As<ast::type::ArrayType>()->size();
     if (size == 0) {
       error_ = "invalid 0 size for array or vector";
       return false;
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 36d5fbc..627138c 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -333,8 +333,8 @@
   auto* res = expr->array()->result_type();
   auto* parent_type = res->UnwrapAll();
   ast::type::Type* ret = nullptr;
-  if (parent_type->IsArray()) {
-    ret = parent_type->AsArray()->type();
+  if (parent_type->Is<ast::type::ArrayType>()) {
+    ret = parent_type->As<ast::type::ArrayType>()->type();
   } else if (parent_type->IsVector()) {
     ret = parent_type->AsVector()->type();
   } else if (parent_type->IsMatrix()) {
@@ -351,8 +351,8 @@
   if (res->IsPointer()) {
     ret = mod_->create<ast::type::PointerType>(
         ret, res->AsPointer()->storage_class());
-  } else if (parent_type->IsArray() &&
-             !parent_type->AsArray()->type()->is_scalar()) {
+  } else if (parent_type->Is<ast::type::ArrayType>() &&
+             !parent_type->As<ast::type::ArrayType>()->type()->is_scalar()) {
     // If we extract a non-scalar from an array then we also get a pointer. We
     // will generate a Function storage class variable to store this
     // into.
diff --git a/src/validator/validator_impl.cc b/src/validator/validator_impl.cc
index da38cbe..f53931b 100644
--- a/src/validator/validator_impl.cc
+++ b/src/validator/validator_impl.cc
@@ -86,8 +86,8 @@
     if (ct->IsStruct()) {
       auto* st = ct->AsStruct();
       for (auto* member : st->impl()->members()) {
-        if (member->type()->UnwrapAll()->IsArray()) {
-          auto* r = member->type()->UnwrapAll()->AsArray();
+        if (member->type()->UnwrapAll()->Is<ast::type::ArrayType>()) {
+          auto* r = member->type()->UnwrapAll()->As<ast::type::ArrayType>();
           if (r->IsRuntimeArray()) {
             if (member != st->impl()->members().back()) {
               add_error(member->source(), "v-0015",
@@ -263,8 +263,12 @@
     return false;
   }
   variable_stack_.set(name, decl->variable());
-  if (decl->variable()->type()->UnwrapAll()->IsArray()) {
-    if (decl->variable()->type()->UnwrapAll()->AsArray()->IsRuntimeArray()) {
+  if (decl->variable()->type()->UnwrapAll()->Is<ast::type::ArrayType>()) {
+    if (decl->variable()
+            ->type()
+            ->UnwrapAll()
+            ->As<ast::type::ArrayType>()
+            ->IsRuntimeArray()) {
       add_error(decl->source(), "v-0015",
                 "runtime arrays may only appear as the last "
                 "member of a struct: '" +
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index c321e91..a4d7564 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -909,7 +909,7 @@
 bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
                                         std::ostream& out,
                                         ast::TypeConstructorExpression* expr) {
-  if (expr->type()->IsArray()) {
+  if (expr->type()->Is<ast::type::ArrayType>()) {
     out << "{";
   } else {
     if (!EmitType(out, expr->type(), "")) {
@@ -938,7 +938,7 @@
     }
   }
 
-  if (expr->type()->IsArray()) {
+  if (expr->type()->Is<ast::type::ArrayType>()) {
     out << "}";
   } else {
     out << ")";
@@ -1219,7 +1219,7 @@
       return false;
     }
     // Array name is output as part of the type
-    if (!v->type()->IsArray()) {
+    if (!v->type()->Is<ast::type::ArrayType>()) {
       out << " " << v->name();
     }
   }
@@ -1718,8 +1718,8 @@
       auto* ary_type = ary->array()->result_type()->UnwrapAll();
 
       out << "(";
-      if (ary_type->IsArray()) {
-        out << ary_type->AsArray()->array_stride();
+      if (ary_type->Is<ast::type::ArrayType>()) {
+        out << ary_type->As<ast::type::ArrayType>()->array_stride();
       } else if (ary_type->IsVector()) {
         // TODO(dsinclair): This is a hack. Our vectors can only be f32, i32
         // or u32 which are all 4 bytes. When we get f16 or other types we'll
@@ -2032,21 +2032,21 @@
   if (type->Is<ast::type::AliasType>()) {
     auto* alias = type->As<ast::type::AliasType>();
     out << namer_.NameFor(alias->name());
-  } else if (type->IsArray()) {
-    auto* ary = type->AsArray();
+  } else if (type->Is<ast::type::ArrayType>()) {
+    auto* ary = type->As<ast::type::ArrayType>();
 
     ast::type::Type* base_type = ary;
     std::vector<uint32_t> sizes;
-    while (base_type->IsArray()) {
-      if (base_type->AsArray()->IsRuntimeArray()) {
+    while (base_type->Is<ast::type::ArrayType>()) {
+      if (base_type->As<ast::type::ArrayType>()->IsRuntimeArray()) {
         // TODO(dsinclair): Support runtime arrays
         // https://bugs.chromium.org/p/tint/issues/detail?id=185
         error_ = "runtime array not supported yet.";
         return false;
       } else {
-        sizes.push_back(base_type->AsArray()->size());
+        sizes.push_back(base_type->As<ast::type::ArrayType>()->size());
       }
-      base_type = base_type->AsArray()->type();
+      base_type = base_type->As<ast::type::ArrayType>()->type();
     }
     if (!EmitType(out, base_type, "")) {
       return false;
@@ -2163,7 +2163,7 @@
       return false;
     }
     // Array member name will be output with the type
-    if (!mem->type()->IsArray()) {
+    if (!mem->type()->Is<ast::type::ArrayType>()) {
       out << " " << namer_.NameFor(mem->name());
     }
     out << ";" << std::endl;
@@ -2226,7 +2226,7 @@
   if (!EmitType(out, var->type(), var->name())) {
     return false;
   }
-  if (!var->type()->IsArray()) {
+  if (!var->type()->Is<ast::type::ArrayType>()) {
     out << " " << var->name();
   }
   out << constructor_out.str() << ";" << std::endl;
@@ -2281,7 +2281,7 @@
     if (!EmitType(out, var->type(), var->name())) {
       return false;
     }
-    if (!var->type()->IsArray()) {
+    if (!var->type()->Is<ast::type::ArrayType>()) {
       out << " " << var->name();
     }
 
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 7bfb40c..1e98cc1 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -188,8 +188,8 @@
   if (type->Is<ast::type::AliasType>()) {
     return calculate_alignment_size(type->As<ast::type::AliasType>()->type());
   }
-  if (type->IsArray()) {
-    auto* ary = type->AsArray();
+  if (type->Is<ast::type::ArrayType>()) {
+    auto* ary = type->As<ast::type::ArrayType>();
     // TODO(dsinclair): Handle array stride and adjust for alignment.
     uint32_t type_size = calculate_alignment_size(ary->type());
     return ary->size() * type_size;
@@ -890,7 +890,7 @@
 }
 
 bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
-  if (expr->type()->IsArray()) {
+  if (expr->type()->Is<ast::type::ArrayType>()) {
     out_ << "{";
   } else {
     if (!EmitType(expr->type(), "")) {
@@ -919,7 +919,7 @@
     }
   }
 
-  if (expr->type()->IsArray()) {
+  if (expr->type()->Is<ast::type::ArrayType>()) {
     out_ << "}";
   } else {
     out_ << ")";
@@ -940,9 +940,9 @@
     return EmitZeroValue(type->AsVector()->type());
   } else if (type->IsMatrix()) {
     return EmitZeroValue(type->AsMatrix()->type());
-  } else if (type->IsArray()) {
+  } else if (type->Is<ast::type::ArrayType>()) {
     out_ << "{";
-    if (!EmitZeroValue(type->AsArray()->type())) {
+    if (!EmitZeroValue(type->As<ast::type::ArrayType>()->type())) {
       return false;
     }
     out_ << "}";
@@ -1308,7 +1308,7 @@
       return false;
     }
     // Array name is output as part of the type
-    if (!v->type()->IsArray()) {
+    if (!v->type()->Is<ast::type::ArrayType>()) {
       out_ << " " << v->name();
     }
   }
@@ -1790,18 +1790,18 @@
   if (type->Is<ast::type::AliasType>()) {
     auto* alias = type->As<ast::type::AliasType>();
     out_ << namer_.NameFor(alias->name());
-  } else if (type->IsArray()) {
-    auto* ary = type->AsArray();
+  } else if (type->Is<ast::type::ArrayType>()) {
+    auto* ary = type->As<ast::type::ArrayType>();
 
     ast::type::Type* base_type = ary;
     std::vector<uint32_t> sizes;
-    while (base_type->IsArray()) {
-      if (base_type->AsArray()->IsRuntimeArray()) {
+    while (base_type->Is<ast::type::ArrayType>()) {
+      if (base_type->As<ast::type::ArrayType>()->IsRuntimeArray()) {
         sizes.push_back(1);
       } else {
-        sizes.push_back(base_type->AsArray()->size());
+        sizes.push_back(base_type->As<ast::type::ArrayType>()->size());
       }
-      base_type = base_type->AsArray()->type();
+      base_type = base_type->As<ast::type::ArrayType>()->type();
     }
     if (!EmitType(base_type, "")) {
       return false;
@@ -1964,7 +1964,7 @@
     current_offset += size;
 
     // Array member name will be output with the type
-    if (!mem->type()->IsArray()) {
+    if (!mem->type()->Is<ast::type::ArrayType>()) {
       out_ << " " << namer_.NameFor(mem->name());
     }
     out_ << ";" << std::endl;
@@ -2011,7 +2011,7 @@
   if (!EmitType(var->type(), var->name())) {
     return false;
   }
-  if (!var->type()->IsArray()) {
+  if (!var->type()->Is<ast::type::ArrayType>()) {
     out_ << " " << var->name();
   }
 
@@ -2051,7 +2051,7 @@
   if (!EmitType(var->type(), var->name())) {
     return false;
   }
-  if (!var->type()->IsArray()) {
+  if (!var->type()->Is<ast::type::ArrayType>()) {
     out_ << " " << var->name();
   }
 
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index db90dcd..68b3e37 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -146,8 +146,8 @@
 /// @param type the given type, which must not be null
 /// @returns the nested matrix type, or nullptr if none
 ast::type::MatrixType* GetNestedMatrixType(ast::type::Type* type) {
-  while (type->IsArray()) {
-    type = type->AsArray()->type();
+  while (type->Is<ast::type::ArrayType>()) {
+    type = type->As<ast::type::ArrayType>()->type();
   }
   return type->IsMatrix() ? type->AsMatrix() : nullptr;
 }
@@ -818,8 +818,8 @@
   // If the source is a pointer we access chain into it. We also access chain
   // into an array of non-scalar types.
   if (info->source_type->IsPointer() ||
-      (info->source_type->IsArray() &&
-       !info->source_type->AsArray()->type()->is_scalar())) {
+      (info->source_type->Is<ast::type::ArrayType>() &&
+       !info->source_type->As<ast::type::ArrayType>()->type()->is_scalar())) {
     info->access_chain_indices.push_back(idx_id);
     info->source_type = expr->result_type();
     return true;
@@ -1008,8 +1008,8 @@
         accessors[0]->AsArrayAccessor()->array()->result_type();
 
     if (!ary_res_type->IsPointer() &&
-        (ary_res_type->IsArray() &&
-         !ary_res_type->AsArray()->type()->is_scalar())) {
+        (ary_res_type->Is<ast::type::ArrayType>() &&
+         !ary_res_type->As<ast::type::ArrayType>()->type()->is_scalar())) {
       ast::type::PointerType ptr(ary_res_type, ast::StorageClass::kFunction);
       auto result_type_id = GenerateTypeIfNeeded(&ptr);
       if (result_type_id == 0) {
@@ -1204,8 +1204,8 @@
       subtype = subtype->AsVector()->type()->UnwrapAll();
     } else if (subtype->IsMatrix()) {
       subtype = subtype->AsMatrix()->type()->UnwrapAll();
-    } else if (subtype->IsArray()) {
-      subtype = subtype->AsArray()->type()->UnwrapAll();
+    } else if (subtype->Is<ast::type::ArrayType>()) {
+      subtype = subtype->As<ast::type::ArrayType>()->type()->UnwrapAll();
     } else if (subtype->IsStruct()) {
       subtype = subtype->AsStruct()->impl()->members()[i]->type()->UnwrapAll();
     }
@@ -1280,7 +1280,7 @@
     // If the result is not a vector then we should have validated that the
     // value type is a correctly sized vector so we can just use it directly.
     if (result_type == value_type || result_type->IsMatrix() ||
-        result_type->IsArray() || result_type->IsStruct()) {
+        result_type->Is<ast::type::ArrayType>() || result_type->IsStruct()) {
       out << "_" << id;
 
       ops.push_back(Operand::Int(id));
@@ -2410,8 +2410,8 @@
                             result)) {
       return 0;
     }
-  } else if (type->IsArray()) {
-    if (!GenerateArrayType(type->AsArray(), result)) {
+  } else if (type->Is<ast::type::ArrayType>()) {
+    if (!GenerateArrayType(type->As<ast::type::ArrayType>(), result)) {
       return 0;
     }
   } else if (type->IsBool()) {
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index e50131c..fc0685c 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -27,6 +27,7 @@
 #include "src/ast/literal.h"
 #include "src/ast/module.h"
 #include "src/ast/struct_member.h"
+#include "src/ast/type/array_type.h"
 #include "src/ast/type/access_control_type.h"
 #include "src/ast/type/storage_texture_type.h"
 #include "src/ast/type_constructor_expression.h"
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 7abf216..f2d16de 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -412,8 +412,8 @@
     }
   } else if (type->Is<ast::type::AliasType>()) {
     out_ << type->As<ast::type::AliasType>()->name();
-  } else if (type->IsArray()) {
-    auto* ary = type->AsArray();
+  } else if (type->Is<ast::type::ArrayType>()) {
+    auto* ary = type->As<ast::type::ArrayType>();
 
     for (auto* deco : ary->decorations()) {
       if (deco->IsStride()) {