wgsl parser: replace almost all sem::Type* with typ::Type where possible

All that remains in the wgsl parser that references sem::Type* are
the register_constructed funcs/types, and adding an ast::ExternalTexture
type.

Also:

* Added specialization of OperatorArrow for type::TypePairs that returns
the value by reference so that operator-> can chain properly.

* In a few places where we expect the type to implicitly cast to a
pointer for a bool expression, e.g. `if (type)` or `TINT_ASSERT(type)`,
I added access to the `.sem` member of the TypePair. I tried adding an
implicit cast to bool, but this results in ambiguity in gtest for
equality comparisons.

* Constified more type pointers in type nodes

* Replaced header includes with forward declares in wgsl/parser_impl.h

Bug: tint:724
Change-Id: Ie0875aa4d4a5e830e3466ac40c63cd185f357200
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48881
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 280a40f..9d033c6 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -498,7 +498,6 @@
     "symbol_table.cc",
     "symbol_table.h",
     "traits.h",
-    "typepair.h",
     "transform/binding_point.h",
     "transform/binding_remapper.cc",
     "transform/binding_remapper.h",
@@ -522,6 +521,7 @@
     "transform/transform.h",
     "transform/vertex_pulling.cc",
     "transform/vertex_pulling.h",
+    "typepair.h",
     "utils/get_or_create.h",
     "utils/hash.h",
     "utils/math.h",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e4c6544..8b8b1ca 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -172,6 +172,8 @@
   ast/type_name.h
   ast/ast_type.cc  # TODO(bclayton) - rename to type.cc
   ast/type.h
+  ast/type_name.cc
+  ast/type_name.h
   ast/u32.cc
   ast/u32.h
   ast/uint_literal.cc
diff --git a/src/ast/function.cc b/src/ast/function.cc
index a14d3cb..403863f 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -27,7 +27,7 @@
                    const Source& source,
                    Symbol symbol,
                    VariableList params,
-                   sem::Type* return_type,
+                   typ::Type return_type,
                    BlockStatement* body,
                    DecorationList decorations,
                    DecorationList return_type_decorations)
@@ -45,7 +45,7 @@
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(param, program_id);
   }
   TINT_ASSERT(symbol_.IsValid());
-  TINT_ASSERT(return_type_);
+  TINT_ASSERT(return_type_.sem);
   for (auto* deco : decorations_) {
     TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(deco, program_id);
   }
@@ -81,7 +81,7 @@
   auto src = ctx->Clone(source());
   auto sym = ctx->Clone(symbol());
   auto p = ctx->Clone(params_);
-  auto* ret = ctx->Clone(return_type_);
+  auto ret = ctx->Clone(return_type_);
   auto* b = ctx->Clone(body_);
   auto decos = ctx->Clone(decorations_);
   auto ret_decos = ctx->Clone(return_type_decorations_);
diff --git a/src/ast/function.h b/src/ast/function.h
index bb43b2f..5a29133 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -28,6 +28,7 @@
 #include "src/ast/location_decoration.h"
 #include "src/ast/pipeline_stage.h"
 #include "src/ast/variable.h"
+#include "src/typepair.h"
 
 namespace tint {
 namespace ast {
@@ -48,7 +49,7 @@
            const Source& source,
            Symbol symbol,
            VariableList params,
-           sem::Type* return_type,
+           typ::Type return_type,
            BlockStatement* body,
            DecorationList decorations,
            DecorationList return_type_decorations);
@@ -76,7 +77,7 @@
   bool IsEntryPoint() const { return pipeline_stage() != PipelineStage::kNone; }
 
   /// @returns the function return type.
-  sem::Type* return_type() const { return return_type_; }
+  typ::Type return_type() const { return return_type_; }
 
   /// @returns the decorations attached to the function return type.
   const DecorationList& return_type_decorations() const {
@@ -114,7 +115,7 @@
 
   Symbol const symbol_;
   VariableList const params_;
-  sem::Type* const return_type_;
+  typ::Type const return_type_;
   BlockStatement* const body_;
   DecorationList const decorations_;
   DecorationList const return_type_decorations_;
diff --git a/src/ast/pointer.cc b/src/ast/pointer.cc
index 3a968dc..3c13998 100644
--- a/src/ast/pointer.cc
+++ b/src/ast/pointer.cc
@@ -23,7 +23,7 @@
 
 Pointer::Pointer(ProgramID program_id,
                  const Source& source,
-                 Type* subtype,
+                 Type* const subtype,
                  ast::StorageClass storage_class)
     : Base(program_id, source),
       subtype_(subtype),
diff --git a/src/ast/pointer.h b/src/ast/pointer.h
index 55882ed..a3364f6 100644
--- a/src/ast/pointer.h
+++ b/src/ast/pointer.h
@@ -33,14 +33,14 @@
   /// @param storage_class the storage class of the pointer
   Pointer(ProgramID program_id,
           const Source& source,
-          Type* subtype,
+          Type* const subtype,
           ast::StorageClass storage_class);
   /// Move constructor
   Pointer(Pointer&&);
   ~Pointer() override;
 
   /// @returns the pointee type
-  Type* type() const { return subtype_; }
+  Type* type() const { return const_cast<Type*>(subtype_); }
   /// @returns the storage class of the pointer
   ast::StorageClass storage_class() const { return storage_class_; }
 
@@ -58,7 +58,7 @@
   Pointer* Clone(CloneContext* ctx) const override;
 
  private:
-  Type* const subtype_;
+  Type const* const subtype_;
   ast::StorageClass const storage_class_;
 };
 
diff --git a/src/ast/sampled_texture.cc b/src/ast/sampled_texture.cc
index 9e1ad0d..6fe7cff 100644
--- a/src/ast/sampled_texture.cc
+++ b/src/ast/sampled_texture.cc
@@ -24,7 +24,7 @@
 SampledTexture::SampledTexture(ProgramID program_id,
                                const Source& source,
                                TextureDimension dim,
-                               Type* type)
+                               Type const* type)
     : Base(program_id, source, dim), type_(type) {
   TINT_ASSERT(type_);
 }
