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

Change-Id: Ic1b82f1ddc61355021a80d8e72f645f830363c62
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34269
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 94e0e73..5ea362d 100644
--- a/src/ast/type/access_control_type_test.cc
+++ b/src/ast/type/access_control_type_test.cc
@@ -58,7 +58,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/alias_type_test.cc b/src/ast/type/alias_type_test.cc
index 99075a9..b4507ca 100644
--- a/src/ast/type/alias_type_test.cc
+++ b/src/ast/type/alias_type_test.cc
@@ -59,7 +59,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/array_type_test.cc b/src/ast/type/array_type_test.cc
index 5c0ac8f..f45bc15 100644
--- a/src/ast/type/array_type_test.cc
+++ b/src/ast/type/array_type_test.cc
@@ -24,6 +24,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 #include "src/ast/type/u32_type.h"
 
 namespace tint {
@@ -63,7 +64,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/bool_type_test.cc b/src/ast/type/bool_type_test.cc
index 05ee0bb..3952c9a 100644
--- a/src/ast/type/bool_type_test.cc
+++ b/src/ast/type/bool_type_test.cc
@@ -20,6 +20,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -38,7 +39,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/depth_texture_type_test.cc b/src/ast/type/depth_texture_type_test.cc
index 1e467ab..3a58197 100644
--- a/src/ast/type/depth_texture_type_test.cc
+++ b/src/ast/type/depth_texture_type_test.cc
@@ -22,6 +22,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -40,7 +41,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_TRUE(ty->IsTexture());
diff --git a/src/ast/type/f32_type_test.cc b/src/ast/type/f32_type_test.cc
index 75e7a53..01622af 100644
--- a/src/ast/type/f32_type_test.cc
+++ b/src/ast/type/f32_type_test.cc
@@ -20,6 +20,7 @@
 #include "src/ast/type/bool_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -38,7 +39,7 @@
   EXPECT_TRUE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/i32_type_test.cc b/src/ast/type/i32_type_test.cc
index 11000af..ff22000 100644
--- a/src/ast/type/i32_type_test.cc
+++ b/src/ast/type/i32_type_test.cc
@@ -20,6 +20,7 @@
 #include "src/ast/type/bool_type.h"
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -38,7 +39,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_TRUE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/matrix_type_test.cc b/src/ast/type/matrix_type_test.cc
index 96d7b70..e203c36 100644
--- a/src/ast/type/matrix_type_test.cc
+++ b/src/ast/type/matrix_type_test.cc
@@ -20,6 +20,7 @@
 #include "src/ast/type/bool_type.h"
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -47,7 +48,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_TRUE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/multisampled_texture_type_test.cc b/src/ast/type/multisampled_texture_type_test.cc
index 1ba22da..1e9b67e 100644
--- a/src/ast/type/multisampled_texture_type_test.cc
+++ b/src/ast/type/multisampled_texture_type_test.cc
@@ -21,6 +21,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -40,7 +41,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_TRUE(ty->IsTexture());
diff --git a/src/ast/type/pointer_type.cc b/src/ast/type/pointer_type.cc
index b81382c..a577e78 100644
--- a/src/ast/type/pointer_type.cc
+++ b/src/ast/type/pointer_type.cc
@@ -21,10 +21,6 @@
 PointerType::PointerType(Type* subtype, StorageClass storage_class)
     : subtype_(subtype), storage_class_(storage_class) {}
 
-bool PointerType::IsPointer() const {
-  return true;
-}
-
 std::string PointerType::type_name() const {
   std::ostringstream out;
   out << "__ptr_" << storage_class_ << subtype_->type_name();
diff --git a/src/ast/type/pointer_type.h b/src/ast/type/pointer_type.h
index f27eab6..9dbf71b 100644
--- a/src/ast/type/pointer_type.h
+++ b/src/ast/type/pointer_type.h
@@ -36,9 +36,6 @@
   PointerType(PointerType&&);
   ~PointerType() override;
 
-  /// @returns true if the type is a pointer type
-  bool IsPointer() const override;
-
   /// @returns the pointee type
   Type* type() const { return subtype_; }
   /// @returns the storage class of the pointer
diff --git a/src/ast/type/pointer_type_test.cc b/src/ast/type/pointer_type_test.cc
index 51e4f4a..7350824 100644
--- a/src/ast/type/pointer_type_test.cc
+++ b/src/ast/type/pointer_type_test.cc
@@ -47,7 +47,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_TRUE(ty->IsPointer());
+  EXPECT_TRUE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/sampled_texture_type_test.cc b/src/ast/type/sampled_texture_type_test.cc
index 5421005..be16aeb 100644
--- a/src/ast/type/sampled_texture_type_test.cc
+++ b/src/ast/type/sampled_texture_type_test.cc
@@ -21,6 +21,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -40,7 +41,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_TRUE(ty->IsTexture());
diff --git a/src/ast/type/sampler_type_test.cc b/src/ast/type/sampler_type_test.cc
index 2c03f2d..42210bc 100644
--- a/src/ast/type/sampler_type_test.cc
+++ b/src/ast/type/sampler_type_test.cc
@@ -21,6 +21,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -50,7 +51,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_TRUE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/storage_texture_type_test.cc b/src/ast/type/storage_texture_type_test.cc
index 03487de..f7764d1 100644
--- a/src/ast/type/storage_texture_type_test.cc
+++ b/src/ast/type/storage_texture_type_test.cc
@@ -24,6 +24,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 #include "src/type_determiner.h"
 
 namespace tint {
@@ -44,7 +45,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_TRUE(ty->IsTexture());
diff --git a/src/ast/type/struct_type_test.cc b/src/ast/type/struct_type_test.cc
index a3dd3b2..8667acf 100644
--- a/src/ast/type/struct_type_test.cc
+++ b/src/ast/type/struct_type_test.cc
@@ -27,6 +27,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 #include "src/ast/type/u32_type.h"
 #include "src/ast/type/vector_type.h"
 
@@ -55,7 +56,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_TRUE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/type.cc b/src/ast/type/type.cc
index 51b8745..affca72 100644
--- a/src/ast/type/type.cc
+++ b/src/ast/type/type.cc
@@ -42,8 +42,8 @@
 Type::~Type() = default;
 
 Type* Type::UnwrapPtrIfNeeded() {
-  if (IsPointer()) {
-    return AsPointer()->type();
+  if (Is<PointerType>()) {
+    return As<PointerType>()->type();
   }
   return this;
 }
@@ -66,10 +66,6 @@
   return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
 }
 
-bool Type::IsPointer() const {
-  return false;
-}
-
 bool Type::IsSampler() const {
   return false;
 }
@@ -146,11 +142,6 @@
   return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
 }
 
-const PointerType* Type::AsPointer() const {
-  assert(IsPointer());
-  return static_cast<const PointerType*>(this);
-}
-
 const SamplerType* Type::AsSampler() const {
   assert(IsSampler());
   return static_cast<const SamplerType*>(this);
@@ -181,11 +172,6 @@
   return static_cast<const VoidType*>(this);
 }
 
-PointerType* Type::AsPointer() {
-  assert(IsPointer());
-  return static_cast<PointerType*>(this);
-}
-
 SamplerType* Type::AsSampler() {
   assert(IsSampler());
   return static_cast<SamplerType*>(this);
diff --git a/src/ast/type/type.h b/src/ast/type/type.h
index 1c3efdc..93a9fb8 100644
--- a/src/ast/type/type.h
+++ b/src/ast/type/type.h
@@ -23,7 +23,6 @@
 namespace ast {
 namespace type {
 
-class PointerType;
 class SamplerType;
 class StructType;
 class TextureType;
@@ -41,8 +40,6 @@
   Type(Type&&);
   ~Type() override;
 
-  /// @returns true if the type is a ptr type
-  virtual bool IsPointer() const;
   /// @returns true if the type is a sampler
   virtual bool IsSampler() const;
   /// @returns true if the type is a struct type
@@ -110,8 +107,6 @@
   /// @returns true if this type is an integer scalar or vector
   bool is_integer_scalar_or_vector();
 
-  /// @returns the type as a pointer type
-  const PointerType* AsPointer() const;
   /// @returns the type as a sampler type
   const SamplerType* AsSampler() const;
   /// @returns the type as a struct type
@@ -125,8 +120,6 @@
   /// @returns the type as a void type
   const VoidType* AsVoid() const;
 
-  /// @returns the type as a pointer type
-  PointerType* AsPointer();
   /// @returns the type as a sampler type
   SamplerType* AsSampler();
   /// @returns the type as a struct type
diff --git a/src/ast/type/u32_type_test.cc b/src/ast/type/u32_type_test.cc
index bc8f21a..60a946b 100644
--- a/src/ast/type/u32_type_test.cc
+++ b/src/ast/type/u32_type_test.cc
@@ -21,6 +21,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -39,7 +40,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/ast/type/vector_type_test.cc b/src/ast/type/vector_type_test.cc
index 8872f7d..d59d96f 100644
--- a/src/ast/type/vector_type_test.cc
+++ b/src/ast/type/vector_type_test.cc
@@ -21,6 +21,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 
 namespace tint {
 namespace ast {
@@ -47,7 +48,7 @@
   EXPECT_FALSE(ty->Is<F32Type>());
   EXPECT_FALSE(ty->Is<I32Type>());
   EXPECT_FALSE(ty->Is<MatrixType>());
-  EXPECT_FALSE(ty->IsPointer());
+  EXPECT_FALSE(ty->Is<PointerType>());
   EXPECT_FALSE(ty->IsSampler());
   EXPECT_FALSE(ty->IsStruct());
   EXPECT_FALSE(ty->IsTexture());
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 816fac1..5b50531 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -2698,8 +2698,8 @@
       // So represent a load by a new const definition.
       auto expr = MakeExpression(inst.GetSingleWordInOperand(0));
       // The load result type is the pointee type of its operand.
-      assert(expr.type->IsPointer());
-      expr.type = expr.type->AsPointer()->type();
+      assert(expr.type->Is<ast::type::PointerType>());
+      expr.type = expr.type->As<ast::type::PointerType>()->type();
       return EmitConstDefOrWriteToHoistedVar(inst, expr);
     }
     case SpvOpCopyObject: {
@@ -3059,7 +3059,7 @@
         type_mgr_->FindPointerToType(pointee_type_id, storage_class);
     auto* ast_pointer_type = parser_impl_.ConvertType(pointer_type_id);
     assert(ast_pointer_type);
-    assert(ast_pointer_type->IsPointer());
+    assert(ast_pointer_type->Is<ast::type::PointerType>());
     current_expr = TypedExpression{ast_pointer_type, next_expr};
   }
   return current_expr;
@@ -3255,8 +3255,9 @@
       if (type) {
         if (type->AsPointer()) {
           const auto* ast_type = parser_impl_.ConvertType(inst.type_id());
-          if (ast_type && ast_type->AsPointer()) {
-            info->storage_class = ast_type->AsPointer()->storage_class();
+          if (ast_type && ast_type->As<ast::type::PointerType>()) {
+            info->storage_class =
+                ast_type->As<ast::type::PointerType>()->storage_class();
           }
           switch (inst.opcode()) {
             case SpvOpUndef:
@@ -3298,8 +3299,8 @@
   const auto type_id = def_use_mgr_->GetDef(id)->type_id();
   if (type_id) {
     auto* ast_type = parser_impl_.ConvertType(type_id);
-    if (ast_type && ast_type->IsPointer()) {
-      return ast_type->AsPointer()->storage_class();
+    if (ast_type && ast_type->Is<ast::type::PointerType>()) {
+      return ast_type->As<ast::type::PointerType>()->storage_class();
     }
   }
   return ast::StorageClass::kNone;
@@ -3307,10 +3308,10 @@
 
 ast::type::Type* FunctionEmitter::RemapStorageClass(ast::type::Type* type,
                                                     uint32_t result_id) {
-  if (type->IsPointer()) {
+  if (type->Is<ast::type::PointerType>()) {
     // Remap an old-style storage buffer pointer to a new-style storage
     // buffer pointer.
-    const auto* ast_ptr_type = type->AsPointer();
+    const auto* ast_ptr_type = type->As<ast::type::PointerType>();
     const auto sc = GetStorageClassForPointerValue(result_id);
     if (ast_ptr_type->storage_class() != sc) {
       return parser_impl_.get_module().create<ast::type::PointerType>(
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 809a38c..82ecf8a 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1116,14 +1116,15 @@
                          "SPIR-V type with ID: "
                       << var.type_id();
       }
-      if (!ast_type->IsPointer()) {
+      if (!ast_type->Is<ast::type::PointerType>()) {
         return Fail() << "variable with ID " << var.result_id()
                       << " has non-pointer type " << var.type_id();
       }
     }
 
-    auto* ast_store_type = ast_type->AsPointer()->type();
-    auto ast_storage_class = ast_type->AsPointer()->storage_class();
+    auto* ast_store_type = ast_type->As<ast::type::PointerType>()->type();
+    auto ast_storage_class =
+        ast_type->As<ast::type::PointerType>()->storage_class();
     auto* ast_var =
         MakeVariable(var.result_id(), ast_storage_class, ast_store_type);
     if (var.NumInOperands() > 1) {
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index b1e2110..11b0052 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -36,6 +36,7 @@
 #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/pointer_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 787e4e7..05425d5 100644
--- a/src/reader/spirv/parser_impl_convert_type_test.cc
+++ b/src/reader/spirv/parser_impl_convert_type_test.cc
@@ -665,8 +665,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kInput);
@@ -681,8 +681,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kOutput);
@@ -697,8 +697,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kUniform);
@@ -713,8 +713,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kWorkgroup);
@@ -729,8 +729,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kUniformConstant);
@@ -745,8 +745,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kStorageBuffer);
@@ -761,8 +761,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kImage);
@@ -777,8 +777,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kPrivate);
@@ -793,8 +793,8 @@
   EXPECT_TRUE(p->BuildInternalModule());
 
   auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->IsPointer());
-  auto* ptr_ty = type->AsPointer();
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_TRUE(ptr_ty->type()->Is<ast::type::F32Type>());
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kFunction);
@@ -812,14 +812,14 @@
 
   auto* type = p->ConvertType(3);
   EXPECT_NE(type, nullptr);
-  EXPECT_TRUE(type->IsPointer());
+  EXPECT_TRUE(type->Is<ast::type::PointerType>());
 
-  auto* ptr_ty = type->AsPointer();
+  auto* ptr_ty = type->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ty, nullptr);
   EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kInput);
-  EXPECT_TRUE(ptr_ty->type()->IsPointer());
+  EXPECT_TRUE(ptr_ty->type()->Is<ast::type::PointerType>());
 
-  auto* ptr_ptr_ty = ptr_ty->type()->AsPointer();
+  auto* ptr_ptr_ty = ptr_ty->type()->As<ast::type::PointerType>();
   EXPECT_NE(ptr_ptr_ty, nullptr);
   EXPECT_EQ(ptr_ptr_ty->storage_class(), ast::StorageClass::kOutput);
   EXPECT_TRUE(ptr_ptr_ty->type()->Is<ast::type::F32Type>());
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index b64fbb8..5943dab 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -239,9 +239,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsPointer());
+  ASSERT_TRUE(t->Is<ast::type::PointerType>());
 
-  auto* ptr = t->AsPointer();
+  auto* ptr = t->As<ast::type::PointerType>();
   ASSERT_TRUE(ptr->type()->Is<ast::type::F32Type>());
   ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
 }
@@ -253,9 +253,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t->IsPointer());
+  ASSERT_TRUE(t->Is<ast::type::PointerType>());
 
-  auto* ptr = t->AsPointer();
+  auto* ptr = t->As<ast::type::PointerType>();
   ASSERT_TRUE(ptr->type()->IsVector());
   ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
 
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index e77d082..fcfc44c 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -348,9 +348,9 @@
   }
 
   // If we're extracting from a pointer, we return a pointer.
