Replace Variable::(Is|As)* with Castable

Change-Id: I7a49287af079d53cee095fa2243dd21757546b56
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34318
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/decorated_variable.cc b/src/ast/decorated_variable.cc
index 5e5694a..4472692 100644
--- a/src/ast/decorated_variable.cc
+++ b/src/ast/decorated_variable.cc
@@ -69,10 +69,6 @@
   return 0;
 }
 
-bool DecoratedVariable::IsDecorated() const {
-  return true;
-}
-
 bool DecoratedVariable::IsValid() const {
   return Variable::IsValid();
 }
diff --git a/src/ast/decorated_variable.h b/src/ast/decorated_variable.h
index 1eeea8c..b0067b5 100644
--- a/src/ast/decorated_variable.h
+++ b/src/ast/decorated_variable.h
@@ -56,9 +56,6 @@
   /// |HasConstantIdDecoration| has been called first.
   uint32_t constant_id() const;
 
-  /// @returns true if this is a decorated variable
-  bool IsDecorated() const override;
-
   /// @returns true if the name and path are both present
   bool IsValid() const override;
 
diff --git a/src/ast/decorated_variable_test.cc b/src/ast/decorated_variable_test.cc
index f133a13..2b41652 100644
--- a/src/ast/decorated_variable_test.cc
+++ b/src/ast/decorated_variable_test.cc
@@ -108,7 +108,7 @@
 
 TEST_F(DecoratedVariableTest, IsDecorated) {
   DecoratedVariable dv;
-  EXPECT_TRUE(dv.IsDecorated());
+  EXPECT_TRUE(dv.Is<ast::DecoratedVariable>());
 }
 
 TEST_F(DecoratedVariableTest, to_str) {
diff --git a/src/ast/function.cc b/src/ast/function.cc
index b636559..8c72209 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -85,13 +85,12 @@
   std::vector<std::pair<Variable*, LocationDecoration*>> ret;
 
   for (auto* var : referenced_module_variables()) {
-    if (!var->IsDecorated()) {
-      continue;
-    }
-    for (auto* deco : var->AsDecorated()->decorations()) {
-      if (auto* location = deco->As<LocationDecoration>()) {
-        ret.push_back({var, location});
-        break;
+    if (auto* decos = var->As<ast::DecoratedVariable>()) {
+      for (auto* deco : decos->decorations()) {
+        if (auto* location = deco->As<LocationDecoration>()) {
+          ret.push_back({var, location});
+          break;
+        }
       }
     }
   }
@@ -103,14 +102,14 @@
   std::vector<std::pair<Variable*, Function::BindingInfo>> ret;
 
   for (auto* var : referenced_module_variables()) {
-    if (!var->IsDecorated() ||
+    if (!var->Is<ast::DecoratedVariable>() ||
         var->storage_class() != ast::StorageClass::kUniform) {
       continue;
     }
 
     BindingDecoration* binding = nullptr;
     SetDecoration* set = nullptr;
-    for (auto* deco : var->AsDecorated()->decorations()) {
+    for (auto* deco : var->As<ast::DecoratedVariable>()->decorations()) {
       if (auto* b = deco->As<ast::BindingDecoration>()) {
         binding = b;
       } else if (auto* s = deco->As<ast::SetDecoration>()) {
@@ -131,14 +130,14 @@
   std::vector<std::pair<Variable*, Function::BindingInfo>> ret;
 
   for (auto* var : referenced_module_variables()) {
-    if (!var->IsDecorated() ||
+    if (!var->Is<ast::DecoratedVariable>() ||
         var->storage_class() != ast::StorageClass::kStorageBuffer) {
       continue;
     }
 
     BindingDecoration* binding = nullptr;
     SetDecoration* set = nullptr;
-    for (auto* deco : var->AsDecorated()->decorations()) {
+    for (auto* deco : var->As<ast::DecoratedVariable>()->decorations()) {
       if (auto* b = deco->As<ast::BindingDecoration>()) {
         binding = b;
       } else if (auto* s = deco->As<ast::SetDecoration>()) {
@@ -159,10 +158,10 @@
   std::vector<std::pair<Variable*, BuiltinDecoration*>> ret;
 
   for (auto* var : referenced_module_variables()) {
-    if (!var->IsDecorated()) {
+    if (!var->Is<ast::DecoratedVariable>()) {
       continue;
     }
-    for (auto* deco : var->AsDecorated()->decorations()) {
+    for (auto* deco : var->As<ast::DecoratedVariable>()->decorations()) {
       if (auto* builtin = deco->As<BuiltinDecoration>()) {
         ret.push_back({var, builtin});
         break;
@@ -283,14 +282,15 @@
 
   for (auto* var : referenced_module_variables()) {
     auto* unwrapped_type = var->type()->UnwrapIfNeeded();
-    if (!var->IsDecorated() || !unwrapped_type->Is<ast::type::SamplerType>() ||
+    if (!var->Is<ast::DecoratedVariable>() ||
+        !unwrapped_type->Is<ast::type::SamplerType>() ||
         unwrapped_type->As<ast::type::SamplerType>()->kind() != kind) {
       continue;
     }
 
     BindingDecoration* binding = nullptr;
     SetDecoration* set = nullptr;
-    for (auto* deco : var->AsDecorated()->decorations()) {
+    for (auto* deco : var->As<ast::DecoratedVariable>()->decorations()) {
       if (auto* b = deco->As<ast::BindingDecoration>()) {
         binding = b;
       } else if (auto* s = deco->As<ast::SetDecoration>()) {
@@ -312,7 +312,8 @@
 
   for (auto* var : referenced_module_variables()) {
     auto* unwrapped_type = var->type()->UnwrapIfNeeded();
-    if (!var->IsDecorated() || !unwrapped_type->Is<ast::type::TextureType>()) {
+    if (!var->Is<ast::DecoratedVariable>() ||
+        !unwrapped_type->Is<ast::type::TextureType>()) {
       continue;
     }
 
@@ -325,7 +326,7 @@
 
     BindingDecoration* binding = nullptr;
     SetDecoration* set = nullptr;
-    for (auto* deco : var->AsDecorated()->decorations()) {
+    for (auto* deco : var->As<ast::DecoratedVariable>()->decorations()) {
       if (auto* b = deco->As<ast::BindingDecoration>()) {
         binding = b;
       } else if (auto* s = deco->As<ast::SetDecoration>()) {
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
index 67b2ed1..37c1f20 100644
--- a/src/ast/variable.cc
+++ b/src/ast/variable.cc
@@ -36,20 +36,6 @@
 
 Variable::~Variable() = default;
 
-DecoratedVariable* Variable::AsDecorated() {
-  assert(IsDecorated());
-  return static_cast<DecoratedVariable*>(this);
-}
-
-const DecoratedVariable* Variable::AsDecorated() const {
-  assert(IsDecorated());
-  return static_cast<const DecoratedVariable*>(this);
-}
-
-bool Variable::IsDecorated() const {
-  return false;
-}
-
 bool Variable::IsValid() const {
   if (name_.length() == 0) {
     return false;
diff --git a/src/ast/variable.h b/src/ast/variable.h
index 6445946..11c95d3 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -29,8 +29,6 @@
 namespace tint {
 namespace ast {
 
-class DecoratedVariable;
-
 /// A Variable statement.
 ///
 /// An instance of this class represents one of three constructs in WGSL: "var"
@@ -134,14 +132,6 @@
   /// @returns true if this is a constant, false otherwise
   bool is_const() const { return is_const_; }
 
-  /// @returns true if this is a decorated variable
-  virtual bool IsDecorated() const;
-
-  /// @returns the expression as a decorated variable
-  DecoratedVariable* AsDecorated();
-  /// @returns the expression as a decorated variable
-  const DecoratedVariable* AsDecorated() const;
-
   /// @returns true if the name and path are both present
   bool IsValid() const override;
 
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index a9401a4..9012f73 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -100,11 +100,11 @@
 std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
   std::map<uint32_t, Scalar> result;
   for (auto* var : module_.global_variables()) {
-    if (!var->IsDecorated()) {
+    auto* decorated = var->As<ast::DecoratedVariable>();
+    if (decorated == nullptr) {
       continue;
     }
 
-    auto* decorated = var->AsDecorated();
     if (!decorated->HasConstantIdDecoration()) {
       continue;
     }
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index b03cd79..76f2c29 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -46,7 +46,7 @@
   EXPECT_EQ(e->source().range.end.column, 11u);
 
   ASSERT_EQ(e->constructor(), nullptr);
-  ASSERT_FALSE(e->IsDecorated());
+  ASSERT_FALSE(e->Is<ast::DecoratedVariable>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
@@ -73,7 +73,7 @@
   ASSERT_TRUE(e->constructor()->Is<ast::ConstructorExpression>());
   ASSERT_TRUE(e->constructor()->Is<ast::ScalarConstructorExpression>());
 
-  ASSERT_FALSE(e->IsDecorated());
+  ASSERT_FALSE(e->Is<ast::DecoratedVariable>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
@@ -86,7 +86,7 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->IsDecorated());
+  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
 
   EXPECT_EQ(e->name(), "a");
   ASSERT_NE(e->type(), nullptr);
@@ -100,8 +100,8 @@
 
   ASSERT_EQ(e->constructor(), nullptr);
 
-  ASSERT_TRUE(e->IsDecorated());
-  auto* v = e->AsDecorated();
+  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
+  auto* v = e->As<ast::DecoratedVariable>();
 
   auto& decorations = v->decorations();
   ASSERT_EQ(decorations.size(), 2u);
@@ -120,7 +120,7 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->IsDecorated());
+  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
 
   EXPECT_EQ(e->name(), "a");
   ASSERT_NE(e->type(), nullptr);
@@ -134,8 +134,8 @@
 
   ASSERT_EQ(e->constructor(), nullptr);
 
-  ASSERT_TRUE(e->IsDecorated());
-  auto* v = e->AsDecorated();
+  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
+  auto* v = e->As<ast::DecoratedVariable>();
 
   auto& decorations = v->decorations();
   ASSERT_EQ(decorations.size(), 2u);
diff --git a/src/transform/vertex_pulling_transform.cc b/src/transform/vertex_pulling_transform.cc
index 11544ca..40cfc4a 100644
--- a/src/transform/vertex_pulling_transform.cc
+++ b/src/transform/vertex_pulling_transform.cc
@@ -122,11 +122,12 @@
 
   // Look for an existing vertex index builtin
   for (auto* v : mod_->global_variables()) {
-    if (!v->IsDecorated() || v->storage_class() != ast::StorageClass::kInput) {
+    if (!v->Is<ast::DecoratedVariable>() ||
+        v->storage_class() != ast::StorageClass::kInput) {
       continue;
     }
 
-    for (auto* d : v->AsDecorated()->decorations()) {
+    for (auto* d : v->As<ast::DecoratedVariable>()->decorations()) {
       if (d->Is<ast::BuiltinDecoration>() &&
           d->As<ast::BuiltinDecoration>()->value() ==
               ast::Builtin::kVertexIdx) {
@@ -165,11 +166,12 @@
 
   // Look for an existing instance index builtin
   for (auto* v : mod_->global_variables()) {
-    if (!v->IsDecorated() || v->storage_class() != ast::StorageClass::kInput) {
+    if (!v->Is<ast::DecoratedVariable>() ||
+        v->storage_class() != ast::StorageClass::kInput) {
       continue;
     }
 
-    for (auto* d : v->AsDecorated()->decorations()) {
+    for (auto* d : v->As<ast::DecoratedVariable>()->decorations()) {
       if (d->Is<ast::BuiltinDecoration>() &&
           d->As<ast::BuiltinDecoration>()->value() ==
               ast::Builtin::kInstanceIdx) {
@@ -195,11 +197,12 @@
 
 void VertexPullingTransform::ConvertVertexInputVariablesToPrivate() {
   for (auto*& v : mod_->global_variables()) {
-    if (!v->IsDecorated() || v->storage_class() != ast::StorageClass::kInput) {
+    if (!v->Is<ast::DecoratedVariable>() ||
+        v->storage_class() != ast::StorageClass::kInput) {
       continue;
     }
 
-    for (auto* d : v->AsDecorated()->decorations()) {
+    for (auto* d : v->As<ast::DecoratedVariable>()->decorations()) {
       if (auto* l = d->As<ast::LocationDecoration>()) {
         uint32_t location = l->value();
         // This is where the replacement happens. Expressions use identifier
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index c5c61b5..a84af8c 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -1005,9 +1005,9 @@
 }
 
 bool GeneratorImpl::global_is_in_struct(ast::Variable* var) const {
-  return var->IsDecorated() &&
-         (var->AsDecorated()->HasLocationDecoration() ||
-          var->AsDecorated()->HasBuiltinDecoration()) &&
+  return var->Is<ast::DecoratedVariable>() &&
+         (var->As<ast::DecoratedVariable>()->HasLocationDecoration() ||
+          var->As<ast::DecoratedVariable>()->HasBuiltinDecoration()) &&
          (var->storage_class() == ast::StorageClass::kInput ||
           var->storage_class() == ast::StorageClass::kOutput);
 }
@@ -2219,7 +2219,7 @@
   make_indent(out);
 
   // TODO(dsinclair): Handle variable decorations
-  if (var->IsDecorated()) {
+  if (var->Is<ast::DecoratedVariable>()) {
     error_ = "Variable decorations are not handled yet";
     return false;
   }
@@ -2253,7 +2253,8 @@
                                              const ast::Variable* var) {
   make_indent(out);
 
-  if (var->IsDecorated() && !var->AsDecorated()->HasConstantIdDecoration()) {
+  if (var->Is<ast::DecoratedVariable>() &&
+      !var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
     error_ = "Decorated const values not valid";
     return false;
   }
@@ -2271,8 +2272,9 @@
     out << pre.str();
   }
 
-  if (var->IsDecorated() && var->AsDecorated()->HasConstantIdDecoration()) {
-    auto const_id = var->AsDecorated()->constant_id();
+  if (var->Is<ast::DecoratedVariable>() &&
+      var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
+    auto const_id = var->As<ast::DecoratedVariable>()->constant_id();
 
     out << "#ifndef WGSL_SPEC_CONSTANT_" << const_id << std::endl;
 
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index a1a9d0d..d4826e9 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -1492,11 +1492,13 @@
 
 bool GeneratorImpl::global_is_in_struct(ast::Variable* var) const {
   bool in_or_out_struct_has_location =
-      var->IsDecorated() && var->AsDecorated()->HasLocationDecoration() &&
+      var->Is<ast::DecoratedVariable>() &&
+      var->As<ast::DecoratedVariable>()->HasLocationDecoration() &&
       (var->storage_class() == ast::StorageClass::kInput ||
        var->storage_class() == ast::StorageClass::kOutput);
   bool in_struct_has_builtin =
-      var->IsDecorated() && var->AsDecorated()->HasBuiltinDecoration() &&
+      var->Is<ast::DecoratedVariable>() &&
+      var->As<ast::DecoratedVariable>()->HasBuiltinDecoration() &&
       var->storage_class() == ast::StorageClass::kOutput;
   return in_or_out_struct_has_location || in_struct_has_builtin;
 }
@@ -2006,7 +2008,7 @@
   make_indent();
 
   // TODO(dsinclair): Handle variable decorations
-  if (var->IsDecorated()) {
+  if (var->Is<ast::DecoratedVariable>()) {
     error_ = "Variable decorations are not handled yet";
     return false;
   }
@@ -2044,7 +2046,8 @@
 bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
   make_indent();
 
-  if (var->IsDecorated() && !var->AsDecorated()->HasConstantIdDecoration()) {
+  if (var->Is<ast::DecoratedVariable>() &&
+      !var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
     error_ = "Decorated const values not valid";
     return false;
   }
@@ -2061,9 +2064,10 @@
     out_ << " " << var->name();
   }
 
-  if (var->IsDecorated() && var->AsDecorated()->HasConstantIdDecoration()) {
-    out_ << " [[function_constant(" << var->AsDecorated()->constant_id()
-         << ")]]";
+  if (var->Is<ast::DecoratedVariable>() &&
+      var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
+    out_ << " [[function_constant("
+         << var->As<ast::DecoratedVariable>()->constant_id() << ")]]";
   } else if (var->constructor() != nullptr) {
     out_ << " = ";
     if (!EmitExpression(var->constructor())) {
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 1f2bdc2..042bea5 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -747,7 +747,8 @@
     //    one
     // 2- If we don't have a constructor and we're an Output or Private variable
     //    then WGSL requires an initializer.
-    if (var->IsDecorated() && var->AsDecorated()->HasConstantIdDecoration()) {
+    if (var->Is<ast::DecoratedVariable>() &&
+        var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
       if (type->Is<ast::type::F32Type>()) {
         ast::FloatLiteral l(type, 0.0f);
         init_id = GenerateLiteralIfNeeded(var, &l);
@@ -782,8 +783,8 @@
 
   push_type(spv::Op::OpVariable, std::move(ops));
 
-  if (var->IsDecorated()) {
-    for (auto* deco : var->AsDecorated()->decorations()) {
+  if (auto* decorated = var->As<ast::DecoratedVariable>()) {
+    for (auto* deco : decorated->decorations()) {
       if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
         push_annot(spv::Op::OpDecorate,
                    {Operand::Int(var_id), Operand::Int(SpvDecorationBuiltIn),
@@ -1468,8 +1469,8 @@
 
   auto name = lit->name();
   bool is_spec_constant = false;
-  if (var && var->IsDecorated() &&
-      var->AsDecorated()->HasConstantIdDecoration()) {
+  if (var && var->Is<ast::DecoratedVariable>() &&
+      var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
     name = "__spec" + name;
     is_spec_constant = true;
   }
@@ -1483,9 +1484,10 @@
   auto result_id = result.to_i();
 
   if (is_spec_constant) {
-    push_annot(spv::Op::OpDecorate,
-               {Operand::Int(result_id), Operand::Int(SpvDecorationSpecId),
-                Operand::Int(var->AsDecorated()->constant_id())});
+    push_annot(
+        spv::Op::OpDecorate,
+        {Operand::Int(result_id), Operand::Int(SpvDecorationSpecId),
+         Operand::Int(var->As<ast::DecoratedVariable>()->constant_id())});
   }
 
   if (lit->IsBool()) {
@@ -2701,10 +2703,10 @@
   bool has_layout = false;
   for (auto* deco : member->decorations()) {
     if (auto* offset = deco->As<ast::StructMemberOffsetDecoration>()) {
-      push_annot(spv::Op::OpMemberDecorate,
-                 {Operand::Int(struct_id), Operand::Int(idx),
-                  Operand::Int(SpvDecorationOffset),
-                  Operand::Int(offset->offset())});
+      push_annot(
+          spv::Op::OpMemberDecorate,
+          {Operand::Int(struct_id), Operand::Int(idx),
+           Operand::Int(SpvDecorationOffset), Operand::Int(offset->offset())});
       has_layout = true;
     } else {
       error_ = "unknown struct member decoration";
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 0761d80..88dfb21 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -602,8 +602,8 @@
 bool GeneratorImpl::EmitVariable(ast::Variable* var) {
   make_indent();
 
-  if (var->IsDecorated()) {
-    if (!EmitVariableDecorations(var->AsDecorated())) {
+  if (auto* decorated = var->As<ast::DecoratedVariable>()) {
+    if (!EmitVariableDecorations(decorated)) {
       return false;
     }
   }
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index 1de0b9d..4680036 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -27,6 +27,7 @@
 #include "src/ast/case_statement.h"
 #include "src/ast/constructor_expression.h"
 #include "src/ast/continue_statement.h"
+#include "src/ast/decorated_variable.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/fallthrough_statement.h"
 #include "src/ast/identifier_expression.h"