diff --git a/src/ast/sampled_texture.h b/src/ast/sampled_texture.h
index f7d9af9..3520d17 100644
--- a/src/ast/sampled_texture.h
+++ b/src/ast/sampled_texture.h
@@ -33,13 +33,13 @@
   SampledTexture(ProgramID program_id,
                  const Source& source,
                  TextureDimension dim,
-                 Type* type);
+                 Type const* type);
   /// Move constructor
   SampledTexture(SampledTexture&&);
   ~SampledTexture() override;
 
   /// @returns the subtype of the sampled texture
-  Type* type() const { return type_; }
+  Type* type() const { return const_cast<Type*>(type_); }
 
   /// @returns the name for this type
   std::string type_name() const override;
@@ -55,7 +55,7 @@
   SampledTexture* Clone(CloneContext* ctx) const override;
 
  private:
-  Type* const type_;
+  Type const* const type_;
 };
 
 }  // namespace ast
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
index bf42180..3837666 100644
--- a/src/ast/variable.cc
+++ b/src/ast/variable.cc
@@ -27,13 +27,13 @@
                    const Source& source,
                    const Symbol& sym,
                    StorageClass declared_storage_class,
-                   const sem::Type* declared_type,
+                   const typ::Type type,
                    bool is_const,
                    Expression* constructor,
                    DecorationList decorations)
     : Base(program_id, source),
       symbol_(sym),
-      declared_type_(declared_type),
+      type_(type),
       is_const_(is_const),
       constructor_(constructor),
       decorations_(std::move(decorations)),
@@ -41,7 +41,7 @@
   TINT_ASSERT(symbol_.IsValid());
   TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(symbol_, program_id);
   // no type means we must have a constructor to infer it
-  TINT_ASSERT(declared_type_ || constructor);
+  TINT_ASSERT(type_.sem || constructor);
   TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(constructor, program_id);
 }
 