-  if (res->IsPointer()) {
+  if (res->Is<ast::type::PointerType>()) {
     ret = mod_->create<ast::type::PointerType>(
-        ret, res->AsPointer()->storage_class());
+        ret, res->As<ast::type::PointerType>()->storage_class());
   } 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
@@ -850,7 +850,7 @@
     // the pointer around the variable type.
     if (var->is_const()) {
       expr->set_result_type(var->type());
-    } else if (var->type()->IsPointer()) {
+    } else if (var->type()->Is<ast::type::PointerType>()) {
       expr->set_result_type(var->type());
     } else {
       expr->set_result_type(mod_->create<ast::type::PointerType>(
@@ -1045,9 +1045,9 @@
     }
 
     // If we're extracting from a pointer, we return a pointer.
-    if (res->IsPointer()) {
+    if (res->Is<ast::type::PointerType>()) {
       ret = mod_->create<ast::type::PointerType>(
-          ret, res->AsPointer()->storage_class());
+          ret, res->As<ast::type::PointerType>()->storage_class());
     }
   } else if (data_type->IsVector()) {
     auto* vec = data_type->AsVector();
@@ -1057,9 +1057,9 @@
       // A single element swizzle is just the type of the vector.
       ret = vec->type();
       // If we're extracting from a pointer, we return a pointer.
-      if (res->IsPointer()) {
+      if (res->Is<ast::type::PointerType>()) {
         ret = mod_->create<ast::type::PointerType>(
-            ret, res->AsPointer()->storage_class());
+            ret, res->As<ast::type::PointerType>()->storage_class());
       }
     } else {
       // The vector will have a number of components equal to the length of the
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 4a928b9..3f3715e 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -438,9 +438,9 @@
                                    idx);
   EXPECT_TRUE(td()->DetermineResultType(&acc));
   ASSERT_NE(acc.result_type(), nullptr);
-  ASSERT_TRUE(acc.result_type()->IsPointer());
+  ASSERT_TRUE(acc.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = acc.result_type()->AsPointer();
+  auto* ptr = acc.result_type()->As<ast::type::PointerType>();
   EXPECT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
@@ -463,9 +463,9 @@
                                    idx);
   EXPECT_TRUE(td()->DetermineResultType(&acc));
   ASSERT_NE(acc.result_type(), nullptr);
-  ASSERT_TRUE(acc.result_type()->IsPointer());
+  ASSERT_TRUE(acc.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = acc.result_type()->AsPointer();
+  auto* ptr = acc.result_type()->As<ast::type::PointerType>();
   EXPECT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
@@ -509,9 +509,9 @@
                                    idx);
   EXPECT_TRUE(td()->DetermineResultType(&acc));
   ASSERT_NE(acc.result_type(), nullptr);
-  ASSERT_TRUE(acc.result_type()->IsPointer());
+  ASSERT_TRUE(acc.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = acc.result_type()->AsPointer();
+  auto* ptr = acc.result_type()->As<ast::type::PointerType>();
   ASSERT_TRUE(ptr->type()->IsVector());
   EXPECT_EQ(ptr->type()->AsVector()->size(), 3u);
 }
@@ -538,9 +538,9 @@
 
   EXPECT_TRUE(td()->DetermineResultType(&acc));
   ASSERT_NE(acc.result_type(), nullptr);
-  ASSERT_TRUE(acc.result_type()->IsPointer());
+  ASSERT_TRUE(acc.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = acc.result_type()->AsPointer();
+  auto* ptr = acc.result_type()->As<ast::type::PointerType>();
   EXPECT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
@@ -561,9 +561,9 @@
                                    idx);
   EXPECT_TRUE(td()->DetermineResultType(&acc));
   ASSERT_NE(acc.result_type(), nullptr);
-  ASSERT_TRUE(acc.result_type()->IsPointer());
+  ASSERT_TRUE(acc.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = acc.result_type()->AsPointer();
+  auto* ptr = acc.result_type()->As<ast::type::PointerType>();
   EXPECT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
@@ -697,9 +697,11 @@
   ast::IdentifierExpression ident("my_var");
   EXPECT_TRUE(td()->DetermineResultType(&ident));
   ASSERT_NE(ident.result_type(), nullptr);
-  EXPECT_TRUE(ident.result_type()->IsPointer());
-  EXPECT_TRUE(
-      ident.result_type()->AsPointer()->type()->Is<ast::type::F32Type>());
+  EXPECT_TRUE(ident.result_type()->Is<ast::type::PointerType>());
+  EXPECT_TRUE(ident.result_type()
+                  ->As<ast::type::PointerType>()
+                  ->type()
+                  ->Is<ast::type::F32Type>());
 }
 
 TEST_F(TypeDeterminerTest, Expr_Identifier_GlobalConstant) {
@@ -755,9 +757,11 @@
   EXPECT_TRUE(td()->DetermineFunction(&f));
 
   ASSERT_NE(my_var->result_type(), nullptr);
-  EXPECT_TRUE(my_var->result_type()->IsPointer());
-  EXPECT_TRUE(
-      my_var->result_type()->AsPointer()->type()->Is<ast::type::F32Type>());
+  EXPECT_TRUE(my_var->result_type()->Is<ast::type::PointerType>());
+  EXPECT_TRUE(my_var->result_type()
+                  ->As<ast::type::PointerType>()
+                  ->type()
+                  ->Is<ast::type::F32Type>());
 }
 
 TEST_F(TypeDeterminerTest, Expr_Identifier_Function_Ptr) {
@@ -778,9 +782,11 @@
   EXPECT_TRUE(td()->DetermineFunction(&f));
 
   ASSERT_NE(my_var->result_type(), nullptr);
-  EXPECT_TRUE(my_var->result_type()->IsPointer());
-  EXPECT_TRUE(
-      my_var->result_type()->AsPointer()->type()->Is<ast::type::F32Type>());
+  EXPECT_TRUE(my_var->result_type()->Is<ast::type::PointerType>());
+  EXPECT_TRUE(my_var->result_type()
+                  ->As<ast::type::PointerType>()
+                  ->type()
+                  ->Is<ast::type::F32Type>());
 }
 
 TEST_F(TypeDeterminerTest, Expr_Identifier_Function) {
@@ -967,9 +973,9 @@
   ast::MemberAccessorExpression mem(ident, mem_ident);
   EXPECT_TRUE(td()->DetermineResultType(&mem));
   ASSERT_NE(mem.result_type(), nullptr);
-  ASSERT_TRUE(mem.result_type()->IsPointer());
+  ASSERT_TRUE(mem.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = mem.result_type()->AsPointer();
+  auto* ptr = mem.result_type()->As<ast::type::PointerType>();
   EXPECT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
@@ -1001,9 +1007,9 @@
   ast::MemberAccessorExpression mem(ident, mem_ident);
   EXPECT_TRUE(td()->DetermineResultType(&mem));
   ASSERT_NE(mem.result_type(), nullptr);
-  ASSERT_TRUE(mem.result_type()->IsPointer());
+  ASSERT_TRUE(mem.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = mem.result_type()->AsPointer();
+  auto* ptr = mem.result_type()->As<ast::type::PointerType>();
   EXPECT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
@@ -1044,9 +1050,9 @@
   ast::MemberAccessorExpression mem(ident, swizzle);
   EXPECT_TRUE(td()->DetermineResultType(&mem)) << td()->error();
   ASSERT_NE(mem.result_type(), nullptr);
-  ASSERT_TRUE(mem.result_type()->IsPointer());
+  ASSERT_TRUE(mem.result_type()->Is<ast::type::PointerType>());
 
-  auto* ptr = mem.result_type()->AsPointer();
+  auto* ptr = mem.result_type()->As<ast::type::PointerType>();
   ASSERT_TRUE(ptr->type()->Is<ast::type::F32Type>());
 }
 
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 782f471..a697caa 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -45,6 +45,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
 #include "src/ast/type/sampler_type.h"
 #include "src/ast/type/struct_type.h"
 #include "src/ast/type/texture_type.h"
@@ -2073,7 +2074,7 @@
       return false;
     }
     out << mat->rows() << "x" << mat->columns();
-  } else if (type->IsPointer()) {
+  } else if (type->Is<ast::type::PointerType>()) {
     // TODO(dsinclair): What do we do with pointers in HLSL?
     // https://bugs.chromium.org/p/tint/issues/detail?id=183
     error_ = "pointers not supported in HLSL";
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 3404522..762cd9a 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -197,7 +197,7 @@
   if (type->Is<ast::type::BoolType>()) {
     return 1;
   }
-  if (type->IsPointer()) {
+  if (type->Is<ast::type::PointerType>()) {
     return 0;
   }
   if (type->Is<ast::type::F32Type>() || type->Is<ast::type::I32Type>() ||
@@ -1825,8 +1825,8 @@
       return false;
     }
     out_ << mat->columns() << "x" << mat->rows();
-  } else if (type->IsPointer()) {
-    auto* ptr = type->AsPointer();
+  } else if (type->Is<ast::type::PointerType>()) {
+    auto* ptr = type->As<ast::type::PointerType>();
     // TODO(dsinclair): Storage class?
     if (!EmitType(ptr->type(), "")) {
       return false;
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 4327476..0906c6f 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -819,7 +819,7 @@
 
   // 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() ||
+  if (info->source_type->Is<ast::type::PointerType>() ||
       (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);
@@ -854,7 +854,7 @@
   // If the data_type is a structure we're accessing a member, if it's a
   // vector we're accessing a swizzle.
   if (data_type->IsStruct()) {
-    if (!info->source_type->IsPointer()) {
+    if (!info->source_type->Is<ast::type::PointerType>()) {
       error_ =
           "Attempting to access a struct member on a non-pointer. Something is "
           "wrong";
@@ -895,7 +895,7 @@
       return false;
     }
 
-    if (info->source_type->IsPointer()) {
+    if (info->source_type->Is<ast::type::PointerType>()) {
       auto idx_id = GenerateU32Literal(val);
       if (idx_id == 0) {
         return 0;
@@ -1009,7 +1009,7 @@
     auto* ary_res_type =
         accessors[0]->AsArrayAccessor()->array()->result_type();
 
-    if (!ary_res_type->IsPointer() &&
+    if (!ary_res_type->Is<ast::type::PointerType>() &&
         (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);
@@ -1087,7 +1087,7 @@
 }
 
 uint32_t Builder::GenerateLoadIfNeeded(ast::type::Type* type, uint32_t id) {
-  if (!type->IsPointer()) {
+  if (!type->Is<ast::type::PointerType>()) {
     return id;
   }
 
@@ -1808,7 +1808,7 @@
       error_ = "missing param for runtime array length";
       return 0;
     } else if (!call->params()[0]->IsMemberAccessor()) {
-      if (call->params()[0]->result_type()->IsPointer()) {
+      if (call->params()[0]->result_type()->Is<ast::type::PointerType>()) {
         error_ = "pointer accessors not supported yet";
       } else {
         error_ = "invalid accessor for runtime array length";
@@ -2431,8 +2431,8 @@
     if (!GenerateMatrixType(type->As<ast::type::MatrixType>(), result)) {
       return 0;
     }
-  } else if (type->IsPointer()) {
-    if (!GeneratePointerType(type->AsPointer(), result)) {
+  } else if (type->Is<ast::type::PointerType>()) {
+    if (!GeneratePointerType(type->As<ast::type::PointerType>(), result)) {
       return 0;
     }
   } else if (type->IsStruct()) {
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index bda42b6..a9d9962 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -28,6 +28,7 @@
 #include "src/ast/module.h"
 #include "src/ast/struct_member.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/pointer_type.h"
 #include "src/ast/type/array_type.h"
 #include "src/ast/type/matrix_type.h"
 #include "src/ast/type/storage_texture_type.h"
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 1ecfec3..e9ed0e8 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -446,8 +446,8 @@
       return false;
     }
     out_ << ">";
-  } else if (type->IsPointer()) {
-    auto* ptr = type->AsPointer();
+  } else if (type->Is<ast::type::PointerType>()) {
+    auto* ptr = type->As<ast::type::PointerType>();
     out_ << "ptr<" << ptr->storage_class() << ", ";
     if (!EmitType(ptr->type())) {
       return false;