Derive all ast::Node from Castable

The hand-rolled `AsBlah()`, `IsBlah()` methods will be migrated in future changes.

Change-Id: I078c100b561b50018771cc38c1cac4379c393424
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34301
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/access_decoration.cc b/src/ast/access_decoration.cc
index 3f7252a..18d0d6e 100644
--- a/src/ast/access_decoration.cc
+++ b/src/ast/access_decoration.cc
@@ -20,7 +20,7 @@
 constexpr const DecorationKind AccessDecoration::Kind;
 
 AccessDecoration::AccessDecoration(AccessControl val, const Source& source)
-    : TypeDecoration(source), value_(val) {}
+    : Base(source), value_(val) {}
 
 AccessDecoration::~AccessDecoration() = default;
 
@@ -29,7 +29,7 @@
 }
 
 bool AccessDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || TypeDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool AccessDecoration::IsAccess() const {
diff --git a/src/ast/access_decoration.h b/src/ast/access_decoration.h
index 3be11d5..489c0e9 100644
--- a/src/ast/access_decoration.h
+++ b/src/ast/access_decoration.h
@@ -24,7 +24,7 @@
 namespace ast {
 
 /// An access decoration
-class AccessDecoration : public TypeDecoration {
+class AccessDecoration : public Castable<AccessDecoration, TypeDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kAccess;
diff --git a/src/ast/array_accessor_expression.cc b/src/ast/array_accessor_expression.cc
index e8eea8a..1891f4f 100644
--- a/src/ast/array_accessor_expression.cc
+++ b/src/ast/array_accessor_expression.cc
@@ -17,16 +17,16 @@
 namespace tint {
 namespace ast {
 
-ArrayAccessorExpression::ArrayAccessorExpression() : Expression() {}
+ArrayAccessorExpression::ArrayAccessorExpression() : Base() {}
 
 ArrayAccessorExpression::ArrayAccessorExpression(Expression* array,
                                                  Expression* idx_expr)
-    : Expression(), array_(array), idx_expr_(idx_expr) {}
+    : Base(), array_(array), idx_expr_(idx_expr) {}
 
 ArrayAccessorExpression::ArrayAccessorExpression(const Source& source,
                                                  Expression* array,
                                                  Expression* idx_expr)
-    : Expression(source), array_(array), idx_expr_(idx_expr) {}
+    : Base(source), array_(array), idx_expr_(idx_expr) {}
 
 ArrayAccessorExpression::ArrayAccessorExpression(ArrayAccessorExpression&&) =
     default;
diff --git a/src/ast/array_accessor_expression.h b/src/ast/array_accessor_expression.h
index bb716ec..f7e5192 100644
--- a/src/ast/array_accessor_expression.h
+++ b/src/ast/array_accessor_expression.h
@@ -25,7 +25,8 @@
 namespace ast {
 
 /// An array accessor expression
-class ArrayAccessorExpression : public Expression {
+class ArrayAccessorExpression
+    : public Castable<ArrayAccessorExpression, Expression> {
  public:
   /// Constructor
   ArrayAccessorExpression();
diff --git a/src/ast/array_decoration.cc b/src/ast/array_decoration.cc
index 7832e9b..088a87f 100644
--- a/src/ast/array_decoration.cc
+++ b/src/ast/array_decoration.cc
@@ -23,7 +23,7 @@
 
 constexpr const DecorationKind ArrayDecoration::Kind;
 
-ArrayDecoration::ArrayDecoration(const Source& source) : Decoration(source) {}
+ArrayDecoration::ArrayDecoration(const Source& source) : Base(source) {}
 
 ArrayDecoration::~ArrayDecoration() = default;
 
diff --git a/src/ast/array_decoration.h b/src/ast/array_decoration.h
index f1a953b..92cb002 100644
--- a/src/ast/array_decoration.h
+++ b/src/ast/array_decoration.h
@@ -27,7 +27,7 @@
 class StrideDecoration;
 
 /// A decoration attached to an array
-class ArrayDecoration : public Decoration {
+class ArrayDecoration : public Castable<ArrayDecoration, Decoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kArray;
diff --git a/src/ast/assignment_statement.cc b/src/ast/assignment_statement.cc
index 0430624..cfad841 100644
--- a/src/ast/assignment_statement.cc
+++ b/src/ast/assignment_statement.cc
@@ -17,15 +17,15 @@
 namespace tint {
 namespace ast {
 
-AssignmentStatement::AssignmentStatement() : Statement() {}
+AssignmentStatement::AssignmentStatement() : Base() {}
 
 AssignmentStatement::AssignmentStatement(Expression* lhs, Expression* rhs)
-    : Statement(), lhs_(lhs), rhs_(rhs) {}
+    : Base(), lhs_(lhs), rhs_(rhs) {}
 
 AssignmentStatement::AssignmentStatement(const Source& source,
                                          Expression* lhs,
                                          Expression* rhs)
-    : Statement(source), lhs_(lhs), rhs_(rhs) {}
+    : Base(source), lhs_(lhs), rhs_(rhs) {}
 
 AssignmentStatement::AssignmentStatement(AssignmentStatement&&) = default;
 
diff --git a/src/ast/assignment_statement.h b/src/ast/assignment_statement.h
index 0a2c379..dd68ca0 100644
--- a/src/ast/assignment_statement.h
+++ b/src/ast/assignment_statement.h
@@ -26,7 +26,7 @@
 namespace ast {
 
 /// An assignment statement
-class AssignmentStatement : public Statement {
+class AssignmentStatement : public Castable<AssignmentStatement, Statement> {
  public:
   /// Constructor
   AssignmentStatement();
diff --git a/src/ast/binary_expression.cc b/src/ast/binary_expression.cc
index 25d7fb7..d43caeb 100644
--- a/src/ast/binary_expression.cc
+++ b/src/ast/binary_expression.cc
@@ -17,18 +17,18 @@
 namespace tint {
 namespace ast {
 
-BinaryExpression::BinaryExpression() : Expression() {}
+BinaryExpression::BinaryExpression() : Base() {}
 
 BinaryExpression::BinaryExpression(BinaryOp op,
                                    Expression* lhs,
                                    Expression* rhs)
-    : Expression(), op_(op), lhs_(lhs), rhs_(rhs) {}
+    : Base(), op_(op), lhs_(lhs), rhs_(rhs) {}
 
 BinaryExpression::BinaryExpression(const Source& source,
                                    BinaryOp op,
                                    Expression* lhs,
                                    Expression* rhs)
-    : Expression(source), op_(op), lhs_(lhs), rhs_(rhs) {}
+    : Base(source), op_(op), lhs_(lhs), rhs_(rhs) {}
 
 BinaryExpression::BinaryExpression(BinaryExpression&&) = default;
 
diff --git a/src/ast/binary_expression.h b/src/ast/binary_expression.h
index 4ef24d8..e96d8da 100644
--- a/src/ast/binary_expression.h
+++ b/src/ast/binary_expression.h
@@ -48,7 +48,7 @@
 };
 
 /// An binary expression
-class BinaryExpression : public Expression {
+class BinaryExpression : public Castable<BinaryExpression, Expression> {
  public:
   /// Constructor
   BinaryExpression();
diff --git a/src/ast/binding_decoration.cc b/src/ast/binding_decoration.cc
index 2af35d9..671e319 100644
--- a/src/ast/binding_decoration.cc
+++ b/src/ast/binding_decoration.cc
@@ -20,7 +20,7 @@
 constexpr const DecorationKind BindingDecoration::Kind;
 
 BindingDecoration::BindingDecoration(uint32_t val, const Source& source)
-    : VariableDecoration(source), value_(val) {}
+    : Base(source), value_(val) {}
 
 BindingDecoration::~BindingDecoration() = default;
 
@@ -29,7 +29,7 @@
 }
 
 bool BindingDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || VariableDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool BindingDecoration::IsBinding() const {
diff --git a/src/ast/binding_decoration.h b/src/ast/binding_decoration.h
index 8e40626..e747edc 100644
--- a/src/ast/binding_decoration.h
+++ b/src/ast/binding_decoration.h
@@ -23,7 +23,8 @@
 namespace ast {
 
 /// A binding decoration
-class BindingDecoration : public VariableDecoration {
+class BindingDecoration
+    : public Castable<BindingDecoration, VariableDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kBinding;
diff --git a/src/ast/bitcast_expression.cc b/src/ast/bitcast_expression.cc
index 693c4ba..6d52a2b 100644
--- a/src/ast/bitcast_expression.cc
+++ b/src/ast/bitcast_expression.cc
@@ -17,15 +17,15 @@
 namespace tint {
 namespace ast {
 
-BitcastExpression::BitcastExpression() : Expression() {}
+BitcastExpression::BitcastExpression() : Base() {}
 
 BitcastExpression::BitcastExpression(type::Type* type, Expression* expr)
-    : Expression(), type_(type), expr_(expr) {}
+    : Base(), type_(type), expr_(expr) {}
 
 BitcastExpression::BitcastExpression(const Source& source,
                                      type::Type* type,
                                      Expression* expr)
-    : Expression(source), type_(type), expr_(expr) {}
+    : Base(source), type_(type), expr_(expr) {}
 
 BitcastExpression::BitcastExpression(BitcastExpression&&) = default;
 BitcastExpression::~BitcastExpression() = default;
diff --git a/src/ast/bitcast_expression.h b/src/ast/bitcast_expression.h
index 014787f..7a30c9e 100644
--- a/src/ast/bitcast_expression.h
+++ b/src/ast/bitcast_expression.h
@@ -26,7 +26,7 @@
 namespace ast {
 
 /// A bitcast expression
-class BitcastExpression : public Expression {
+class BitcastExpression : public Castable<BitcastExpression, Expression> {
  public:
   /// Constructor
   BitcastExpression();
diff --git a/src/ast/block_statement.cc b/src/ast/block_statement.cc
index 7934d02..a5aa5a9 100644
--- a/src/ast/block_statement.cc
+++ b/src/ast/block_statement.cc
@@ -17,9 +17,9 @@
 namespace tint {
 namespace ast {
 
-BlockStatement::BlockStatement() : Statement() {}
+BlockStatement::BlockStatement() : Base() {}
 
-BlockStatement::BlockStatement(const Source& source) : Statement(source) {}
+BlockStatement::BlockStatement(const Source& source) : Base(source) {}
 
 BlockStatement::BlockStatement(BlockStatement&&) = default;
 
diff --git a/src/ast/block_statement.h b/src/ast/block_statement.h
index eee8f7c..07189c7 100644
--- a/src/ast/block_statement.h
+++ b/src/ast/block_statement.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A block statement
-class BlockStatement : public Statement {
+class BlockStatement : public Castable<BlockStatement, Statement> {
  public:
   /// Constructor
   BlockStatement();
diff --git a/src/ast/bool_literal.cc b/src/ast/bool_literal.cc
index 7e11015..3fba92d 100644
--- a/src/ast/bool_literal.cc
+++ b/src/ast/bool_literal.cc
@@ -18,7 +18,7 @@
 namespace ast {
 
 BoolLiteral::BoolLiteral(ast::type::Type* type, bool value)
-    : Literal(type), value_(value) {}
+    : Base(type), value_(value) {}
 
 BoolLiteral::~BoolLiteral() = default;
 
diff --git a/src/ast/bool_literal.h b/src/ast/bool_literal.h
index fbb1868..9591470 100644
--- a/src/ast/bool_literal.h
+++ b/src/ast/bool_literal.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// A boolean literal
-class BoolLiteral : public Literal {
+class BoolLiteral : public Castable<BoolLiteral, Literal> {
  public:
   /// Constructor
   /// @param type the type of the literal
diff --git a/src/ast/break_statement.cc b/src/ast/break_statement.cc
index db543d3..ed70840 100644
--- a/src/ast/break_statement.cc
+++ b/src/ast/break_statement.cc
@@ -17,9 +17,9 @@
 namespace tint {
 namespace ast {
 
-BreakStatement::BreakStatement() : Statement() {}
+BreakStatement::BreakStatement() : Base() {}
 
-BreakStatement::BreakStatement(const Source& source) : Statement(source) {}
+BreakStatement::BreakStatement(const Source& source) : Base(source) {}
 
 BreakStatement::BreakStatement(BreakStatement&&) = default;
 
diff --git a/src/ast/break_statement.h b/src/ast/break_statement.h
index f29d5fc..13a7d57 100644
--- a/src/ast/break_statement.h
+++ b/src/ast/break_statement.h
@@ -21,7 +21,7 @@
 namespace ast {
 
 /// An break statement
-class BreakStatement : public Statement {
+class BreakStatement : public Castable<BreakStatement, Statement> {
  public:
   /// Constructor
   BreakStatement();
diff --git a/src/ast/builtin_decoration.cc b/src/ast/builtin_decoration.cc
index 28108d35..e59b592 100644
--- a/src/ast/builtin_decoration.cc
+++ b/src/ast/builtin_decoration.cc
@@ -20,7 +20,7 @@
 constexpr const DecorationKind BuiltinDecoration::Kind;
 
 BuiltinDecoration::BuiltinDecoration(Builtin builtin, const Source& source)
-    : VariableDecoration(source), builtin_(builtin) {}
+    : Base(source), builtin_(builtin) {}
 
 BuiltinDecoration::~BuiltinDecoration() = default;
 
@@ -29,7 +29,7 @@
 }
 
 bool BuiltinDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || VariableDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool BuiltinDecoration::IsBuiltin() const {
diff --git a/src/ast/builtin_decoration.h b/src/ast/builtin_decoration.h
index 07dedfe..cc0dc6d 100644
--- a/src/ast/builtin_decoration.h
+++ b/src/ast/builtin_decoration.h
@@ -22,7 +22,8 @@
 namespace ast {
 
 /// A builtin decoration
-class BuiltinDecoration : public VariableDecoration {
+class BuiltinDecoration
+    : public Castable<BuiltinDecoration, VariableDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kBuiltin;
diff --git a/src/ast/call_expression.cc b/src/ast/call_expression.cc
index c3d7d83..13c5efc 100644
--- a/src/ast/call_expression.cc
+++ b/src/ast/call_expression.cc
@@ -17,15 +17,15 @@
 namespace tint {
 namespace ast {
 
-CallExpression::CallExpression() : Expression() {}
+CallExpression::CallExpression() : Base() {}
 
 CallExpression::CallExpression(Expression* func, ExpressionList params)
-    : Expression(), func_(func), params_(params) {}
+    : Base(), func_(func), params_(params) {}
 
 CallExpression::CallExpression(const Source& source,
                                Expression* func,
                                ExpressionList params)
-    : Expression(source), func_(func), params_(params) {}
+    : Base(source), func_(func), params_(params) {}
 
 CallExpression::CallExpression(CallExpression&&) = default;
 
diff --git a/src/ast/call_expression.h b/src/ast/call_expression.h
index cae3f9c..c79dffd 100644
--- a/src/ast/call_expression.h
+++ b/src/ast/call_expression.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A call expression
-class CallExpression : public Expression {
+class CallExpression : public Castable<CallExpression, Expression> {
  public:
   /// Constructor
   CallExpression();
diff --git a/src/ast/call_statement.cc b/src/ast/call_statement.cc
index 7c43049..0ff5188 100644
--- a/src/ast/call_statement.cc
+++ b/src/ast/call_statement.cc
@@ -19,9 +19,9 @@
 namespace tint {
 namespace ast {
 
-CallStatement::CallStatement() : Statement() {}
+CallStatement::CallStatement() : Base() {}
 
-CallStatement::CallStatement(CallExpression* call) : Statement(), call_(call) {}
+CallStatement::CallStatement(CallExpression* call) : Base(), call_(call) {}
 
 CallStatement::CallStatement(CallStatement&&) = default;
 
diff --git a/src/ast/call_statement.h b/src/ast/call_statement.h
index c4cee4d..c74f156 100644
--- a/src/ast/call_statement.h
+++ b/src/ast/call_statement.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A call expression
-class CallStatement : public Statement {
+class CallStatement : public Castable<CallStatement, Statement> {
  public:
   /// Constructor
   CallStatement();
diff --git a/src/ast/case_statement.cc b/src/ast/case_statement.cc
index 667390c..84cda94 100644
--- a/src/ast/case_statement.cc
+++ b/src/ast/case_statement.cc
@@ -17,15 +17,15 @@
 namespace tint {
 namespace ast {
 
-CaseStatement::CaseStatement(BlockStatement* body) : Statement(), body_(body) {}
+CaseStatement::CaseStatement(BlockStatement* body) : Base(), body_(body) {}
 
 CaseStatement::CaseStatement(CaseSelectorList selectors, BlockStatement* body)
-    : Statement(), selectors_(selectors), body_(body) {}
+    : Base(), selectors_(selectors), body_(body) {}
 
 CaseStatement::CaseStatement(const Source& source,
                              CaseSelectorList selectors,
                              BlockStatement* body)
-    : Statement(source), selectors_(selectors), body_(body) {}
+    : Base(source), selectors_(selectors), body_(body) {}
 
 CaseStatement::CaseStatement(CaseStatement&&) = default;
 
diff --git a/src/ast/case_statement.h b/src/ast/case_statement.h
index 73844fd..aacd2f0 100644
--- a/src/ast/case_statement.h
+++ b/src/ast/case_statement.h
@@ -31,7 +31,7 @@
 using CaseSelectorList = std::vector<IntLiteral*>;
 
 /// A case statement
-class CaseStatement : public Statement {
+class CaseStatement : public Castable<CaseStatement, Statement> {
  public:
   /// Constructor
   /// Creates a default case statement
diff --git a/src/ast/constant_id_decoration.cc b/src/ast/constant_id_decoration.cc
index 3cd219d..7b1bc53 100644
--- a/src/ast/constant_id_decoration.cc
+++ b/src/ast/constant_id_decoration.cc
@@ -20,7 +20,7 @@
 constexpr const DecorationKind ConstantIdDecoration::Kind;
 
 ConstantIdDecoration::ConstantIdDecoration(uint32_t val, const Source& source)
-    : VariableDecoration(source), value_(val) {}
+    : Base(source), value_(val) {}
 
 ConstantIdDecoration::~ConstantIdDecoration() = default;
 
@@ -29,7 +29,7 @@
 }
 
 bool ConstantIdDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || VariableDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool ConstantIdDecoration::IsConstantId() const {
diff --git a/src/ast/constant_id_decoration.h b/src/ast/constant_id_decoration.h
index b2776fd..cc260cf 100644
--- a/src/ast/constant_id_decoration.h
+++ b/src/ast/constant_id_decoration.h
@@ -22,7 +22,8 @@
 namespace ast {
 
 /// A constant id decoration
-class ConstantIdDecoration : public VariableDecoration {
+class ConstantIdDecoration
+    : public Castable<ConstantIdDecoration, VariableDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kConstantId;
diff --git a/src/ast/constructor_expression.cc b/src/ast/constructor_expression.cc
index 5202bdf..6aae250 100644
--- a/src/ast/constructor_expression.cc
+++ b/src/ast/constructor_expression.cc
@@ -26,8 +26,10 @@
 
 ConstructorExpression::~ConstructorExpression() = default;
 
+ConstructorExpression::ConstructorExpression(ConstructorExpression&&) = default;
+
 ConstructorExpression::ConstructorExpression(const Source& source)
-    : Expression(source) {}
+    : Base(source) {}
 
 bool ConstructorExpression::IsConstructor() const {
   return true;
diff --git a/src/ast/constructor_expression.h b/src/ast/constructor_expression.h
index 5aaa5c3..9613318 100644
--- a/src/ast/constructor_expression.h
+++ b/src/ast/constructor_expression.h
@@ -24,7 +24,8 @@
 class TypeConstructorExpression;
 
 /// Base class for constructor style expressions
-class ConstructorExpression : public Expression {
+class ConstructorExpression
+    : public Castable<ConstructorExpression, Expression> {
  public:
   ~ConstructorExpression() override;
 
@@ -48,7 +49,7 @@
   /// @param source the constructor source
   explicit ConstructorExpression(const Source& source);
   /// Move constructor
-  ConstructorExpression(ConstructorExpression&&) = default;
+  ConstructorExpression(ConstructorExpression&&);
 
  private:
   ConstructorExpression(const ConstructorExpression&) = delete;
diff --git a/src/ast/continue_statement.cc b/src/ast/continue_statement.cc
index efc17d9..f66a958 100644
--- a/src/ast/continue_statement.cc
+++ b/src/ast/continue_statement.cc
@@ -17,10 +17,9 @@
 namespace tint {
 namespace ast {
 
-ContinueStatement::ContinueStatement() : Statement() {}
+ContinueStatement::ContinueStatement() : Base() {}
 
-ContinueStatement::ContinueStatement(const Source& source)
-    : Statement(source) {}
+ContinueStatement::ContinueStatement(const Source& source) : Base(source) {}
 
 ContinueStatement::ContinueStatement(ContinueStatement&&) = default;
 
diff --git a/src/ast/continue_statement.h b/src/ast/continue_statement.h
index 866917b..1eb93f9 100644
--- a/src/ast/continue_statement.h
+++ b/src/ast/continue_statement.h
@@ -24,7 +24,7 @@
 namespace ast {
 
 /// An continue statement
-class ContinueStatement : public Statement {
+class ContinueStatement : public Castable<ContinueStatement, Statement> {
  public:
   /// Constructor
   ContinueStatement();
diff --git a/src/ast/decorated_variable.cc b/src/ast/decorated_variable.cc
index cd83395..9b30e57 100644
--- a/src/ast/decorated_variable.cc
+++ b/src/ast/decorated_variable.cc
@@ -24,7 +24,7 @@
 DecoratedVariable::DecoratedVariable() = default;
 
 DecoratedVariable::DecoratedVariable(Variable* var)
-    : Variable(var->source(), var->name(), var->storage_class(), var->type()) {}
+    : Base(var->source(), var->name(), var->storage_class(), var->type()) {}
 
 DecoratedVariable::DecoratedVariable(DecoratedVariable&&) = default;
 
diff --git a/src/ast/decorated_variable.h b/src/ast/decorated_variable.h
index 8c2c34b..1eeea8c 100644
--- a/src/ast/decorated_variable.h
+++ b/src/ast/decorated_variable.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A Decorated Variable statement.
-class DecoratedVariable : public Variable {
+class DecoratedVariable : public Castable<DecoratedVariable, Variable> {
  public:
   /// Create a new empty decorated variable statement
   DecoratedVariable();
diff --git a/src/ast/decoration.h b/src/ast/decoration.h
index c7dffdb..bf30452 100644
--- a/src/ast/decoration.h
+++ b/src/ast/decoration.h
@@ -47,7 +47,7 @@
 std::ostream& operator<<(std::ostream& out, DecorationKind data);
 
 /// The base class for all decorations
-class Decoration : public Node {
+class Decoration : public Castable<Decoration, Node> {
  public:
   ~Decoration() override;
 
@@ -59,19 +59,13 @@
   /// kind.
   virtual bool IsKind(DecorationKind kind) const = 0;
 
-  /// @return true if this decoration is of (or derives from) type |TO|
-  template <typename TO>
-  bool Is() const {
-    return IsKind(TO::Kind);
-  }
-
   /// @returns true if the node is valid
   bool IsValid() const override;
 
  protected:
   /// Constructor
   /// @param source the source of this decoration
-  explicit Decoration(const Source& source) : Node(source) {}
+  explicit Decoration(const Source& source) : Base(source) {}
 };
 
 /// As dynamically casts |deco| to the target type |TO|.
diff --git a/src/ast/decoration_test.cc b/src/ast/decoration_test.cc
index a9beaac..1df9f9c 100644
--- a/src/ast/decoration_test.cc
+++ b/src/ast/decoration_test.cc
@@ -57,7 +57,7 @@
 }
 
 TEST_F(DecorationTest, Is) {
-  auto* decoration = create<ConstantIdDecoration>(1, Source{});
+  Decoration* decoration = create<ConstantIdDecoration>(1, Source{});
   EXPECT_TRUE(decoration->Is<VariableDecoration>());
   EXPECT_FALSE(decoration->Is<ArrayDecoration>());
 }
diff --git a/src/ast/discard_statement.cc b/src/ast/discard_statement.cc
index 6864aa0..e2c17fa 100644
--- a/src/ast/discard_statement.cc
+++ b/src/ast/discard_statement.cc
@@ -17,9 +17,11 @@
 namespace tint {
 namespace ast {
 
-DiscardStatement::DiscardStatement() : Statement() {}
+DiscardStatement::DiscardStatement() : Base() {}
 
-DiscardStatement::DiscardStatement(const Source& source) : Statement(source) {}
+DiscardStatement::DiscardStatement(const Source& source) : Base(source) {}
+
+DiscardStatement::DiscardStatement(DiscardStatement&&) = default;
 
 DiscardStatement::~DiscardStatement() = default;
 
diff --git a/src/ast/discard_statement.h b/src/ast/discard_statement.h
index af0f3fd..6f2e42a 100644
--- a/src/ast/discard_statement.h
+++ b/src/ast/discard_statement.h
@@ -21,7 +21,7 @@
 namespace ast {
 
 /// A discard statement
-class DiscardStatement : public Statement {
+class DiscardStatement : public Castable<DiscardStatement, Statement> {
  public:
   /// Constructor
   DiscardStatement();
@@ -29,7 +29,7 @@
   /// @param source the discard statement source
   explicit DiscardStatement(const Source& source);
   /// Move constructor
-  DiscardStatement(DiscardStatement&&) = default;
+  DiscardStatement(DiscardStatement&&);
   ~DiscardStatement() override;
 
   /// @returns true if this is a discard statement
diff --git a/src/ast/else_statement.cc b/src/ast/else_statement.cc
index b084f8d..00279c3 100644
--- a/src/ast/else_statement.cc
+++ b/src/ast/else_statement.cc
@@ -17,18 +17,18 @@
 namespace tint {
 namespace ast {
 
-ElseStatement::ElseStatement(BlockStatement* body) : Statement(), body_(body) {}
+ElseStatement::ElseStatement(BlockStatement* body) : Base(), body_(body) {}
 
 ElseStatement::ElseStatement(Expression* condition, BlockStatement* body)
-    : Statement(), condition_(condition), body_(body) {}
+    : Base(), condition_(condition), body_(body) {}
 
 ElseStatement::ElseStatement(const Source& source, BlockStatement* body)
-    : Statement(source), body_(body) {}
+    : Base(source), body_(body) {}
 
 ElseStatement::ElseStatement(const Source& source,
                              Expression* condition,
                              BlockStatement* body)
-    : Statement(source), condition_(condition), body_(body) {}
+    : Base(source), condition_(condition), body_(body) {}
 
 ElseStatement::ElseStatement(ElseStatement&&) = default;
 
diff --git a/src/ast/else_statement.h b/src/ast/else_statement.h
index c1feb6e..b75904d 100644
--- a/src/ast/else_statement.h
+++ b/src/ast/else_statement.h
@@ -27,7 +27,7 @@
 namespace ast {
 
 /// An else statement
-class ElseStatement : public Statement {
+class ElseStatement : public Castable<ElseStatement, Statement> {
  public:
   /// Constructor
   /// @param body the else body
diff --git a/src/ast/expression.cc b/src/ast/expression.cc
index 90d597e..0f77f2e 100644
--- a/src/ast/expression.cc
+++ b/src/ast/expression.cc
@@ -31,7 +31,9 @@
 
 Expression::Expression() = default;
 
-Expression::Expression(const Source& source) : Node(source) {}
+Expression::Expression(const Source& source) : Base(source) {}
+
+Expression::Expression(Expression&&) = default;
 
 Expression::~Expression() = default;
 
diff --git a/src/ast/expression.h b/src/ast/expression.h
index e696812..c4d85d4 100644
--- a/src/ast/expression.h
+++ b/src/ast/expression.h
@@ -35,7 +35,7 @@
 class UnaryOpExpression;
 
 /// Base expression class
-class Expression : public Node {
+class Expression : public Castable<Expression, Node> {
  public:
   ~Expression() override;
 
@@ -109,7 +109,7 @@
   /// @param source the source of the expression
   explicit Expression(const Source& source);
   /// Move constructor
-  Expression(Expression&&) = default;
+  Expression(Expression&&);
 
  private:
   Expression(const Expression&) = delete;
diff --git a/src/ast/fallthrough_statement.cc b/src/ast/fallthrough_statement.cc
index 9abb2d2..6c84ab3 100644
--- a/src/ast/fallthrough_statement.cc
+++ b/src/ast/fallthrough_statement.cc
@@ -17,10 +17,12 @@
 namespace tint {
 namespace ast {
 
-FallthroughStatement::FallthroughStatement() : Statement() {}
+FallthroughStatement::FallthroughStatement() : Base() {}
 
 FallthroughStatement::FallthroughStatement(const Source& source)
-    : Statement(source) {}
+    : Base(source) {}
+
+FallthroughStatement::FallthroughStatement(FallthroughStatement&&) = default;
 
 FallthroughStatement::~FallthroughStatement() = default;
 
diff --git a/src/ast/fallthrough_statement.h b/src/ast/fallthrough_statement.h
index 7579e49..f586666 100644
--- a/src/ast/fallthrough_statement.h
+++ b/src/ast/fallthrough_statement.h
@@ -21,7 +21,7 @@
 namespace ast {
 
 /// An fallthrough statement
-class FallthroughStatement : public Statement {
+class FallthroughStatement : public Castable<FallthroughStatement, Statement> {
  public:
   /// Constructor
   FallthroughStatement();
@@ -29,7 +29,7 @@
   /// @param source the source information
   explicit FallthroughStatement(const Source& source);
   /// Move constructor
-  FallthroughStatement(FallthroughStatement&&) = default;
+  FallthroughStatement(FallthroughStatement&&);
   ~FallthroughStatement() override;
 
   /// @returns true if this is an fallthrough statement
diff --git a/src/ast/float_literal.cc b/src/ast/float_literal.cc
index 3d6d1f8..d7b6a31 100644
--- a/src/ast/float_literal.cc
+++ b/src/ast/float_literal.cc
@@ -21,7 +21,7 @@
 namespace ast {
 
 FloatLiteral::FloatLiteral(ast::type::Type* type, float value)
-    : Literal(type), value_(value) {}
+    : Base(type), value_(value) {}
 
 FloatLiteral::~FloatLiteral() = default;
 
diff --git a/src/ast/float_literal.h b/src/ast/float_literal.h
index 44977c2..d8b69e4 100644
--- a/src/ast/float_literal.h
+++ b/src/ast/float_literal.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// A float literal
-class FloatLiteral : public Literal {
+class FloatLiteral : public Castable<FloatLiteral, Literal> {
  public:
   /// Constructor
   /// @param type the type of the literal
diff --git a/src/ast/function.cc b/src/ast/function.cc
index 0d20fc1..da38be0 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -32,7 +32,7 @@
                    VariableList params,
                    type::Type* return_type,
                    BlockStatement* body)
-    : Node(),
+    : Base(),
       name_(name),
       params_(std::move(params)),
       return_type_(return_type),
@@ -43,7 +43,7 @@
                    VariableList params,
                    type::Type* return_type,
                    BlockStatement* body)
-    : Node(source),
+    : Base(source),
       name_(name),
       params_(std::move(params)),
       return_type_(return_type),
diff --git a/src/ast/function.h b/src/ast/function.h
index 679a6d8..acaf30c 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -40,7 +40,7 @@
 namespace ast {
 
 /// A Function statement.
-class Function : public Node {
+class Function : public Castable<Function, Node> {
  public:
   /// Information about a binding
   struct BindingInfo {
diff --git a/src/ast/function_decoration.cc b/src/ast/function_decoration.cc
index 2d11714..36861c4 100644
--- a/src/ast/function_decoration.cc
+++ b/src/ast/function_decoration.cc
@@ -24,8 +24,7 @@
 
 constexpr const DecorationKind FunctionDecoration::Kind;
 
-FunctionDecoration::FunctionDecoration(const Source& source)
-    : Decoration(source) {}
+FunctionDecoration::FunctionDecoration(const Source& source) : Base(source) {}
 
 FunctionDecoration::~FunctionDecoration() = default;
 
diff --git a/src/ast/function_decoration.h b/src/ast/function_decoration.h
index 86b9514..5c15a6c 100644
--- a/src/ast/function_decoration.h
+++ b/src/ast/function_decoration.h
@@ -28,7 +28,7 @@
 class WorkgroupDecoration;
 
 /// A decoration attached to a function
-class FunctionDecoration : public Decoration {
+class FunctionDecoration : public Castable<FunctionDecoration, Decoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kFunction;
diff --git a/src/ast/identifier_expression.cc b/src/ast/identifier_expression.cc
index 76f92a2..ecad6ad 100644
--- a/src/ast/identifier_expression.cc
+++ b/src/ast/identifier_expression.cc
@@ -18,11 +18,11 @@
 namespace ast {
 
 IdentifierExpression::IdentifierExpression(const std::string& name)
-    : Expression(), name_(name) {}
+    : Base(), name_(name) {}
 
 IdentifierExpression::IdentifierExpression(const Source& source,
                                            const std::string& name)
-    : Expression(source), name_(name) {}
+    : Base(source), name_(name) {}
 
 IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
 
diff --git a/src/ast/identifier_expression.h b/src/ast/identifier_expression.h
index 4c6ac31..b13fb0e 100644
--- a/src/ast/identifier_expression.h
+++ b/src/ast/identifier_expression.h
@@ -26,7 +26,7 @@
 namespace ast {
 
 /// An identifier expression
-class IdentifierExpression : public Expression {
+class IdentifierExpression : public Castable<IdentifierExpression, Expression> {
  public:
   /// Constructor
   /// @param name the name
diff --git a/src/ast/if_statement.cc b/src/ast/if_statement.cc
index 6e4ffbe..bcf156c 100644
--- a/src/ast/if_statement.cc
+++ b/src/ast/if_statement.cc
@@ -20,12 +20,12 @@
 namespace ast {
 
 IfStatement::IfStatement(Expression* condition, BlockStatement* body)
-    : Statement(), condition_(condition), body_(body) {}
+    : Base(), condition_(condition), body_(body) {}
 
 IfStatement::IfStatement(const Source& source,
                          Expression* condition,
                          BlockStatement* body)
-    : Statement(source), condition_(condition), body_(body) {}
+    : Base(source), condition_(condition), body_(body) {}
 
 IfStatement::IfStatement(IfStatement&&) = default;
 
diff --git a/src/ast/if_statement.h b/src/ast/if_statement.h
index 62b53eb..4b8a0fb 100644
--- a/src/ast/if_statement.h
+++ b/src/ast/if_statement.h
@@ -27,7 +27,7 @@
 namespace ast {
 
 /// An if statement
-class IfStatement : public Statement {
+class IfStatement : public Castable<IfStatement, Statement> {
  public:
   /// Constructor
   /// @param condition the if condition
diff --git a/src/ast/int_literal.cc b/src/ast/int_literal.cc
index c641ac2..20480d2 100644
--- a/src/ast/int_literal.cc
+++ b/src/ast/int_literal.cc
@@ -17,7 +17,7 @@
 namespace tint {
 namespace ast {
 
-IntLiteral::IntLiteral(ast::type::Type* type) : Literal(type) {}
+IntLiteral::IntLiteral(ast::type::Type* type) : Base(type) {}
 
 IntLiteral::~IntLiteral() = default;
 
diff --git a/src/ast/int_literal.h b/src/ast/int_literal.h
index 8f09299..d23fceb 100644
--- a/src/ast/int_literal.h
+++ b/src/ast/int_literal.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// An integer literal. This could be either signed or unsigned.
-class IntLiteral : public Literal {
+class IntLiteral : public Castable<IntLiteral, Literal> {
  public:
   ~IntLiteral() override;
 
diff --git a/src/ast/literal.h b/src/ast/literal.h
index 2154b2b..b8c1b7c 100644
--- a/src/ast/literal.h
+++ b/src/ast/literal.h
@@ -31,7 +31,7 @@
 class UintLiteral;
 
 /// Base class for a literal value
-class Literal : public Node {
+class Literal : public Castable<Literal, Node> {
  public:
   ~Literal() override;
 
diff --git a/src/ast/location_decoration.cc b/src/ast/location_decoration.cc
index 51737d9..1ca0e39 100644
--- a/src/ast/location_decoration.cc
+++ b/src/ast/location_decoration.cc
@@ -20,7 +20,7 @@
 constexpr const DecorationKind LocationDecoration::Kind;
 
 LocationDecoration::LocationDecoration(uint32_t val, const Source& source)
-    : VariableDecoration(source), value_(val) {}
+    : Base(source), value_(val) {}
 
 LocationDecoration::~LocationDecoration() = default;
 
@@ -29,7 +29,7 @@
 }
 
 bool LocationDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || VariableDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool LocationDecoration::IsLocation() const {
diff --git a/src/ast/location_decoration.h b/src/ast/location_decoration.h
index ae7aed1..c99267d 100644
--- a/src/ast/location_decoration.h
+++ b/src/ast/location_decoration.h
@@ -23,7 +23,8 @@
 namespace ast {
 
 /// A location decoration
-class LocationDecoration : public VariableDecoration {
+class LocationDecoration
+    : public Castable<LocationDecoration, VariableDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kLocation;
diff --git a/src/ast/loop_statement.cc b/src/ast/loop_statement.cc
index d1e865d..fbffebe 100644
--- a/src/ast/loop_statement.cc
+++ b/src/ast/loop_statement.cc
@@ -18,12 +18,12 @@
 namespace ast {
 
 LoopStatement::LoopStatement(BlockStatement* body, BlockStatement* continuing)
-    : Statement(), body_(body), continuing_(continuing) {}
+    : Base(), body_(body), continuing_(continuing) {}
 
 LoopStatement::LoopStatement(const Source& source,
                              BlockStatement* body,
                              BlockStatement* continuing)
-    : Statement(source), body_(body), continuing_(continuing) {}
+    : Base(source), body_(body), continuing_(continuing) {}
 
 LoopStatement::LoopStatement(LoopStatement&&) = default;
 
diff --git a/src/ast/loop_statement.h b/src/ast/loop_statement.h
index d0d959f..f1ed192 100644
--- a/src/ast/loop_statement.h
+++ b/src/ast/loop_statement.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A loop statement
-class LoopStatement : public Statement {
+class LoopStatement : public Castable<LoopStatement, Statement> {
  public:
   /// Constructor
   /// @param body the body statements
diff --git a/src/ast/member_accessor_expression.cc b/src/ast/member_accessor_expression.cc
index 18ca50d..029c272 100644
--- a/src/ast/member_accessor_expression.cc
+++ b/src/ast/member_accessor_expression.cc
@@ -21,12 +21,12 @@
 
 MemberAccessorExpression::MemberAccessorExpression(Expression* structure,
                                                    IdentifierExpression* member)
-    : Expression(), struct_(structure), member_(member) {}
+    : Base(), struct_(structure), member_(member) {}
 
 MemberAccessorExpression::MemberAccessorExpression(const Source& source,
                                                    Expression* structure,
                                                    IdentifierExpression* member)
-    : Expression(source), struct_(structure), member_(member) {}
+    : Base(source), struct_(structure), member_(member) {}
 
 MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) =
     default;
diff --git a/src/ast/member_accessor_expression.h b/src/ast/member_accessor_expression.h
index f0c9aa9..006ef88 100644
--- a/src/ast/member_accessor_expression.h
+++ b/src/ast/member_accessor_expression.h
@@ -27,7 +27,8 @@
 namespace ast {
 
 /// A member accessor expression
-class MemberAccessorExpression : public Expression {
+class MemberAccessorExpression
+    : public Castable<MemberAccessorExpression, Expression> {
  public:
   /// Constructor
   MemberAccessorExpression();
diff --git a/src/ast/node.cc b/src/ast/node.cc
index 8870db0..2c7395b 100644
--- a/src/ast/node.cc
+++ b/src/ast/node.cc
@@ -23,6 +23,8 @@
 
 Node::Node(const Source& source) : source_(source) {}
 
+Node::Node(Node&&) = default;
+
 Node::~Node() = default;
 
 void Node::make_indent(std::ostream& out, size_t indent) const {
diff --git a/src/ast/node.h b/src/ast/node.h
index 9ab4db6..9bfe8d6 100644
--- a/src/ast/node.h
+++ b/src/ast/node.h
@@ -18,15 +18,16 @@
 #include <ostream>
 #include <string>
 
+#include "src/castable.h"
 #include "src/source.h"
 
 namespace tint {
 namespace ast {
 
 /// AST base class node
-class Node {
+class Node : public Castable<Node> {
  public:
-  virtual ~Node();
+  ~Node() override;
 
   /// @returns the node source data
   const Source& source() const { return source_; }
@@ -53,7 +54,7 @@
   /// @param source The input source for the node
   explicit Node(const Source& source);
   /// Move constructor
-  Node(Node&&) = default;
+  Node(Node&&);
 
   /// Writes indent into stream
   /// @param out the stream to write to
diff --git a/src/ast/null_literal.cc b/src/ast/null_literal.cc
index 7d44751..3c759ed 100644
--- a/src/ast/null_literal.cc
+++ b/src/ast/null_literal.cc
@@ -17,7 +17,7 @@
 namespace tint {
 namespace ast {
 
-NullLiteral::NullLiteral(ast::type::Type* type) : Literal(type) {}
+NullLiteral::NullLiteral(ast::type::Type* type) : Base(type) {}
 
 NullLiteral::~NullLiteral() = default;
 
diff --git a/src/ast/null_literal.h b/src/ast/null_literal.h
index cfe2a87..0c396c9 100644
--- a/src/ast/null_literal.h
+++ b/src/ast/null_literal.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// A null literal
-class NullLiteral : public Literal {
+class NullLiteral : public Castable<NullLiteral, Literal> {
  public:
   /// Constructor
   /// @param type the type
diff --git a/src/ast/return_statement.cc b/src/ast/return_statement.cc
index 8f78861..e395dfc 100644
--- a/src/ast/return_statement.cc
+++ b/src/ast/return_statement.cc
@@ -17,15 +17,14 @@
 namespace tint {
 namespace ast {
 
-ReturnStatement::ReturnStatement() : Statement() {}
+ReturnStatement::ReturnStatement() : Base() {}
 
-ReturnStatement::ReturnStatement(const Source& source) : Statement(source) {}
+ReturnStatement::ReturnStatement(const Source& source) : Base(source) {}
 
-ReturnStatement::ReturnStatement(Expression* value)
-    : Statement(), value_(value) {}
+ReturnStatement::ReturnStatement(Expression* value) : Base(), value_(value) {}
 
 ReturnStatement::ReturnStatement(const Source& source, Expression* value)
-    : Statement(source), value_(value) {}
+    : Base(source), value_(value) {}
 
 ReturnStatement::ReturnStatement(ReturnStatement&&) = default;
 
diff --git a/src/ast/return_statement.h b/src/ast/return_statement.h
index 4605fd7..a1177f7 100644
--- a/src/ast/return_statement.h
+++ b/src/ast/return_statement.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A return statement
-class ReturnStatement : public Statement {
+class ReturnStatement : public Castable<ReturnStatement, Statement> {
  public:
   /// Constructor
   ReturnStatement();
diff --git a/src/ast/scalar_constructor_expression.cc b/src/ast/scalar_constructor_expression.cc
index f82983d..02fee32 100644
--- a/src/ast/scalar_constructor_expression.cc
+++ b/src/ast/scalar_constructor_expression.cc
@@ -17,15 +17,14 @@
 namespace tint {
 namespace ast {
 
-ScalarConstructorExpression::ScalarConstructorExpression()
-    : ConstructorExpression() {}
+ScalarConstructorExpression::ScalarConstructorExpression() : Base() {}
 
 ScalarConstructorExpression::ScalarConstructorExpression(Literal* literal)
     : literal_(literal) {}
 
 ScalarConstructorExpression::ScalarConstructorExpression(const Source& source,
                                                          Literal* litearl)
-    : ConstructorExpression(source), literal_(litearl) {}
+    : Base(source), literal_(litearl) {}
 
 ScalarConstructorExpression::ScalarConstructorExpression(
     ScalarConstructorExpression&&) = default;
diff --git a/src/ast/scalar_constructor_expression.h b/src/ast/scalar_constructor_expression.h
index 360a2e8..d780fef 100644
--- a/src/ast/scalar_constructor_expression.h
+++ b/src/ast/scalar_constructor_expression.h
@@ -25,7 +25,8 @@
 namespace ast {
 
 /// A scalar constructor
-class ScalarConstructorExpression : public ConstructorExpression {
+class ScalarConstructorExpression
+    : public Castable<ScalarConstructorExpression, ConstructorExpression> {
  public:
   /// Constructor
   ScalarConstructorExpression();
diff --git a/src/ast/set_decoration.cc b/src/ast/set_decoration.cc
index 08d5312..4178e4d 100644
--- a/src/ast/set_decoration.cc
+++ b/src/ast/set_decoration.cc
@@ -18,7 +18,7 @@
 namespace ast {
 
 SetDecoration::SetDecoration(uint32_t val, const Source& source)
-    : VariableDecoration(source), value_(val) {}
+    : Base(source), value_(val) {}
 
 SetDecoration::~SetDecoration() = default;
 
diff --git a/src/ast/set_decoration.h b/src/ast/set_decoration.h
index 5398c88..73469c4 100644
--- a/src/ast/set_decoration.h
+++ b/src/ast/set_decoration.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// A set decoration
-class SetDecoration : public VariableDecoration {
+class SetDecoration : public Castable<SetDecoration, VariableDecoration> {
  public:
   /// constructor
   /// @param value the set value
diff --git a/src/ast/sint_literal.cc b/src/ast/sint_literal.cc
index 93aab83..6a5da13 100644
--- a/src/ast/sint_literal.cc
+++ b/src/ast/sint_literal.cc
@@ -18,7 +18,7 @@
 namespace ast {
 
 SintLiteral::SintLiteral(ast::type::Type* type, int32_t value)
-    : IntLiteral(type), value_(value) {}
+    : Base(type), value_(value) {}
 
 SintLiteral::~SintLiteral() = default;
 
diff --git a/src/ast/sint_literal.h b/src/ast/sint_literal.h
index 3995148..0e4db04 100644
--- a/src/ast/sint_literal.h
+++ b/src/ast/sint_literal.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// A signed int literal
-class SintLiteral : public IntLiteral {
+class SintLiteral : public Castable<SintLiteral, IntLiteral> {
  public:
   /// Constructor
   /// @param type the type
diff --git a/src/ast/stage_decoration.cc b/src/ast/stage_decoration.cc
index ae996c8..307503b 100644
--- a/src/ast/stage_decoration.cc
+++ b/src/ast/stage_decoration.cc
@@ -20,7 +20,7 @@
 constexpr const DecorationKind StageDecoration::Kind;
 
 StageDecoration::StageDecoration(ast::PipelineStage stage, const Source& source)
-    : FunctionDecoration(source), stage_(stage) {}
+    : Base(source), stage_(stage) {}
 
 StageDecoration::~StageDecoration() = default;
 
@@ -29,7 +29,7 @@
 }
 
 bool StageDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || FunctionDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool StageDecoration::IsStage() const {
diff --git a/src/ast/stage_decoration.h b/src/ast/stage_decoration.h
index 0b7e94a..15b1d60 100644
--- a/src/ast/stage_decoration.h
+++ b/src/ast/stage_decoration.h
@@ -22,7 +22,7 @@
 namespace ast {
 
 /// A workgroup decoration
-class StageDecoration : public FunctionDecoration {
+class StageDecoration : public Castable<StageDecoration, FunctionDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kStage;
diff --git a/src/ast/statement.cc b/src/ast/statement.cc
index cd3e09d..f44286f 100644
--- a/src/ast/statement.cc
+++ b/src/ast/statement.cc
@@ -36,7 +36,7 @@
 
 Statement::Statement() = default;
 
-Statement::Statement(const Source& source) : Node(source) {}
+Statement::Statement(const Source& source) : Base(source) {}
 
 Statement::Statement(Statement&&) = default;
 
diff --git a/src/ast/statement.h b/src/ast/statement.h
index c75b091..7e791ba 100644
--- a/src/ast/statement.h
+++ b/src/ast/statement.h
@@ -39,7 +39,7 @@
 class VariableDeclStatement;
 
 /// Base statement class
-class Statement : public Node {
+class Statement : public Castable<Statement, Node> {
  public:
   ~Statement() override;
 
diff --git a/src/ast/stride_decoration.cc b/src/ast/stride_decoration.cc
index d92bf58..8e30f3c 100644
--- a/src/ast/stride_decoration.cc
+++ b/src/ast/stride_decoration.cc
@@ -20,14 +20,14 @@
 constexpr const DecorationKind StrideDecoration::Kind;
 
 StrideDecoration::StrideDecoration(uint32_t stride, const Source& source)
-    : ArrayDecoration(source), stride_(stride) {}
+    : Base(source), stride_(stride) {}
 
 DecorationKind StrideDecoration::GetKind() const {
   return Kind;
 }
 
 bool StrideDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || ArrayDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool StrideDecoration::IsStride() const {
diff --git a/src/ast/stride_decoration.h b/src/ast/stride_decoration.h
index f97734e..a64754a 100644
--- a/src/ast/stride_decoration.h
+++ b/src/ast/stride_decoration.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// A stride decoration
-class StrideDecoration : public ArrayDecoration {
+class StrideDecoration : public Castable<StrideDecoration, ArrayDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kStride;
diff --git a/src/ast/struct.cc b/src/ast/struct.cc
index 73dc11f..525afe4 100644
--- a/src/ast/struct.cc
+++ b/src/ast/struct.cc
@@ -17,23 +17,23 @@
 namespace tint {
 namespace ast {
 
-Struct::Struct() : Node() {}
+Struct::Struct() : Base() {}
 
 Struct::Struct(StructMemberList members)
-    : Node(), members_(std::move(members)) {}
+    : Base(), members_(std::move(members)) {}
 
 Struct::Struct(StructDecorationList decorations, StructMemberList members)
-    : Node(),
+    : Base(),
       decorations_(std::move(decorations)),
       members_(std::move(members)) {}
 
 Struct::Struct(const Source& source, StructMemberList members)
-    : Node(source), members_(std::move(members)) {}
+    : Base(source), members_(std::move(members)) {}
 
 Struct::Struct(const Source& source,
                StructDecorationList decorations,
                StructMemberList members)
-    : Node(source),
+    : Base(source),
       decorations_(std::move(decorations)),
       members_(std::move(members)) {}
 
diff --git a/src/ast/struct.h b/src/ast/struct.h
index 8a55b8d..419b270 100644
--- a/src/ast/struct.h
+++ b/src/ast/struct.h
@@ -27,7 +27,7 @@
 namespace ast {
 
 /// A struct statement.
-class Struct : public Node {
+class Struct : public Castable<Struct, Node> {
  public:
   /// Create a new empty struct statement
   Struct();
diff --git a/src/ast/struct_block_decoration.cc b/src/ast/struct_block_decoration.cc
index 585646d..33fa124 100644
--- a/src/ast/struct_block_decoration.cc
+++ b/src/ast/struct_block_decoration.cc
@@ -18,7 +18,7 @@
 namespace ast {
 
 StructBlockDecoration::StructBlockDecoration(const Source& source)
-    : StructDecoration(source) {}
+    : Base(source) {}
 
 StructBlockDecoration::~StructBlockDecoration() = default;
 
diff --git a/src/ast/struct_block_decoration.h b/src/ast/struct_block_decoration.h
index 34b031c..9c06255 100644
--- a/src/ast/struct_block_decoration.h
+++ b/src/ast/struct_block_decoration.h
@@ -25,7 +25,8 @@
 namespace ast {
 
 /// The struct decorations
-class StructBlockDecoration : public StructDecoration {
+class StructBlockDecoration
+    : public Castable<StructBlockDecoration, StructDecoration> {
  public:
   /// constructor
   /// @param source the source of this decoration
diff --git a/src/ast/struct_decoration.cc b/src/ast/struct_decoration.cc
index 5b93b90..68b54a4 100644
--- a/src/ast/struct_decoration.cc
+++ b/src/ast/struct_decoration.cc
@@ -19,7 +19,7 @@
 
 constexpr const DecorationKind StructDecoration::Kind;
 
-StructDecoration::StructDecoration(const Source& source) : Decoration(source) {}
+StructDecoration::StructDecoration(const Source& source) : Base(source) {}
 
 StructDecoration::~StructDecoration() = default;
 
diff --git a/src/ast/struct_decoration.h b/src/ast/struct_decoration.h
index 727ba7d..75d3e69 100644
--- a/src/ast/struct_decoration.h
+++ b/src/ast/struct_decoration.h
@@ -25,7 +25,7 @@
 namespace ast {
 
 /// The struct decorations
-class StructDecoration : public Decoration {
+class StructDecoration : public Castable<StructDecoration, Decoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kStruct;
diff --git a/src/ast/struct_member.cc b/src/ast/struct_member.cc
index 8d54ad5..6293234 100644
--- a/src/ast/struct_member.cc
+++ b/src/ast/struct_member.cc
@@ -24,13 +24,13 @@
 StructMember::StructMember(const std::string& name,
                            type::Type* type,
                            StructMemberDecorationList decorations)
-    : Node(), name_(name), type_(type), decorations_(std::move(decorations)) {}
+    : Base(), name_(name), type_(type), decorations_(std::move(decorations)) {}
 
 StructMember::StructMember(const Source& source,
                            const std::string& name,
                            type::Type* type,
                            StructMemberDecorationList decorations)
-    : Node(source),
+    : Base(source),
       name_(name),
       type_(type),
       decorations_(std::move(decorations)) {}
diff --git a/src/ast/struct_member.h b/src/ast/struct_member.h
index 00dd870..ea18502 100644
--- a/src/ast/struct_member.h
+++ b/src/ast/struct_member.h
@@ -29,7 +29,7 @@
 namespace ast {
 
 /// A struct member statement.
-class StructMember : public Node {
+class StructMember : public Castable<StructMember, Node> {
  public:
   /// Create a new empty struct member statement
   StructMember();
diff --git a/src/ast/struct_member_decoration.cc b/src/ast/struct_member_decoration.cc
index 8573bc7..b56ec52 100644
--- a/src/ast/struct_member_decoration.cc
+++ b/src/ast/struct_member_decoration.cc
@@ -24,7 +24,7 @@
 constexpr const DecorationKind StructMemberDecoration::Kind;
 
 StructMemberDecoration::StructMemberDecoration(const Source& source)
-    : Decoration(source) {}
+    : Base(source) {}
 
 StructMemberDecoration::~StructMemberDecoration() = default;
 
diff --git a/src/ast/struct_member_decoration.h b/src/ast/struct_member_decoration.h
index 1652df3..2c1400a 100644
--- a/src/ast/struct_member_decoration.h
+++ b/src/ast/struct_member_decoration.h
@@ -27,7 +27,8 @@
 class StructMemberOffsetDecoration;
 
 /// A decoration attached to a struct member
-class StructMemberDecoration : public Decoration {
+class StructMemberDecoration
+    : public Castable<StructMemberDecoration, Decoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kStructMember;
diff --git a/src/ast/struct_member_offset_decoration.cc b/src/ast/struct_member_offset_decoration.cc
index c211c5b..2436658 100644
--- a/src/ast/struct_member_offset_decoration.cc
+++ b/src/ast/struct_member_offset_decoration.cc
@@ -21,14 +21,14 @@
 
 StructMemberOffsetDecoration::StructMemberOffsetDecoration(uint32_t offset,
                                                            const Source& source)
-    : StructMemberDecoration(source), offset_(offset) {}
+    : Base(source), offset_(offset) {}
 
 DecorationKind StructMemberOffsetDecoration::GetKind() const {
   return Kind;
 }
 
 bool StructMemberOffsetDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || StructMemberDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool StructMemberOffsetDecoration::IsOffset() const {
diff --git a/src/ast/struct_member_offset_decoration.h b/src/ast/struct_member_offset_decoration.h
index 60a2068..531336d 100644
--- a/src/ast/struct_member_offset_decoration.h
+++ b/src/ast/struct_member_offset_decoration.h
@@ -25,7 +25,8 @@
 namespace ast {
 
 /// A struct member offset decoration
-class StructMemberOffsetDecoration : public StructMemberDecoration {
+class StructMemberOffsetDecoration
+    : public Castable<StructMemberOffsetDecoration, StructMemberDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind =
diff --git a/src/ast/switch_statement.cc b/src/ast/switch_statement.cc
index 2d86fcb..65bb68f 100644
--- a/src/ast/switch_statement.cc
+++ b/src/ast/switch_statement.cc
@@ -19,7 +19,7 @@
 namespace tint {
 namespace ast {
 
-SwitchStatement::SwitchStatement() : Statement() {}
+SwitchStatement::SwitchStatement() : Base() {}
 
 SwitchStatement::SwitchStatement(Expression* condition, CaseStatementList body)
     : condition_(condition), body_(body) {}
@@ -27,7 +27,7 @@
 SwitchStatement::SwitchStatement(const Source& source,
                                  Expression* condition,
                                  CaseStatementList body)
-    : Statement(source), condition_(condition), body_(body) {}
+    : Base(source), condition_(condition), body_(body) {}
 
 bool SwitchStatement::IsSwitch() const {
   return true;
diff --git a/src/ast/switch_statement.h b/src/ast/switch_statement.h
index e5346da..656918d 100644
--- a/src/ast/switch_statement.h
+++ b/src/ast/switch_statement.h
@@ -27,7 +27,7 @@
 namespace ast {
 
 /// A switch statement
-class SwitchStatement : public Statement {
+class SwitchStatement : public Castable<SwitchStatement, Statement> {
  public:
   /// Constructor
   SwitchStatement();
diff --git a/src/ast/type_constructor_expression.cc b/src/ast/type_constructor_expression.cc
index 3168df0..8f1d8a8 100644
--- a/src/ast/type_constructor_expression.cc
+++ b/src/ast/type_constructor_expression.cc
@@ -17,17 +17,16 @@
 namespace tint {
 namespace ast {
 
-TypeConstructorExpression::TypeConstructorExpression()
-    : ConstructorExpression() {}
+TypeConstructorExpression::TypeConstructorExpression() : Base() {}
 
 TypeConstructorExpression::TypeConstructorExpression(type::Type* type,
                                                      ExpressionList values)
-    : ConstructorExpression(), type_(type), values_(std::move(values)) {}
+    : Base(), type_(type), values_(std::move(values)) {}
 
 TypeConstructorExpression::TypeConstructorExpression(const Source& source,
                                                      type::Type* type,
                                                      ExpressionList values)
-    : ConstructorExpression(source), type_(type), values_(std::move(values)) {}
+    : Base(source), type_(type), values_(std::move(values)) {}
 
 TypeConstructorExpression::TypeConstructorExpression(
     TypeConstructorExpression&&) = default;
diff --git a/src/ast/type_constructor_expression.h b/src/ast/type_constructor_expression.h
index 68ad2d1..ae911e8 100644
--- a/src/ast/type_constructor_expression.h
+++ b/src/ast/type_constructor_expression.h
@@ -25,7 +25,8 @@
 namespace ast {
 
 /// A type specific constructor
-class TypeConstructorExpression : public ConstructorExpression {
+class TypeConstructorExpression
+    : public Castable<TypeConstructorExpression, ConstructorExpression> {
  public:
   TypeConstructorExpression();
   /// Constructor
diff --git a/src/ast/type_decoration.cc b/src/ast/type_decoration.cc
index 763d24c..3f08e1a 100644
--- a/src/ast/type_decoration.cc
+++ b/src/ast/type_decoration.cc
@@ -23,7 +23,7 @@
 
 constexpr const DecorationKind TypeDecoration::Kind;
 
-TypeDecoration::TypeDecoration(const Source& source) : Decoration(source) {}
+TypeDecoration::TypeDecoration(const Source& source) : Base(source) {}
 
 TypeDecoration::~TypeDecoration() = default;
 
diff --git a/src/ast/type_decoration.h b/src/ast/type_decoration.h
index f515a4b..7b96218 100644
--- a/src/ast/type_decoration.h
+++ b/src/ast/type_decoration.h
@@ -28,7 +28,7 @@
 class AccessDecoration;
 
 /// A decoration attached to a type
-class TypeDecoration : public Decoration {
+class TypeDecoration : public Castable<TypeDecoration, Decoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kType;
diff --git a/src/ast/uint_literal.cc b/src/ast/uint_literal.cc
index 078066b..4548a4f 100644
--- a/src/ast/uint_literal.cc
+++ b/src/ast/uint_literal.cc
@@ -18,7 +18,7 @@
 namespace ast {
 
 UintLiteral::UintLiteral(ast::type::Type* type, uint32_t value)
-    : IntLiteral(type), value_(value) {}
+    : Base(type), value_(value) {}
 
 UintLiteral::~UintLiteral() = default;
 
diff --git a/src/ast/uint_literal.h b/src/ast/uint_literal.h
index 6189ee4..f15642a 100644
--- a/src/ast/uint_literal.h
+++ b/src/ast/uint_literal.h
@@ -23,7 +23,7 @@
 namespace ast {
 
 /// A uint literal
-class UintLiteral : public IntLiteral {
+class UintLiteral : public Castable<UintLiteral, IntLiteral> {
  public:
   /// Constructor
   /// @param type the type of the literal
diff --git a/src/ast/unary_op_expression.cc b/src/ast/unary_op_expression.cc
index d519451..ed60a62 100644
--- a/src/ast/unary_op_expression.cc
+++ b/src/ast/unary_op_expression.cc
@@ -17,15 +17,15 @@
 namespace tint {
 namespace ast {
 
-UnaryOpExpression::UnaryOpExpression() : Expression() {}
+UnaryOpExpression::UnaryOpExpression() : Base() {}
 
 UnaryOpExpression::UnaryOpExpression(UnaryOp op, Expression* expr)
-    : Expression(), op_(op), expr_(expr) {}
+    : Base(), op_(op), expr_(expr) {}
 
 UnaryOpExpression::UnaryOpExpression(const Source& source,
                                      UnaryOp op,
                                      Expression* expr)
-    : Expression(source), op_(op), expr_(expr) {}
+    : Base(source), op_(op), expr_(expr) {}
 
 UnaryOpExpression::UnaryOpExpression(UnaryOpExpression&&) = default;
 
diff --git a/src/ast/unary_op_expression.h b/src/ast/unary_op_expression.h
index 918d779..67d9e01 100644
--- a/src/ast/unary_op_expression.h
+++ b/src/ast/unary_op_expression.h
@@ -26,7 +26,7 @@
 namespace ast {
 
 /// A unary op expression
-class UnaryOpExpression : public Expression {
+class UnaryOpExpression : public Castable<UnaryOpExpression, Expression> {
  public:
   /// Constructor
   UnaryOpExpression();
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
index 408b6f4..67b2ed1 100644
--- a/src/ast/variable.cc
+++ b/src/ast/variable.cc
@@ -24,13 +24,13 @@
 Variable::Variable() = default;
 
 Variable::Variable(const std::string& name, StorageClass sc, type::Type* type)
-    : Node(), name_(name), storage_class_(sc), type_(type) {}
+    : Base(), name_(name), storage_class_(sc), type_(type) {}
 
 Variable::Variable(const Source& source,
                    const std::string& name,
                    StorageClass sc,
                    type::Type* type)
-    : Node(source), name_(name), storage_class_(sc), type_(type) {}
+    : Base(source), name_(name), storage_class_(sc), type_(type) {}
 
 Variable::Variable(Variable&&) = default;
 
diff --git a/src/ast/variable.h b/src/ast/variable.h
index 711d6b7..6445946 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -78,7 +78,7 @@
 /// defaulting syntax for a "var" declared inside a function.
 /// The storage class for a "const" is always StorageClass::kNone.
 /// The storage class for a formal parameter is always StorageClass::kNone.
-class Variable : public Node {
+class Variable : public Castable<Variable, Node> {
  public:
   /// Create a new empty variable statement
   Variable();
diff --git a/src/ast/variable_decl_statement.cc b/src/ast/variable_decl_statement.cc
index 2a509be..732c166 100644
--- a/src/ast/variable_decl_statement.cc
+++ b/src/ast/variable_decl_statement.cc
@@ -17,14 +17,14 @@
 namespace tint {
 namespace ast {
 
-VariableDeclStatement::VariableDeclStatement() : Statement() {}
+VariableDeclStatement::VariableDeclStatement() : Base() {}
 
 VariableDeclStatement::VariableDeclStatement(Variable* variable)
-    : Statement(), variable_(variable) {}
+    : Base(), variable_(variable) {}
 
 VariableDeclStatement::VariableDeclStatement(const Source& source,
                                              Variable* variable)
-    : Statement(source), variable_(variable) {}
+    : Base(source), variable_(variable) {}
 
 VariableDeclStatement::VariableDeclStatement(VariableDeclStatement&&) = default;
 
diff --git a/src/ast/variable_decl_statement.h b/src/ast/variable_decl_statement.h
index a628991..a233029 100644
--- a/src/ast/variable_decl_statement.h
+++ b/src/ast/variable_decl_statement.h
@@ -26,7 +26,8 @@
 namespace ast {
 
 /// A variable declaration statement
-class VariableDeclStatement : public Statement {
+class VariableDeclStatement
+    : public Castable<VariableDeclStatement, Statement> {
  public:
   /// Constructor
   VariableDeclStatement();
diff --git a/src/ast/variable_decoration.cc b/src/ast/variable_decoration.cc
index 9b7d2c0..84ed238 100644
--- a/src/ast/variable_decoration.cc
+++ b/src/ast/variable_decoration.cc
@@ -27,8 +27,7 @@
 
 constexpr const DecorationKind VariableDecoration::Kind;
 
-VariableDecoration::VariableDecoration(const Source& source)
-    : Decoration(source) {}
+VariableDecoration::VariableDecoration(const Source& source) : Base(source) {}
 
 VariableDecoration::~VariableDecoration() = default;
 
diff --git a/src/ast/variable_decoration.h b/src/ast/variable_decoration.h
index e5c18fd..8fd4e44 100644
--- a/src/ast/variable_decoration.h
+++ b/src/ast/variable_decoration.h
@@ -32,7 +32,7 @@
 class SetDecoration;
 
 /// A decoration attached to a variable
-class VariableDecoration : public Decoration {
+class VariableDecoration : public Castable<VariableDecoration, Decoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kVariable;
diff --git a/src/ast/workgroup_decoration.cc b/src/ast/workgroup_decoration.cc
index 1c4c58b..045143b 100644
--- a/src/ast/workgroup_decoration.cc
+++ b/src/ast/workgroup_decoration.cc
@@ -20,18 +20,18 @@
 constexpr const DecorationKind WorkgroupDecoration::Kind;
 
 WorkgroupDecoration::WorkgroupDecoration(uint32_t x, const Source& source)
-    : FunctionDecoration(source), x_(x) {}
+    : Base(source), x_(x) {}
 
 WorkgroupDecoration::WorkgroupDecoration(uint32_t x,
                                          uint32_t y,
                                          const Source& source)
-    : FunctionDecoration(source), x_(x), y_(y) {}
+    : Base(source), x_(x), y_(y) {}
 
 WorkgroupDecoration::WorkgroupDecoration(uint32_t x,
                                          uint32_t y,
                                          uint32_t z,
                                          const Source& source)
-    : FunctionDecoration(source), x_(x), y_(y), z_(z) {}
+    : Base(source), x_(x), y_(y), z_(z) {}
 
 WorkgroupDecoration::~WorkgroupDecoration() = default;
 
@@ -40,7 +40,7 @@
 }
 
 bool WorkgroupDecoration::IsKind(DecorationKind kind) const {
-  return kind == Kind || FunctionDecoration::IsKind(kind);
+  return kind == Kind || Base::IsKind(kind);
 }
 
 bool WorkgroupDecoration::IsWorkgroup() const {
diff --git a/src/ast/workgroup_decoration.h b/src/ast/workgroup_decoration.h
index fbdbf06..41c690c 100644
--- a/src/ast/workgroup_decoration.h
+++ b/src/ast/workgroup_decoration.h
@@ -25,7 +25,8 @@
 namespace ast {
 
 /// A workgroup decoration
-class WorkgroupDecoration : public FunctionDecoration {
+class WorkgroupDecoration
+    : public Castable<WorkgroupDecoration, FunctionDecoration> {
  public:
   /// The kind of decoration that this type represents
   static constexpr const DecorationKind Kind = DecorationKind::kWorkgroup;