@@ -73,7 +73,7 @@
 Variable* Variable::Clone(CloneContext* ctx) const {
   auto src = ctx->Clone(source());
   auto sym = ctx->Clone(symbol());
-  auto* ty = ctx->Clone(declared_type());
+  auto ty = ctx->Clone(type());
   auto* ctor = ctx->Clone(constructor());
   auto decos = ctx->Clone(decorations());
   return ctx->dst->create<Variable>(src, sym, declared_storage_class(), ty,
@@ -90,8 +90,8 @@
   out << (var_sem ? var_sem->StorageClass() : declared_storage_class())
       << std::endl;
   make_indent(out, indent);
-  if (declared_type_) {
-    out << declared_type_->type_name() << std::endl;
+  if (type_.sem) {
+    out << type_->type_name() << std::endl;
   }
 }
 
diff --git a/src/ast/variable.h b/src/ast/variable.h
index 1327c56..533743e 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -95,7 +95,7 @@
   /// @param source the variable source
   /// @param sym the variable symbol
   /// @param declared_storage_class the declared storage class
-  /// @param declared_type the declared variable type
+  /// @param type the declared variable type
   /// @param is_const true if the variable is const
   /// @param constructor the constructor expression
   /// @param decorations the variable decorations
@@ -103,7 +103,7 @@
            const Source& source,
            const Symbol& sym,
            StorageClass declared_storage_class,
-           const sem::Type* declared_type,
+           typ::Type type,
            bool is_const,
            Expression* constructor,
            DecorationList decorations);
@@ -116,9 +116,11 @@
   const Symbol& symbol() const { return symbol_; }
 
   /// @returns the declared type
-  sem::Type* declared_type() const {
-    return const_cast<sem::Type*>(declared_type_);
-  }
+  // TODO(crbug.com/tint/697): Remove and use type() instead
+  sem::Type* declared_type() const { return const_cast<sem::Type*>(type_.sem); }
+
+  /// @returns the variable type
+  typ::Type type() const { return type_; }
 
   /// @returns the declared storage class
   StorageClass declared_storage_class() const {
@@ -177,7 +179,7 @@
 
   Symbol const symbol_;
   // The value type if a const or formal paramter, and the store type if a var
-  const sem::Type* const declared_type_;
+  typ::Type const type_;
   bool const is_const_;
   Expression* const constructor_;
   DecorationList const decorations_;
diff --git a/src/ast/vector.cc b/src/ast/vector.cc
index 60e52a3..1b2a8a0 100644
--- a/src/ast/vector.cc
+++ b/src/ast/vector.cc
@@ -23,7 +23,7 @@
 
 Vector::Vector(ProgramID program_id,
                const Source& source,
-               Type* subtype,
+               Type const* subtype,
                uint32_t size)
     : Base(program_id, source), subtype_(subtype), size_(size) {
   TINT_ASSERT(size_ > 1);
diff --git a/src/ast/vector.h b/src/ast/vector.h
index 13e7cad..640c512 100644
--- a/src/ast/vector.h
+++ b/src/ast/vector.h
@@ -32,14 +32,14 @@
   /// @param size the number of elements in the vector
   Vector(ProgramID program_id,
          const Source& source,
-         Type* subtype,
+         Type const* subtype,
          uint32_t size);
   /// Move constructor
   Vector(Vector&&);
   ~Vector() override;
 
   /// @returns the type of the vector elements
-  Type* type() const { return subtype_; }
+  Type* type() const { return const_cast<Type*>(subtype_); }
   /// @returns the size of the vector
   uint32_t size() const { return size_; }
 
@@ -57,7 +57,7 @@
   Vector* Clone(CloneContext* ctx) const override;
 
  private:
-  Type* const subtype_;
+  Type const* const subtype_;
   uint32_t const size_;
 };
 
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 58f54fb..3c07f7b 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -15,13 +15,25 @@
 #include "src/reader/wgsl/parser_impl.h"
 
 #include "src/ast/access_decoration.h"
+#include "src/ast/array.h"
+#include "src/ast/assignment_statement.h"
 #include "src/ast/bitcast_expression.h"
+#include "src/ast/break_statement.h"
+#include "src/ast/call_statement.h"
 #include "src/ast/constant_id_decoration.h"
+#include "src/ast/continue_statement.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/fallthrough_statement.h"
+#include "src/ast/if_statement.h"
+#include "src/ast/loop_statement.h"
+#include "src/ast/return_statement.h"
 #include "src/ast/stage_decoration.h"
 #include "src/ast/struct_block_decoration.h"
+#include "src/ast/switch_statement.h"
+#include "src/ast/type_name.h"
 #include "src/ast/unary_op_expression.h"
+#include "src/ast/variable_decl_statement.h"
+#include "src/ast/vector.h"
 #include "src/ast/workgroup_decoration.h"
 #include "src/reader/wgsl/lexer.h"
 #include "src/sem/access_control_type.h"
@@ -185,7 +197,7 @@
 ParserImpl::FunctionHeader::FunctionHeader(Source src,
                                            std::string n,
                                            ast::VariableList p,
-                                           sem::Type* ret_ty,
+                                           typ::Type ret_ty,
                                            ast::DecorationList ret_decos)
     : source(src),
       name(n),
@@ -198,6 +210,21 @@
 ParserImpl::FunctionHeader& ParserImpl::FunctionHeader::operator=(
     const FunctionHeader& rhs) = default;
 
+ParserImpl::VarDeclInfo::VarDeclInfo() = default;
+
+ParserImpl::VarDeclInfo::VarDeclInfo(const VarDeclInfo&) = default;
+
+ParserImpl::VarDeclInfo::VarDeclInfo(Source source_in,
+                                     std::string name_in,
+                                     ast::StorageClass storage_class_in,
+                                     typ::Type type_in)
+    : source(std::move(source_in)),
+      name(std::move(name_in)),
+      storage_class(storage_class_in),
+      type(type_in) {}
+
+ParserImpl::VarDeclInfo::~VarDeclInfo() = default;
+
 ParserImpl::ParserImpl(Source::File const* file)
     : lexer_(std::make_unique<Lexer>(file->path, &file->content)) {}
 
@@ -519,14 +546,14 @@
 //  | sampled_texture_type LESS_THAN type_decl GREATER_THAN
 //  | multisampled_texture_type LESS_THAN type_decl GREATER_THAN
 //  | storage_texture_type LESS_THAN image_storage_type GREATER_THAN
-Maybe<sem::Type*> ParserImpl::texture_sampler_types() {
+Maybe<typ::Type> ParserImpl::texture_sampler_types() {
   auto type = sampler_type();
   if (type.matched)
     return type;
 
   type = depth_texture_type();
   if (type.matched)
-    return type.value;
+    return type;
 
   type = external_texture_type();
   if (type.matched)
@@ -540,7 +567,9 @@
     if (subtype.errored)
       return Failure::kErrored;
 
-    return builder_.create<sem::SampledTexture>(dim.value, subtype.value);
+    return typ::Type{
+        builder_.create<ast::SampledTexture>(dim.value, subtype.value),
+        builder_.create<sem::SampledTexture>(dim.value, subtype.value)};
   }
 
   auto ms_dim = multisampled_texture_type();
@@ -551,8 +580,9 @@
     if (subtype.errored)
       return Failure::kErrored;
 
-    return builder_.create<sem::MultisampledTexture>(ms_dim.value,
-                                                     subtype.value);
+    return typ::Type{
+        builder_.create<ast::MultisampledTexture>(ms_dim.value, subtype.value),
+        builder_.create<sem::MultisampledTexture>(ms_dim.value, subtype.value)};
   }
 
   auto storage = storage_texture_type();
@@ -565,10 +595,14 @@
     if (format.errored)
       return Failure::kErrored;
 
-    auto* subtype =
+    auto* subtype = ast::StorageTexture::SubtypeFor(format.value, builder_);
+    auto* subtype_sem =
         sem::StorageTexture::SubtypeFor(format.value, builder_.Types());
-    return builder_.create<sem::StorageTexture>(storage.value, format.value,
-                                                subtype);
+
+    return typ::Type{builder_.create<ast::StorageTexture>(
+                         storage.value, format.value, subtype),
+                     builder_.create<sem::StorageTexture>(
+                         storage.value, format.value, subtype_sem)};
   }
 
   return Failure::kNoMatch;
@@ -577,12 +611,15 @@
 // sampler_type
 //  : SAMPLER
 //  | SAMPLER_COMPARISON
-Maybe<sem::Type*> ParserImpl::sampler_type() {
+Maybe<typ::Type> ParserImpl::sampler_type() {
   if (match(Token::Type::kSampler))
-    return builder_.create<sem::Sampler>(ast::SamplerKind::kSampler);
+    return typ::Type{builder_.create<ast::Sampler>(ast::SamplerKind::kSampler),
+                     builder_.create<sem::Sampler>(ast::SamplerKind::kSampler)};
 
   if (match(Token::Type::kComparisonSampler))
-    return builder_.create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
+    return typ::Type{
+        builder_.create<ast::Sampler>(ast::SamplerKind::kComparisonSampler),
+        builder_.create<sem::Sampler>(ast::SamplerKind::kComparisonSampler)};
 
   return Failure::kNoMatch;
 }
@@ -618,9 +655,10 @@
 
 // external_texture_type
 //  : TEXTURE_EXTERNAL
-Maybe<sem::Type*> ParserImpl::external_texture_type() {
+Maybe<typ::Type> ParserImpl::external_texture_type() {
   if (match(Token::Type::kTextureExternal)) {
-    return builder_.create<sem::ExternalTexture>();
+    // TODO(crbug.com/tint/724): builder_.create<ast::ExternalTexture>()
+    return typ::Type{nullptr, builder_.create<sem::ExternalTexture>()};
   }
 
   return Failure::kNoMatch;
@@ -658,19 +696,26 @@
 //  | TEXTURE_DEPTH_2D_ARRAY
 //  | TEXTURE_DEPTH_CUBE
 //  | TEXTURE_DEPTH_CUBE_ARRAY
-Maybe<sem::Type*> ParserImpl::depth_texture_type() {
+Maybe<typ::Type> ParserImpl::depth_texture_type() {
   if (match(Token::Type::kTextureDepth2d))
-    return builder_.create<sem::DepthTexture>(ast::TextureDimension::k2d);
+    return typ::Type{
+        builder_.create<ast::DepthTexture>(ast::TextureDimension::k2d),
+        builder_.create<sem::DepthTexture>(ast::TextureDimension::k2d)};
 
   if (match(Token::Type::kTextureDepth2dArray))
-    return builder_.create<sem::DepthTexture>(ast::TextureDimension::k2dArray);
+    return typ::Type{
+        builder_.create<ast::DepthTexture>(ast::TextureDimension::k2dArray),
+        builder_.create<sem::DepthTexture>(ast::TextureDimension::k2dArray)};
 
   if (match(Token::Type::kTextureDepthCube))
-    return builder_.create<sem::DepthTexture>(ast::TextureDimension::kCube);
+    return typ::Type{
+        builder_.create<ast::DepthTexture>(ast::TextureDimension::kCube),
+        builder_.create<sem::DepthTexture>(ast::TextureDimension::kCube)};
 
   if (match(Token::Type::kTextureDepthCubeArray))
-    return builder_.create<sem::DepthTexture>(
-        ast::TextureDimension::kCubeArray);
+    return typ::Type{
+        builder_.create<ast::DepthTexture>(ast::TextureDimension::kCubeArray),
+        builder_.create<sem::DepthTexture>(ast::TextureDimension::kCubeArray)};
 
   return Failure::kNoMatch;
 }
@@ -906,7 +951,7 @@
 
 // type_alias
 //   : TYPE IDENT EQUAL type_decl
-Maybe<sem::Type*> ParserImpl::type_alias() {
+Maybe<typ::Type> ParserImpl::type_alias() {
   auto t = peek();
   if (!t.IsType())
     return Failure::kNoMatch;
@@ -928,11 +973,14 @@
   if (!type.matched)
     return add_error(peek(), "invalid type alias");
 
+  // TODO(crbug.com/tint/724): remove
   auto* alias = builder_.create<sem::Alias>(
       builder_.Symbols().Register(name.value), type.value);
   register_constructed(name.value, alias);
 
-  return alias;
+  return typ::Type{builder_.create<ast::Alias>(
+                       builder_.Symbols().Register(name.value), type.value),
+                   alias};
 }
 
 // type_decl
@@ -979,55 +1027,58 @@
 Maybe<typ::Type> ParserImpl::type_decl(ast::DecorationList& decos) {
   auto t = peek();
   if (match(Token::Type::kIdentifier)) {
+    // TODO(crbug.com/tint/697): Remove
     auto* ty = get_constructed(t.to_str());
     if (ty == nullptr)
       return add_error(t, "unknown constructed type '" + t.to_str() + "'");
 
-    // TODO(crbug.com/tint/724): builder_.create<ast::TypeName>(t.to_str())
-    return typ::Type{nullptr, ty};
+    return typ::Type{
+        builder_.create<ast::TypeName>(builder_.Symbols().Register(t.to_str())),
+        ty};
   }
 
   if (match(Token::Type::kBool))
-    return typ::Type{nullptr, builder_.create<sem::Bool>()};
+    return typ::Type{builder_.create<ast::Bool>(),
+                     builder_.create<sem::Bool>()};
 
   if (match(Token::Type::kF32))
-    return typ::Type{nullptr, builder_.create<sem::F32>()};
+    return typ::Type{builder_.create<ast::F32>(), builder_.create<sem::F32>()};
 
   if (match(Token::Type::kI32))
-    return typ::Type{nullptr, builder_.create<sem::I32>()};
+    return typ::Type{builder_.create<ast::I32>(), builder_.create<sem::I32>()};
 
   if (match(Token::Type::kU32))
-    return typ::Type{nullptr, builder_.create<sem::U32>()};
+    return typ::Type{builder_.create<ast::U32>(), builder_.create<sem::U32>()};
 
   if (t.IsVec2() || t.IsVec3() || t.IsVec4()) {
     next();  // Consume the peek
-    return from_deprecated(expect_type_decl_vector(t));
+    return expect_type_decl_vector(t);
   }
 
   if (match(Token::Type::kPtr))
-    return from_deprecated(expect_type_decl_pointer());
+    return expect_type_decl_pointer();
 
   if (match(Token::Type::kArray)) {
-    return from_deprecated(expect_type_decl_array(std::move(decos)));
+    return expect_type_decl_array(std::move(decos));
   }
 
   if (t.IsMat2x2() || t.IsMat2x3() || t.IsMat2x4() || t.IsMat3x2() ||
       t.IsMat3x3() || t.IsMat3x4() || t.IsMat4x2() || t.IsMat4x3() ||
       t.IsMat4x4()) {
     next();  // Consume the peek
-    return from_deprecated(expect_type_decl_matrix(t));
+    return expect_type_decl_matrix(t);
   }
 
   auto texture_or_sampler = texture_sampler_types();
   if (texture_or_sampler.errored)
     return Failure::kErrored;
   if (texture_or_sampler.matched)
-    return typ::Type{nullptr, texture_or_sampler.value};
+    return texture_or_sampler;
 
   return Failure::kNoMatch;
 }
 
-Expect<sem::Type*> ParserImpl::expect_type(const std::string& use) {
+Expect<typ::Type> ParserImpl::expect_type(const std::string& use) {
   auto type = type_decl();
   if (type.errored)
     return Failure::kErrored;
@@ -1036,10 +1087,10 @@
   return type.value;
 }
 
-Expect<sem::Type*> ParserImpl::expect_type_decl_pointer() {
+Expect<typ::Type> ParserImpl::expect_type_decl_pointer() {
   const char* use = "ptr declaration";
 
-  return expect_lt_gt_block(use, [&]() -> Expect<sem::Type*> {
+  return expect_lt_gt_block(use, [&]() -> Expect<typ::Type> {
     auto sc = expect_storage_class(use);
     if (sc.errored)
       return Failure::kErrored;
@@ -1051,11 +1102,12 @@
     if (subtype.errored)
       return Failure::kErrored;
 
-    return builder_.create<sem::Pointer>(subtype.value, sc.value);
+    return typ::Type{builder_.create<ast::Pointer>(subtype.value, sc.value),
+                     builder_.create<sem::Pointer>(subtype.value, sc.value)};
   });
 }
 
-Expect<sem::Type*> ParserImpl::expect_type_decl_vector(Token t) {
+Expect<typ::Type> ParserImpl::expect_type_decl_vector(Token t) {
   uint32_t count = 2;
   if (t.IsVec3())
     count = 3;
@@ -1068,14 +1120,15 @@
   if (subtype.errored)
     return Failure::kErrored;
 
-  return builder_.create<sem::Vector>(subtype.value, count);
+  return typ::Type{builder_.create<ast::Vector>(subtype.value.ast, count),
+                   builder_.create<sem::Vector>(subtype.value.sem, count)};
 }
 
-Expect<sem::Type*> ParserImpl::expect_type_decl_array(
+Expect<typ::Type> ParserImpl::expect_type_decl_array(
     ast::DecorationList decos) {
   const char* use = "array declaration";
 
-  return expect_lt_gt_block(use, [&]() -> Expect<sem::Type*> {
+  return expect_lt_gt_block(use, [&]() -> Expect<typ::Type> {
     auto subtype = expect_type(use);
     if (subtype.errored)
       return Failure::kErrored;
@@ -1088,11 +1141,13 @@
       size = val.value;
     }
 
-    return create<sem::ArrayType>(subtype.value, size, std::move(decos));
+    return typ::Type{
+        create<ast::Array>(subtype.value, size, decos),
+        create<sem::ArrayType>(subtype.value, size, std::move(decos))};
   });
 }
 
-Expect<sem::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
+Expect<typ::Type> ParserImpl::expect_type_decl_matrix(Token t) {
   uint32_t rows = 2;
   uint32_t columns = 2;
   if (t.IsMat3x2() || t.IsMat3x3() || t.IsMat3x4()) {
@@ -1112,7 +1167,8 @@
   if (subtype.errored)
     return Failure::kErrored;
 
-  return builder_.create<sem::Matrix>(subtype.value, rows, columns);
+  return typ::Type{builder_.create<ast::Matrix>(subtype.value, rows, columns),
+                   builder_.create<sem::Matrix>(subtype.value, rows, columns)};
 }
 
 // storage_class
@@ -1263,11 +1319,12 @@
 // function_type_decl
 //   : type_decl
 //   | VOID
-Maybe<sem::Type*> ParserImpl::function_type_decl() {
+Maybe<typ::Type> ParserImpl::function_type_decl() {
   if (match(Token::Type::kVoid))
-    return builder_.create<sem::Void>();
+    return typ::Type{builder_.create<ast::Void>(),
+                     builder_.create<sem::Void>()};
 
-  return to_deprecated(type_decl());
+  return type_decl();
 }
 
 // function_header
@@ -1297,7 +1354,7 @@
     }
   }
 
-  sem::Type* return_type = nullptr;
+  typ::Type return_type;
   ast::DecorationList return_decorations;
 
   if (match(Token::Type::kArrow)) {
@@ -1318,7 +1375,7 @@
       return_type = type.value;
     }
 
-    if (return_type->Is<sem::Void>()) {
+    if (return_type.ast->Is<ast::Void>()) {
       // crbug.com/tint/677: void has been removed from the language
       deprecated(tok.source(),
                  "omit '-> void' for functions that do not return a value");
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 871f86e..7ae13ba 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -23,15 +23,6 @@
 #include <vector>
 
 #include "src/ast/access_control.h"
-#include "src/ast/assignment_statement.h"
-#include "src/ast/break_statement.h"
-#include "src/ast/call_statement.h"
-#include "src/ast/continue_statement.h"
-#include "src/ast/if_statement.h"
-#include "src/ast/loop_statement.h"
-#include "src/ast/return_statement.h"
-#include "src/ast/switch_statement.h"
-#include "src/ast/variable_decl_statement.h"
 #include "src/program_builder.h"
 #include "src/reader/wgsl/parser_impl_detail.h"
 #include "src/reader/wgsl/token.h"
@@ -39,6 +30,18 @@
 #include "src/typepair.h"
 
 namespace tint {
+namespace ast {
+class AssignmentStatement;
+class BreakStatement;
+class CallStatement;
+class ContinueStatement;
+class IfStatement;
+class LoopStatement;
+class ReturnStatement;
+class SwitchStatement;
+class VariableDeclStatement;
+}  // namespace ast
+
 namespace reader {
 namespace wgsl {
 
@@ -236,7 +239,7 @@
     FunctionHeader(Source src,
                    std::string n,
                    ast::VariableList p,
-                   sem::Type* ret_ty,
+                   typ::Type ret_ty,
                    ast::DecorationList ret_decos);
     /// Destructor
     ~FunctionHeader();
@@ -252,13 +255,30 @@
     /// Function parameters
     ast::VariableList params;
     /// Function return type
-    sem::Type* return_type;
+    typ::Type return_type;
     /// Function return type decorations
     ast::DecorationList return_type_decorations;
   };
 
   /// VarDeclInfo contains the parsed information for variable declaration.
   struct VarDeclInfo {
+    /// Constructor
+    VarDeclInfo();
+    /// Copy constructor
+    /// @param other the VarDeclInfo to copy
+    VarDeclInfo(const VarDeclInfo& other);
+    /// Constructor
+    /// @param source_in variable declaration source
+    /// @param name_in variable name
+    /// @param storage_class_in variable storage class
+    /// @param type_in variable type
+    VarDeclInfo(Source source_in,
+                std::string name_in,
+                ast::StorageClass storage_class_in,
+                typ::Type type_in);
+    /// Destructor
+    ~VarDeclInfo();
+
     /// Variable declaration source
     Source source;
     /// Variable name
@@ -266,7 +286,7 @@
     /// Variable storage class
     ast::StorageClass storage_class;
     /// Variable type
-    sem::Type* type;
+    typ::Type type;
   };
 
   /// Creates a new parser using the given file
@@ -376,16 +396,10 @@
   Maybe<ast::StorageClass> variable_storage_decoration();
   /// Parses a `type_alias` grammar element
   /// @returns the type alias or nullptr on error
-  Maybe<sem::Type*> type_alias();
+  Maybe<typ::Type> type_alias();
   /// Parses a `type_decl` grammar element
   /// @returns the parsed Type or nullptr if none matched.
   Maybe<typ::Type> type_decl();
-  /// TODO(crbug.com/tint/724): Temporary until type_decl() returns
-  /// Maybe<ast::Type*>
-  /// @returns the parsed Type or nullptr if none matched.
-  Maybe<sem::Type*> type_decl_DEPRECATED() {
-    return to_deprecated(type_decl());
-  }
   /// Parses a `type_decl` grammar element with the given pre-parsed
   /// decorations.
   /// @param decos the list of decorations for the type.
@@ -416,10 +430,10 @@
   Maybe<ast::Function*> function_decl(ast::DecorationList& decos);
   /// Parses a `texture_sampler_types` grammar element
   /// @returns the parsed Type or nullptr if none matched.
-  Maybe<sem::Type*> texture_sampler_types();
+  Maybe<typ::Type> texture_sampler_types();
   /// Parses a `sampler_type` grammar element
   /// @returns the parsed Type or nullptr if none matched.
-  Maybe<sem::Type*> sampler_type();
+  Maybe<typ::Type> sampler_type();
   /// Parses a `multisampled_texture_type` grammar element
   /// @returns returns the multisample texture dimension or kNone if none
   /// matched.
@@ -433,17 +447,17 @@
   Maybe<ast::TextureDimension> storage_texture_type();
   /// Parses a `depth_texture_type` grammar element
   /// @returns the parsed Type or nullptr if none matched.
-  Maybe<sem::Type*> depth_texture_type();
+  Maybe<typ::Type> depth_texture_type();
   /// Parses a 'texture_external_type' grammar element
   /// @returns the parsed Type or nullptr if none matched
-  Maybe<sem::Type*> external_texture_type();
+  Maybe<typ::Type> external_texture_type();
   /// Parses a `image_storage_type` grammar element
   /// @param use a description of what was being parsed if an error was raised
   /// @returns returns the image format or kNone if none matched.
   Expect<ast::ImageFormat> expect_image_storage_type(const std::string& use);
   /// Parses a `function_type_decl` grammar element
   /// @returns the parsed type or nullptr otherwise
-  Maybe<sem::Type*> function_type_decl();
+  Maybe<typ::Type> function_type_decl();
   /// Parses a `function_header` grammar element
   /// @returns the parsed function header
   Maybe<FunctionHeader> function_header();
@@ -655,30 +669,6 @@
   Expect<ast::Decoration*> expect_decoration();
 
  private:
-  // TODO(crbug.com/tint/724): Helper to convert Maybe<typ::Type> to
-  // Maybe<sem::Type*> while we convert code
-  Maybe<sem::Type*> to_deprecated(const Maybe<typ::Type>& tp) {
-    if (tp.errored) {
-      return Failure::kErrored;
-    }
-    if (!tp.matched) {
-      return Failure::kNoMatch;
-    }
-    return tp.value;
-  }
-
-  //// TODO(crbug.com/tint/724): Helper to convert Maybe<sem::Type*> to
-  /// Maybe<typ::Type> while we / convert code
-  Maybe<typ::Type> from_deprecated(const Maybe<sem::Type*>& tp) {
-    if (tp.errored) {
-      return Failure::kErrored;
-    }
-    if (!tp.matched) {
-      return Failure::kNoMatch;
-    }
-    return typ::Type{nullptr, tp.value};
-  }
-
   /// ReturnType resolves to the return type for the function or lambda F.
   template <typename F>
   using ReturnType = typename std::result_of<F()>::type;
@@ -831,12 +821,12 @@
   /// Used to ensure that all decorations are consumed.
   bool expect_decorations_consumed(const ast::DecorationList& list);
 
-  Expect<sem::Type*> expect_type_decl_pointer();
-  Expect<sem::Type*> expect_type_decl_vector(Token t);
-  Expect<sem::Type*> expect_type_decl_array(ast::DecorationList decos);
-  Expect<sem::Type*> expect_type_decl_matrix(Token t);
+  Expect<typ::Type> expect_type_decl_pointer();
+  Expect<typ::Type> expect_type_decl_vector(Token t);
+  Expect<typ::Type> expect_type_decl_array(ast::DecorationList decos);
+  Expect<typ::Type> expect_type_decl_matrix(Token t);
 
-  Expect<sem::Type*> expect_type(const std::string& use);
+  Expect<typ::Type> expect_type(const std::string& use);
 
   Maybe<ast::Statement*> non_block_statement();
   Maybe<ast::Statement*> for_header_initializer();
diff --git a/src/reader/wgsl/parser_impl_break_stmt_test.cc b/src/reader/wgsl/parser_impl_break_stmt_test.cc
index c13525f..9ba1361 100644
--- a/src/reader/wgsl/parser_impl_break_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_break_stmt_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/ast/break_statement.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
 
 namespace tint {
diff --git a/src/reader/wgsl/parser_impl_call_stmt_test.cc b/src/reader/wgsl/parser_impl_call_stmt_test.cc
index e7f9ee4..5a1dfc2 100644
--- a/src/reader/wgsl/parser_impl_call_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_call_stmt_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/ast/call_statement.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
 
 namespace tint {
diff --git a/src/reader/wgsl/parser_impl_continue_stmt_test.cc b/src/reader/wgsl/parser_impl_continue_stmt_test.cc
index 9a27322..8eba255 100644
--- a/src/reader/wgsl/parser_impl_continue_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_continue_stmt_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/ast/continue_statement.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
 
 namespace tint {
diff --git a/src/reader/wgsl/parser_impl_detail.h b/src/reader/wgsl/parser_impl_detail.h
index 6d5d144..26f2813 100644
--- a/src/reader/wgsl/parser_impl_detail.h
+++ b/src/reader/wgsl/parser_impl_detail.h
@@ -16,6 +16,7 @@
 #define SRC_READER_WGSL_PARSER_IMPL_DETAIL_H_
 
 #include <memory>
+#include "src/typepair.h"
 
 namespace tint {
 namespace reader {
@@ -62,6 +63,17 @@
   static inline T* ptr(T* val) { return val; }
 };
 
+/// OperatorArrow template specialization for TypePair<T, U>.
+template <typename T, typename U>
+struct OperatorArrow<typ::TypePair<T, U>> {
+  /// type resolves to the same as input type to allow for operator-> chaining
+  using type = typ::TypePair<T, U>;
+  /// @param val the value held by `ParserImpl::Expect<T>` or
+  /// `ParserImpl::Maybe<T>`.
+  /// @return `val`.
+  static inline type& ptr(type& val) { return val; }
+};
+
 }  // namespace detail
 }  // namespace wgsl
 }  // namespace reader
diff --git a/src/reader/wgsl/parser_impl_statement_test.cc b/src/reader/wgsl/parser_impl_statement_test.cc
index 8c79b0d..153ebd3 100644
--- a/src/reader/wgsl/parser_impl_statement_test.cc
+++ b/src/reader/wgsl/parser_impl_statement_test.cc
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/ast/break_statement.h"
+#include "src/ast/continue_statement.h"
 #include "src/ast/discard_statement.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
 
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index 3d61b15..185ac69 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -22,7 +22,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Invalid) {
   auto p = parser("1234");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_EQ(t.errored, false);
   EXPECT_EQ(t.matched, false);
   EXPECT_EQ(t.value, nullptr);
@@ -40,7 +40,7 @@
 
   p->register_constructed("A", alias_type);
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -55,7 +55,7 @@
 TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) {
   auto p = parser("B");
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -69,7 +69,7 @@
   auto& builder = p->builder();
   auto* bool_type = builder.create<sem::Bool>();
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -83,7 +83,7 @@
   auto& builder = p->builder();
   auto* float_type = builder.create<sem::F32>();
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -97,7 +97,7 @@
   auto& builder = p->builder();
   auto* int_type = builder.create<sem::I32>();
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -111,7 +111,7 @@
   auto& builder = p->builder();
   auto* uint_type = builder.create<sem::U32>();
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -133,7 +133,7 @@
 TEST_P(VecTest, Parse) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -152,7 +152,7 @@
 TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -170,7 +170,7 @@
 TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -188,7 +188,7 @@
 TEST_P(VecBadType, Handles_Unknown_Type) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -206,7 +206,7 @@
 TEST_P(VecMissingType, Handles_Missing_Type) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -221,7 +221,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr) {
   auto p = parser("ptr<function, f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -235,7 +235,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
   auto p = parser("ptr<function, vec2<f32>>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -253,7 +253,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
   auto p = parser("ptr private, f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -263,7 +263,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) {
   auto p = parser("ptr<function, f32");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -273,7 +273,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) {
   auto p = parser("ptr<function f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -283,7 +283,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
   auto p = parser("ptr<, f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -293,7 +293,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
   auto p = parser("ptr<>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -303,7 +303,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
   auto p = parser("ptr<function,>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -313,7 +313,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
   auto p = parser("ptr<unknown, f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -323,7 +323,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) {
   auto p = parser("ptr<function, unknown>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -333,7 +333,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array) {
   auto p = parser("array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -349,7 +349,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
   auto p = parser("[[stride(16)]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -369,7 +369,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
   auto p = parser("[[stride(16)]] array<f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -388,7 +388,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) {
   auto p = parser("[[stride(16), stride(32)]] array<f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -409,7 +409,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) {
   auto p = parser("[[stride(16)]] [[stride(32)]] array<f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -430,7 +430,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingArray) {
   auto p = parser("[[stride(16)]] f32");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -440,7 +440,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingClosingAttr) {
   auto p = parser("[[stride(16) array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -450,7 +450,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Decoration_UnknownDecoration) {
   auto p = parser("[[unknown 16]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -460,7 +460,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) {
   auto p = parser("[[stride 4)]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -470,7 +470,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingRightParen) {
   auto p = parser("[[stride(4]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -480,7 +480,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) {
   auto p = parser("[[stride()]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -491,7 +491,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) {
   auto p = parser("[[stride(invalid)]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -502,7 +502,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) {
   auto p = parser("[[stride(-1)]] array<f32, 5>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -512,7 +512,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
   auto p = parser("array<u32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -526,7 +526,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Vec) {
   auto p = parser("array<vec4<u32>>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -540,7 +540,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
   auto p = parser("array<unknown, 3>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -550,7 +550,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
   auto p = parser("array<f32, 0>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -560,7 +560,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
   auto p = parser("array<f32, -1>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -570,7 +570,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
   auto p = parser("array<f32, invalid>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -580,7 +580,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
   auto p = parser("array f32>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -590,7 +590,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
   auto p = parser("array<f32");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -600,7 +600,7 @@
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
   auto p = parser("array<f32 3>");
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -623,7 +623,7 @@
 TEST_P(MatrixTest, Parse) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -651,7 +651,7 @@
 TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -675,7 +675,7 @@
 TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -699,7 +699,7 @@
 TEST_P(MatrixBadType, Handles_Unknown_Type) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -723,7 +723,7 @@
 TEST_P(MatrixMissingType, Handles_Missing_Type) {
   auto params = GetParam();
   auto p = parser(params.input);
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.errored);
   EXPECT_FALSE(t.matched);
   ASSERT_EQ(t.value, nullptr);
@@ -748,7 +748,7 @@
   auto& builder = p->builder();
   auto type = builder.ty.sampler(ast::SamplerKind::kSampler);
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
@@ -764,7 +764,7 @@
   auto* type = builder.create<sem::SampledTexture>(ast::TextureDimension::kCube,
                                                    ty.f32());
 
-  auto t = p->type_decl_DEPRECATED();
+  auto t = p->type_decl();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
diff --git a/src/sem/vector_type.cc b/src/sem/vector_type.cc
index 591bcb1..caa43c4 100644
--- a/src/sem/vector_type.cc
+++ b/src/sem/vector_type.cc
@@ -21,7 +21,8 @@
 namespace tint {
 namespace sem {
 
-Vector::Vector(Type* subtype, uint32_t size) : subtype_(subtype), size_(size) {
+Vector::Vector(Type const* subtype, uint32_t size)
+    : subtype_(subtype), size_(size) {
   TINT_ASSERT(size_ > 1);
   TINT_ASSERT(size_ < 5);
 }
diff --git a/src/sem/vector_type.h b/src/sem/vector_type.h
index 4df716a..0c9cae7 100644
--- a/src/sem/vector_type.h
+++ b/src/sem/vector_type.h
@@ -28,13 +28,13 @@
   /// Constructor
   /// @param subtype the vector element type
   /// @param size the number of elements in the vector
-  Vector(Type* subtype, uint32_t size);
+  Vector(Type const* subtype, uint32_t size);
   /// Move constructor
   Vector(Vector&&);
   ~Vector() override;
 
   /// @returns the type of the vector elements
-  Type* type() const { return subtype_; }
+  Type* type() const { return const_cast<Type*>(subtype_); }
   /// @returns the size of the vector
   uint32_t size() const { return size_; }
 
@@ -52,7 +52,7 @@
   Vector* Clone(CloneContext* ctx) const override;
 
  private:
-  Type* const subtype_;
+  Type const* const subtype_;
   uint32_t const size_;
 };
 
diff --git a/src/transform/transform.cc b/src/transform/transform.cc
index 503e5a5..a06d75e 100644
--- a/src/transform/transform.cc
+++ b/src/transform/transform.cc
@@ -49,7 +49,7 @@
   auto source = ctx->Clone(in->source());
   auto symbol = ctx->Clone(in->symbol());
   auto params = ctx->Clone(in->params());
-  auto* return_type = ctx->Clone(in->return_type());
+  auto return_type = ctx->Clone(in->return_type());
   auto* body = ctx->dst->create<ast::BlockStatement>(
       ctx->Clone(in->body()->source()), statements);
   auto decos = ctx->Clone(in->decorations());