wsgl parser: Have Expect & Maybe operator-> deref

For values of type T* and std::unique_ptr<T>.

This allows us to replace all occurances of `res.value->member` with: `res->member`, which also asserts that `res` is not in an error state.

Brings the verbosity back down to pre-expect and pre-maybe levels.

Bug: tint:282
Change-Id: Ib00018affca53ac5e71ee2140e7e0cd607b83715
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32141
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index b94c054..ca9ce6c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -524,6 +524,7 @@
     "src/reader/wgsl/parser.h",
     "src/reader/wgsl/parser_impl.cc",
     "src/reader/wgsl/parser_impl.h",
+    "src/reader/wgsl/parser_impl_detail.h",
     "src/reader/wgsl/token.cc",
     "src/reader/wgsl/token.h",
   ]
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1cc7808..0356719 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -280,6 +280,7 @@
     reader/wgsl/parser.h
     reader/wgsl/parser_impl.cc
     reader/wgsl/parser_impl.h
+    reader/wgsl/parser_impl_detail.h
     reader/wgsl/token.cc
     reader/wgsl/token.h
   )
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index a4e4e71..03bdaf4 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1156,13 +1156,13 @@
   if (func_decos.errored)
     return Failure::kErrored;
 
-  f.value->set_decorations(std::move(func_decos.value));
+  f->set_decorations(std::move(func_decos.value));
 
   auto body = expect_body_stmt();
   if (body.errored)
     return Failure::kErrored;
 
-  f.value->set_body(std::move(body.value));
+  f->set_body(std::move(body.value));
   return std::move(f.value);
 }
 
@@ -1491,10 +1491,10 @@
     if (!constructor.matched)
       return add_error(peek(), "missing constructor for variable declaration");
 
-    var.value->set_constructor(std::move(constructor.value));
+    var->set_constructor(std::move(constructor.value));
   }
 
-  return std::make_unique<ast::VariableDeclStatement>(var.value->source(),
+  return std::make_unique<ast::VariableDeclStatement>(var->source(),
                                                       std::move(var.value));
 }
 
@@ -1655,7 +1655,7 @@
       return Failure::kErrored;
     if (!cond.matched)
       break;
-    if (!cond.value->IsInt())
+    if (!cond->IsInt())
       return add_error(t, "invalid case selector must be an integer value");
 
     std::unique_ptr<ast::IntLiteral> selector(cond.value.release()->AsInt());
@@ -1819,11 +1819,11 @@
   // The for statement is a syntactic sugar on top of the loop statement.
   // We create corresponding nodes in ast with the exact same behaviour
   // as we would expect from the loop statement.
-  if (header.value->condition != nullptr) {
+  if (header->condition != nullptr) {
     // !condition
     auto not_condition = std::make_unique<ast::UnaryOpExpression>(
-        header.value->condition->source(), ast::UnaryOp::kNot,
-        std::move(header.value->condition));
+        header->condition->source(), ast::UnaryOp::kNot,
+        std::move(header->condition));
     // { break; }
     auto break_stmt =
         std::make_unique<ast::BreakStatement>(not_condition->source());
@@ -1834,22 +1834,22 @@
     auto break_if_not_condition = std::make_unique<ast::IfStatement>(
         not_condition->source(), std::move(not_condition),
         std::move(break_body));
-    body.value->insert(0, std::move(break_if_not_condition));
+    body->insert(0, std::move(break_if_not_condition));
   }
 
   std::unique_ptr<ast::BlockStatement> continuing_body = nullptr;
-  if (header.value->continuing != nullptr) {
-    continuing_body = std::make_unique<ast::BlockStatement>(
-        header.value->continuing->source());
-    continuing_body->append(std::move(header.value->continuing));
+  if (header->continuing != nullptr) {
+    continuing_body =
+        std::make_unique<ast::BlockStatement>(header->continuing->source());
+    continuing_body->append(std::move(header->continuing));
   }
 
   auto loop = std::make_unique<ast::LoopStatement>(
       source, std::move(body.value), std::move(continuing_body));
 
-  if (header.value->initializer != nullptr) {
+  if (header->initializer != nullptr) {
     auto result = std::make_unique<ast::BlockStatement>(source);
-    result->append(std::move(header.value->initializer));
+    result->append(std::move(header->initializer));
     result->append(std::move(loop));
     return result;
   }
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index ab3efea..0dcaa37 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -50,6 +50,7 @@
 #include "src/context.h"
 #include "src/diagnostic/diagnostic.h"
 #include "src/diagnostic/formatter.h"
+#include "src/reader/wgsl/parser_impl_detail.h"
 #include "src/reader/wgsl/token.h"
 
 namespace tint {
@@ -121,10 +122,13 @@
     /// @return this Expect
     inline Expect& operator=(Expect&&) = default;
 
-    /// @return a pointer to |value|. |errored| must be false to call.
-    inline T* operator->() {
+    /// @return a pointer to the returned value. If T is a pointer or
+    /// std::unique_ptr, operator->() automatically dereferences so that the
+    /// return type will always be a pointer to a non-pointer type. |errored|
+    /// must be false to call.
+    inline typename detail::OperatorArrow<T>::type operator->() {
       assert(!errored);
-      return &value;
+      return detail::OperatorArrow<T>::ptr(value);
     }
 
     /// The expected value of a successful parse.
@@ -161,6 +165,7 @@
     inline Maybe(Failure::NoMatch) {}  // NOLINT
 
     /// Constructor from an Expect.
+    /// @param e the Expect to copy this Maybe from
     template <typename U>
     inline Maybe(const Expect<U>& e)  // NOLINT
         : value(e.value),
@@ -169,6 +174,7 @@
           matched(!e.errored) {}
 
     /// Move from an Expect.
+    /// @param e the Expect to move this Maybe from
     template <typename U>
     inline Maybe(Expect<U>&& e)  // NOLINT
         : value(std::move(e.value)),
@@ -187,10 +193,13 @@
     /// @return this Maybe
     inline Maybe& operator=(Maybe&&) = default;
 
-    /// @return a pointer to |value|. |errored| must be false to call.
-    inline T* operator->() {
+    /// @return a pointer to the returned value. If T is a pointer or
+    /// std::unique_ptr, operator->() automatically dereferences so that the
+    /// return type will always be a pointer to a non-pointer type. |errored|
+    /// must be false to call.
+    inline typename detail::OperatorArrow<T>::type operator->() {
       assert(!errored);
-      return &value;
+      return detail::OperatorArrow<T>::ptr(value);
     }
 
     /// The value of a successful parse.
diff --git a/src/reader/wgsl/parser_impl_additive_expression_test.cc b/src/reader/wgsl/parser_impl_additive_expression_test.cc
index 7a93975..e77c670 100644
--- a/src/reader/wgsl/parser_impl_additive_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_additive_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kAdd, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -56,8 +56,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kSubtract, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -97,7 +97,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_and_expression_test.cc b/src/reader/wgsl/parser_impl_and_expression_test.cc
index 2b85958..990e149 100644
--- a/src/reader/wgsl/parser_impl_and_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_and_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kAnd, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -74,7 +74,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_assignment_stmt_test.cc b/src/reader/wgsl/parser_impl_assignment_stmt_test.cc
index 304781e..89ab5e4 100644
--- a/src/reader/wgsl/parser_impl_assignment_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_assignment_stmt_test.cc
@@ -36,18 +36,18 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsAssign());
-  ASSERT_NE(e.value->lhs(), nullptr);
-  ASSERT_NE(e.value->rhs(), nullptr);
+  ASSERT_TRUE(e->IsAssign());
+  ASSERT_NE(e->lhs(), nullptr);
+  ASSERT_NE(e->rhs(), nullptr);
 
-  ASSERT_TRUE(e.value->lhs()->IsIdentifier());
-  auto* ident = e.value->lhs()->AsIdentifier();
+  ASSERT_TRUE(e->lhs()->IsIdentifier());
+  auto* ident = e->lhs()->AsIdentifier();
   EXPECT_EQ(ident->name(), "a");
 
-  ASSERT_TRUE(e.value->rhs()->IsConstructor());
-  ASSERT_TRUE(e.value->rhs()->AsConstructor()->IsScalarConstructor());
+  ASSERT_TRUE(e->rhs()->IsConstructor());
+  ASSERT_TRUE(e->rhs()->AsConstructor()->IsScalarConstructor());
 
-  auto* init = e.value->rhs()->AsConstructor()->AsScalarConstructor();
+  auto* init = e->rhs()->AsConstructor()->AsScalarConstructor();
   ASSERT_NE(init->literal(), nullptr);
   ASSERT_TRUE(init->literal()->IsSint());
   EXPECT_EQ(init->literal()->AsSint()->value(), 123);
@@ -61,19 +61,19 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsAssign());
-  ASSERT_NE(e.value->lhs(), nullptr);
-  ASSERT_NE(e.value->rhs(), nullptr);
+  ASSERT_TRUE(e->IsAssign());
+  ASSERT_NE(e->lhs(), nullptr);
+  ASSERT_NE(e->rhs(), nullptr);
 
-  ASSERT_TRUE(e.value->rhs()->IsConstructor());
-  ASSERT_TRUE(e.value->rhs()->AsConstructor()->IsScalarConstructor());
-  auto* init = e.value->rhs()->AsConstructor()->AsScalarConstructor();
+  ASSERT_TRUE(e->rhs()->IsConstructor());
+  ASSERT_TRUE(e->rhs()->AsConstructor()->IsScalarConstructor());
+  auto* init = e->rhs()->AsConstructor()->AsScalarConstructor();
   ASSERT_NE(init->literal(), nullptr);
   ASSERT_TRUE(init->literal()->IsSint());
   EXPECT_EQ(init->literal()->AsSint()->value(), 123);
 
-  ASSERT_TRUE(e.value->lhs()->IsMemberAccessor());
-  auto* mem = e.value->lhs()->AsMemberAccessor();
+  ASSERT_TRUE(e->lhs()->IsMemberAccessor());
+  auto* mem = e->lhs()->AsMemberAccessor();
 
   ASSERT_TRUE(mem->member()->IsIdentifier());
   auto* ident = mem->member()->AsIdentifier();
diff --git a/src/reader/wgsl/parser_impl_body_stmt_test.cc b/src/reader/wgsl/parser_impl_body_stmt_test.cc
index 4a3b5a0..d0474eb 100644
--- a/src/reader/wgsl/parser_impl_body_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_body_stmt_test.cc
@@ -29,9 +29,9 @@
   auto e = p->expect_body_stmt();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_FALSE(e.errored);
-  ASSERT_EQ(e.value->size(), 2u);
-  EXPECT_TRUE(e.value->get(0)->IsDiscard());
-  EXPECT_TRUE(e.value->get(1)->IsReturn());
+  ASSERT_EQ(e->size(), 2u);
+  EXPECT_TRUE(e->get(0)->IsDiscard());
+  EXPECT_TRUE(e->get(1)->IsReturn());
 }
 
 TEST_F(ParserImplTest, BodyStmt_Empty) {
@@ -39,7 +39,7 @@
   auto e = p->expect_body_stmt();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_FALSE(e.errored);
-  EXPECT_EQ(e.value->size(), 0u);
+  EXPECT_EQ(e->size(), 0u);
 }
 
 TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
diff --git a/src/reader/wgsl/parser_impl_break_stmt_test.cc b/src/reader/wgsl/parser_impl_break_stmt_test.cc
index 8fd49c3..a45f719 100644
--- a/src/reader/wgsl/parser_impl_break_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_break_stmt_test.cc
@@ -28,7 +28,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsBreak());
+  ASSERT_TRUE(e->IsBreak());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_call_stmt_test.cc b/src/reader/wgsl/parser_impl_call_stmt_test.cc
index ded8f50..875805d 100644
--- a/src/reader/wgsl/parser_impl_call_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_call_stmt_test.cc
@@ -32,8 +32,8 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
 
-  ASSERT_TRUE(e.value->IsCall());
-  auto* c = e.value->AsCall()->expr();
+  ASSERT_TRUE(e->IsCall());
+  auto* c = e->AsCall()->expr();
 
   ASSERT_TRUE(c->func()->IsIdentifier());
   auto* func = c->func()->AsIdentifier();
@@ -50,8 +50,8 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
 
-  ASSERT_TRUE(e.value->IsCall());
-  auto* c = e.value->AsCall()->expr();
+  ASSERT_TRUE(e->IsCall());
+  auto* c = e->AsCall()->expr();
 
   ASSERT_TRUE(c->func()->IsIdentifier());
   auto* func = c->func()->AsIdentifier();
diff --git a/src/reader/wgsl/parser_impl_case_body_test.cc b/src/reader/wgsl/parser_impl_case_body_test.cc
index b840d70..17e55da 100644
--- a/src/reader/wgsl/parser_impl_case_body_test.cc
+++ b/src/reader/wgsl/parser_impl_case_body_test.cc
@@ -27,7 +27,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_FALSE(e.errored);
   EXPECT_TRUE(e.matched);
-  EXPECT_EQ(e.value->size(), 0u);
+  EXPECT_EQ(e->size(), 0u);
 }
 
 TEST_F(ParserImplTest, CaseBody_Statements) {
@@ -39,9 +39,9 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_FALSE(e.errored);
   EXPECT_TRUE(e.matched);
-  ASSERT_EQ(e.value->size(), 2u);
-  EXPECT_TRUE(e.value->get(0)->IsVariableDecl());
-  EXPECT_TRUE(e.value->get(1)->IsAssign());
+  ASSERT_EQ(e->size(), 2u);
+  EXPECT_TRUE(e->get(0)->IsVariableDecl());
+  EXPECT_TRUE(e->get(1)->IsAssign());
 }
 
 TEST_F(ParserImplTest, CaseBody_InvalidStatement) {
@@ -59,8 +59,8 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_FALSE(e.errored);
   EXPECT_TRUE(e.matched);
-  ASSERT_EQ(e.value->size(), 1u);
-  EXPECT_TRUE(e.value->get(0)->IsFallthrough());
+  ASSERT_EQ(e->size(), 1u);
+  EXPECT_TRUE(e->get(0)->IsFallthrough());
 }
 
 TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) {
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc
index 14b716f..f07fbc2 100644
--- a/src/reader/wgsl/parser_impl_const_expr_test.cc
+++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -31,10 +31,10 @@
   auto e = p->expect_const_expr();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsConstructor());
-  ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
+  ASSERT_TRUE(e->IsConstructor());
+  ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor());
 
-  auto* t = e.value->AsConstructor()->AsTypeConstructor();
+  auto* t = e->AsConstructor()->AsTypeConstructor();
   ASSERT_TRUE(t->type()->IsVector());
   EXPECT_EQ(t->type()->AsVector()->size(), 2u);
 
@@ -114,9 +114,9 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsConstructor());
-  ASSERT_TRUE(e.value->AsConstructor()->IsScalarConstructor());
-  auto* c = e.value->AsConstructor()->AsScalarConstructor();
+  ASSERT_TRUE(e->IsConstructor());
+  ASSERT_TRUE(e->AsConstructor()->IsScalarConstructor());
+  auto* c = e->AsConstructor()->AsScalarConstructor();
   ASSERT_TRUE(c->literal()->IsBool());
   EXPECT_TRUE(c->literal()->AsBool()->IsTrue());
 }
diff --git a/src/reader/wgsl/parser_impl_const_literal_test.cc b/src/reader/wgsl/parser_impl_const_literal_test.cc
index 28b0771..acb7637 100644
--- a/src/reader/wgsl/parser_impl_const_literal_test.cc
+++ b/src/reader/wgsl/parser_impl_const_literal_test.cc
@@ -32,8 +32,8 @@
   EXPECT_FALSE(c.errored);
   EXPECT_FALSE(p->has_error());
   ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c.value->IsSint());
-  EXPECT_EQ(c.value->AsSint()->value(), -234);
+  ASSERT_TRUE(c->IsSint());
+  EXPECT_EQ(c->AsSint()->value(), -234);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_Uint) {
@@ -43,8 +43,8 @@
   EXPECT_FALSE(c.errored);
   EXPECT_FALSE(p->has_error());
   ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c.value->IsUint());
-  EXPECT_EQ(c.value->AsUint()->value(), 234u);
+  ASSERT_TRUE(c->IsUint());
+  EXPECT_EQ(c->AsUint()->value(), 234u);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_Float) {
@@ -54,8 +54,8 @@
   EXPECT_FALSE(c.errored);
   EXPECT_FALSE(p->has_error());
   ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c.value->IsFloat());
-  EXPECT_FLOAT_EQ(c.value->AsFloat()->value(), 234e12f);
+  ASSERT_TRUE(c->IsFloat());
+  EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12f);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) {
@@ -73,8 +73,8 @@
   EXPECT_FALSE(c.errored);
   EXPECT_FALSE(p->has_error());
   ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c.value->IsBool());
-  EXPECT_TRUE(c.value->AsBool()->IsTrue());
+  ASSERT_TRUE(c->IsBool());
+  EXPECT_TRUE(c->AsBool()->IsTrue());
 }
 
 TEST_F(ParserImplTest, ConstLiteral_False) {
@@ -84,8 +84,8 @@
   EXPECT_FALSE(c.errored);
   EXPECT_FALSE(p->has_error());
   ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c.value->IsBool());
-  EXPECT_TRUE(c.value->AsBool()->IsFalse());
+  ASSERT_TRUE(c->IsBool());
+  EXPECT_TRUE(c->AsBool()->IsFalse());
 }
 
 TEST_F(ParserImplTest, ConstLiteral_NoMatch) {
diff --git a/src/reader/wgsl/parser_impl_continue_stmt_test.cc b/src/reader/wgsl/parser_impl_continue_stmt_test.cc
index 1a7f644..b2003ce 100644
--- a/src/reader/wgsl/parser_impl_continue_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_continue_stmt_test.cc
@@ -28,7 +28,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsContinue());
+  ASSERT_TRUE(e->IsContinue());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_continuing_stmt_test.cc b/src/reader/wgsl/parser_impl_continuing_stmt_test.cc
index e29b1d4..68c9ec6 100644
--- a/src/reader/wgsl/parser_impl_continuing_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_continuing_stmt_test.cc
@@ -27,8 +27,8 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e.value->size(), 1u);
-  ASSERT_TRUE(e.value->get(0)->IsDiscard());
+  ASSERT_EQ(e->size(), 1u);
+  ASSERT_TRUE(e->get(0)->IsDiscard());
 }
 
 TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) {
diff --git a/src/reader/wgsl/parser_impl_depth_texture_type_test.cc b/src/reader/wgsl/parser_impl_depth_texture_type_test.cc
index 35119bb..5125c06 100644
--- a/src/reader/wgsl/parser_impl_depth_texture_type_test.cc
+++ b/src/reader/wgsl/parser_impl_depth_texture_type_test.cc
@@ -36,9 +36,9 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsDepth());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsDepth());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
   EXPECT_FALSE(p->has_error());
 }
 
@@ -48,9 +48,9 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsDepth());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2dArray);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsDepth());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2dArray);
   EXPECT_FALSE(p->has_error());
 }
 
@@ -60,9 +60,9 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsDepth());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::kCube);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsDepth());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::kCube);
   EXPECT_FALSE(p->has_error());
 }
 
@@ -72,10 +72,9 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsDepth());
-  EXPECT_EQ(t.value->AsTexture()->dim(),
-            ast::type::TextureDimension::kCubeArray);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsDepth());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::kCubeArray);
   EXPECT_FALSE(p->has_error());
 }
 
diff --git a/src/reader/wgsl/parser_impl_detail.h b/src/reader/wgsl/parser_impl_detail.h
new file mode 100644
index 0000000..b19a523
--- /dev/null
+++ b/src/reader/wgsl/parser_impl_detail.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_READER_WGSL_PARSER_IMPL_DETAIL_H_
+#define SRC_READER_WGSL_PARSER_IMPL_DETAIL_H_
+
+#include <memory>
+#include <type_traits>
+
+namespace tint {
+namespace reader {
+namespace wgsl {
+namespace detail {
+
+/// OperatorArrow is a traits helper for ParserImpl::Expect<T>::operator->() and
+/// ParserImpl::Maybe<T>::operator->() so that pointer types are automatically
+/// dereferenced. This simplifies usage by allowing
+///  `result.value->field`
+/// to be written as:
+///  `result->field`
+/// As well as reducing the amount of code, using the operator->() asserts that
+/// the Expect<T> or Maybe<T> is not in an error state before dereferencing.
+template <typename T>
+struct OperatorArrow {
+  /// type resolves to the return type for the operator->()
+  using type = T*;
+  /// @param val the value held by `ParserImpl::Expect<T>` or
+  /// `ParserImpl::Maybe<T>`.
+  /// @return a pointer to `val`
+  static inline T* ptr(T& val) { return &val; }
+};
+
+/// OperatorArrow template specialization for std::unique_ptr<>.
+template <typename T>
+struct OperatorArrow<std::unique_ptr<T>> {
+  /// type resolves to the return type for the operator->()
+  using type = T*;
+  /// @param val the value held by `ParserImpl::Expect<T>` or
+  /// `ParserImpl::Maybe<T>`.
+  /// @return the raw pointer held by `val`.
+  static inline T* ptr(std::unique_ptr<T>& val) { return val.get(); }
+};
+
+/// OperatorArrow template specialization for T*.
+template <typename T>
+struct OperatorArrow<T*> {
+  /// type resolves to the return type for the operator->()
+  using type = T*;
+  /// @param val the value held by `ParserImpl::Expect<T>` or
+  /// `ParserImpl::Maybe<T>`.
+  /// @return `val`.
+  static inline T* ptr(T* val) { return val; }
+};
+
+}  // namespace detail
+}  // namespace wgsl
+}  // namespace reader
+}  // namespace tint
+
+#endif  // SRC_READER_WGSL_PARSER_IMPL_DETAIL_H_
diff --git a/src/reader/wgsl/parser_impl_else_stmt_test.cc b/src/reader/wgsl/parser_impl_else_stmt_test.cc
index 08313f2..89632e3 100644
--- a/src/reader/wgsl/parser_impl_else_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_else_stmt_test.cc
@@ -29,9 +29,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsElse());
-  ASSERT_EQ(e.value->condition(), nullptr);
-  EXPECT_EQ(e.value->body()->size(), 2u);
+  ASSERT_TRUE(e->IsElse());
+  ASSERT_EQ(e->condition(), nullptr);
+  EXPECT_EQ(e->body()->size(), 2u);
 }
 
 TEST_F(ParserImplTest, ElseStmt_InvalidBody) {
diff --git a/src/reader/wgsl/parser_impl_equality_expression_test.cc b/src/reader/wgsl/parser_impl_equality_expression_test.cc
index 9801d00..f160075 100644
--- a/src/reader/wgsl/parser_impl_equality_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_equality_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kEqual, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -56,8 +56,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kNotEqual, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -97,7 +97,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc b/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
index 39f34e4..c3a3139 100644
--- a/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kXor, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -74,7 +74,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_for_stmt_test.cc b/src/reader/wgsl/parser_impl_for_stmt_test.cc
index fe9b63f..27c7def 100644
--- a/src/reader/wgsl/parser_impl_for_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_for_stmt_test.cc
@@ -38,7 +38,7 @@
     EXPECT_FALSE(p_for->has_error()) << p_for->error();
     ASSERT_NE(e_for.value, nullptr);
 
-    EXPECT_EQ(e_loop.value->str(), e_for.value->str());
+    EXPECT_EQ(e_loop->str(), e_for->str());
   }
 };
 
diff --git a/src/reader/wgsl/parser_impl_function_decl_test.cc b/src/reader/wgsl/parser_impl_function_decl_test.cc
index 68ba11a..03dc6cb 100644
--- a/src/reader/wgsl/parser_impl_function_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decl_test.cc
@@ -36,18 +36,18 @@
   EXPECT_TRUE(f.matched);
   ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f.value->name(), "main");
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
+  EXPECT_EQ(f->name(), "main");
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
 
-  ASSERT_EQ(f.value->params().size(), 2u);
-  EXPECT_EQ(f.value->params()[0]->name(), "a");
-  EXPECT_EQ(f.value->params()[1]->name(), "b");
+  ASSERT_EQ(f->params().size(), 2u);
+  EXPECT_EQ(f->params()[0]->name(), "a");
+  EXPECT_EQ(f->params()[1]->name(), "b");
 
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
 
-  auto* body = f.value->body();
+  auto* body = f->body();
   ASSERT_EQ(body->size(), 1u);
   EXPECT_TRUE(body->get(0)->IsReturn());
 }
@@ -64,14 +64,14 @@
   EXPECT_TRUE(f.matched);
   ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f.value->name(), "main");
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
-  ASSERT_EQ(f.value->params().size(), 0u);
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
+  EXPECT_EQ(f->name(), "main");
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
+  ASSERT_EQ(f->params().size(), 0u);
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
 
-  auto& decorations = f.value->decorations();
+  auto& decorations = f->decorations();
   ASSERT_EQ(decorations.size(), 1u);
   ASSERT_TRUE(decorations[0]->IsWorkgroup());
 
@@ -83,7 +83,7 @@
   EXPECT_EQ(y, 3u);
   EXPECT_EQ(z, 4u);
 
-  auto* body = f.value->body();
+  auto* body = f->body();
   ASSERT_EQ(body->size(), 1u);
   EXPECT_TRUE(body->get(0)->IsReturn());
 }
@@ -102,14 +102,14 @@
   EXPECT_TRUE(f.matched);
   ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f.value->name(), "main");
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
-  ASSERT_EQ(f.value->params().size(), 0u);
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
+  EXPECT_EQ(f->name(), "main");
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
+  ASSERT_EQ(f->params().size(), 0u);
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
 
-  auto& decorations = f.value->decorations();
+  auto& decorations = f->decorations();
   ASSERT_EQ(decorations.size(), 2u);
 
   uint32_t x = 0;
@@ -127,7 +127,7 @@
   EXPECT_EQ(y, 6u);
   EXPECT_EQ(z, 7u);
 
-  auto* body = f.value->body();
+  auto* body = f->body();
   ASSERT_EQ(body->size(), 1u);
   EXPECT_TRUE(body->get(0)->IsReturn());
 }
@@ -147,14 +147,14 @@
   EXPECT_TRUE(f.matched);
   ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f.value->name(), "main");
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
-  ASSERT_EQ(f.value->params().size(), 0u);
-  ASSERT_NE(f.value->return_type(), nullptr);
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
+  EXPECT_EQ(f->name(), "main");
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
+  ASSERT_EQ(f->params().size(), 0u);
+  ASSERT_NE(f->return_type(), nullptr);
+  EXPECT_TRUE(f->return_type()->IsVoid());
 
-  auto& decos = f.value->decorations();
+  auto& decos = f->decorations();
   ASSERT_EQ(decos.size(), 2u);
 
   uint32_t x = 0;
@@ -172,7 +172,7 @@
   EXPECT_EQ(y, 6u);
   EXPECT_EQ(z, 7u);
 
-  auto* body = f.value->body();
+  auto* body = f->body();
   ASSERT_EQ(body->size(), 1u);
   EXPECT_TRUE(body->get(0)->IsReturn());
 }
diff --git a/src/reader/wgsl/parser_impl_function_header_test.cc b/src/reader/wgsl/parser_impl_function_header_test.cc
index a7f000b..ae1e2d3 100644
--- a/src/reader/wgsl/parser_impl_function_header_test.cc
+++ b/src/reader/wgsl/parser_impl_function_header_test.cc
@@ -31,11 +31,11 @@
   EXPECT_FALSE(f.errored);
   ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f.value->name(), "main");
-  ASSERT_EQ(f.value->params().size(), 2u);
-  EXPECT_EQ(f.value->params()[0]->name(), "a");
-  EXPECT_EQ(f.value->params()[1]->name(), "b");
-  EXPECT_TRUE(f.value->return_type()->IsVoid());
+  EXPECT_EQ(f->name(), "main");
+  ASSERT_EQ(f->params().size(), 2u);
+  EXPECT_EQ(f->params()[0]->name(), "a");
+  EXPECT_EQ(f->params()[1]->name(), "b");
+  EXPECT_TRUE(f->return_type()->IsVoid());
 }
 
 TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
index 929be79..5888ee9 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -31,18 +31,18 @@
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(e.value->is_const());
-  EXPECT_EQ(e.value->name(), "a");
-  ASSERT_NE(e.value->type(), nullptr);
-  EXPECT_TRUE(e.value->type()->IsF32());
+  EXPECT_TRUE(e->is_const());
+  EXPECT_EQ(e->name(), "a");
+  ASSERT_NE(e->type(), nullptr);
+  EXPECT_TRUE(e->type()->IsF32());
 
-  EXPECT_EQ(e.value->source().range.begin.line, 1u);
-  EXPECT_EQ(e.value->source().range.begin.column, 7u);
-  EXPECT_EQ(e.value->source().range.end.line, 1u);
-  EXPECT_EQ(e.value->source().range.end.column, 8u);
+  EXPECT_EQ(e->source().range.begin.line, 1u);
+  EXPECT_EQ(e->source().range.begin.column, 7u);
+  EXPECT_EQ(e->source().range.end.line, 1u);
+  EXPECT_EQ(e->source().range.end.column, 8u);
 
-  ASSERT_NE(e.value->constructor(), nullptr);
-  EXPECT_TRUE(e.value->constructor()->IsConstructor());
+  ASSERT_NE(e->constructor(), nullptr);
+  EXPECT_TRUE(e->constructor()->IsConstructor());
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) {
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index d6dbcbd..446d93f 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -34,17 +34,17 @@
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
 
-  EXPECT_EQ(e.value->name(), "a");
-  EXPECT_TRUE(e.value->type()->IsF32());
-  EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
+  EXPECT_EQ(e->name(), "a");
+  EXPECT_TRUE(e->type()->IsF32());
+  EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
 
-  EXPECT_EQ(e.value->source().range.begin.line, 1u);
-  EXPECT_EQ(e.value->source().range.begin.column, 10u);
-  EXPECT_EQ(e.value->source().range.end.line, 1u);
-  EXPECT_EQ(e.value->source().range.end.column, 11u);
+  EXPECT_EQ(e->source().range.begin.line, 1u);
+  EXPECT_EQ(e->source().range.begin.column, 10u);
+  EXPECT_EQ(e->source().range.end.line, 1u);
+  EXPECT_EQ(e->source().range.end.column, 11u);
 
-  ASSERT_EQ(e.value->constructor(), nullptr);
-  ASSERT_FALSE(e.value->IsDecorated());
+  ASSERT_EQ(e->constructor(), nullptr);
+  ASSERT_FALSE(e->IsDecorated());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
@@ -58,20 +58,20 @@
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
 
-  EXPECT_EQ(e.value->name(), "a");
-  EXPECT_TRUE(e.value->type()->IsF32());
-  EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
+  EXPECT_EQ(e->name(), "a");
+  EXPECT_TRUE(e->type()->IsF32());
+  EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
 
-  EXPECT_EQ(e.value->source().range.begin.line, 1u);
-  EXPECT_EQ(e.value->source().range.begin.column, 10u);
-  EXPECT_EQ(e.value->source().range.end.line, 1u);
-  EXPECT_EQ(e.value->source().range.end.column, 11u);
+  EXPECT_EQ(e->source().range.begin.line, 1u);
+  EXPECT_EQ(e->source().range.begin.column, 10u);
+  EXPECT_EQ(e->source().range.end.line, 1u);
+  EXPECT_EQ(e->source().range.end.column, 11u);
 
-  ASSERT_NE(e.value->constructor(), nullptr);
-  ASSERT_TRUE(e.value->constructor()->IsConstructor());
-  ASSERT_TRUE(e.value->constructor()->AsConstructor()->IsScalarConstructor());
+  ASSERT_NE(e->constructor(), nullptr);
+  ASSERT_TRUE(e->constructor()->IsConstructor());
+  ASSERT_TRUE(e->constructor()->AsConstructor()->IsScalarConstructor());
 
-  ASSERT_FALSE(e.value->IsDecorated());
+  ASSERT_FALSE(e->IsDecorated());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
@@ -84,22 +84,22 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsDecorated());
+  ASSERT_TRUE(e->IsDecorated());
 
-  EXPECT_EQ(e.value->name(), "a");
-  ASSERT_NE(e.value->type(), nullptr);
-  EXPECT_TRUE(e.value->type()->IsF32());
-  EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
+  EXPECT_EQ(e->name(), "a");
+  ASSERT_NE(e->type(), nullptr);
+  EXPECT_TRUE(e->type()->IsF32());
+  EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
 
-  EXPECT_EQ(e.value->source().range.begin.line, 1u);
-  EXPECT_EQ(e.value->source().range.begin.column, 33u);
-  EXPECT_EQ(e.value->source().range.end.line, 1u);
-  EXPECT_EQ(e.value->source().range.end.column, 34u);
+  EXPECT_EQ(e->source().range.begin.line, 1u);
+  EXPECT_EQ(e->source().range.begin.column, 33u);
+  EXPECT_EQ(e->source().range.end.line, 1u);
+  EXPECT_EQ(e->source().range.end.column, 34u);
 
-  ASSERT_EQ(e.value->constructor(), nullptr);
+  ASSERT_EQ(e->constructor(), nullptr);
 
-  ASSERT_TRUE(e.value->IsDecorated());
-  auto* v = e.value->AsDecorated();
+  ASSERT_TRUE(e->IsDecorated());
+  auto* v = e->AsDecorated();
 
   auto& decorations = v->decorations();
   ASSERT_EQ(decorations.size(), 2u);
@@ -118,22 +118,22 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsDecorated());
+  ASSERT_TRUE(e->IsDecorated());
 
-  EXPECT_EQ(e.value->name(), "a");
-  ASSERT_NE(e.value->type(), nullptr);
-  EXPECT_TRUE(e.value->type()->IsF32());
-  EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
+  EXPECT_EQ(e->name(), "a");
+  ASSERT_NE(e->type(), nullptr);
+  EXPECT_TRUE(e->type()->IsF32());
+  EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
 
-  EXPECT_EQ(e.value->source().range.begin.line, 1u);
-  EXPECT_EQ(e.value->source().range.begin.column, 36u);
-  EXPECT_EQ(e.value->source().range.end.line, 1u);
-  EXPECT_EQ(e.value->source().range.end.column, 37u);
+  EXPECT_EQ(e->source().range.begin.line, 1u);
+  EXPECT_EQ(e->source().range.begin.column, 36u);
+  EXPECT_EQ(e->source().range.end.line, 1u);
+  EXPECT_EQ(e->source().range.end.column, 37u);
 
-  ASSERT_EQ(e.value->constructor(), nullptr);
+  ASSERT_EQ(e->constructor(), nullptr);
 
-  ASSERT_TRUE(e.value->IsDecorated());
-  auto* v = e.value->AsDecorated();
+  ASSERT_TRUE(e->IsDecorated());
+  auto* v = e->AsDecorated();
 
   auto& decorations = v->decorations();
   ASSERT_EQ(decorations.size(), 2u);
diff --git a/src/reader/wgsl/parser_impl_if_stmt_test.cc b/src/reader/wgsl/parser_impl_if_stmt_test.cc
index 8dea243..0297559 100644
--- a/src/reader/wgsl/parser_impl_if_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_if_stmt_test.cc
@@ -31,11 +31,11 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsIf());
-  ASSERT_NE(e.value->condition(), nullptr);
-  ASSERT_TRUE(e.value->condition()->IsBinary());
-  EXPECT_EQ(e.value->body()->size(), 2u);
-  EXPECT_EQ(e.value->else_statements().size(), 0u);
+  ASSERT_TRUE(e->IsIf());
+  ASSERT_NE(e->condition(), nullptr);
+  ASSERT_TRUE(e->condition()->IsBinary());
+  EXPECT_EQ(e->body()->size(), 2u);
+  EXPECT_EQ(e->else_statements().size(), 0u);
 }
 
 TEST_F(ParserImplTest, IfStmt_WithElse) {
@@ -47,18 +47,18 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsIf());
-  ASSERT_NE(e.value->condition(), nullptr);
-  ASSERT_TRUE(e.value->condition()->IsBinary());
-  EXPECT_EQ(e.value->body()->size(), 2u);
+  ASSERT_TRUE(e->IsIf());
+  ASSERT_NE(e->condition(), nullptr);
+  ASSERT_TRUE(e->condition()->IsBinary());
+  EXPECT_EQ(e->body()->size(), 2u);
 
-  ASSERT_EQ(e.value->else_statements().size(), 2u);
-  ASSERT_NE(e.value->else_statements()[0]->condition(), nullptr);
-  ASSERT_TRUE(e.value->else_statements()[0]->condition()->IsIdentifier());
-  EXPECT_EQ(e.value->else_statements()[0]->body()->size(), 1u);
+  ASSERT_EQ(e->else_statements().size(), 2u);
+  ASSERT_NE(e->else_statements()[0]->condition(), nullptr);
+  ASSERT_TRUE(e->else_statements()[0]->condition()->IsIdentifier());
+  EXPECT_EQ(e->else_statements()[0]->body()->size(), 1u);
 
-  ASSERT_EQ(e.value->else_statements()[1]->condition(), nullptr);
-  EXPECT_EQ(e.value->else_statements()[1]->body()->size(), 0u);
+  ASSERT_EQ(e->else_statements()[1]->condition(), nullptr);
+  EXPECT_EQ(e->else_statements()[1]->body()->size(), 0u);
 }
 
 TEST_F(ParserImplTest, IfStmt_InvalidCondition) {
diff --git a/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc b/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
index 073c2be..e010429 100644
--- a/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kOr, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -74,7 +74,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_logical_and_expression_test.cc b/src/reader/wgsl/parser_impl_logical_and_expression_test.cc
index c11de2a..0235cad 100644
--- a/src/reader/wgsl/parser_impl_logical_and_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_logical_and_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kLogicalAnd, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -74,7 +74,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_logical_or_expression_test.cc b/src/reader/wgsl/parser_impl_logical_or_expression_test.cc
index 3925590..fd8c934 100644
--- a/src/reader/wgsl/parser_impl_logical_or_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_logical_or_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kLogicalOr, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -74,7 +74,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_loop_stmt_test.cc b/src/reader/wgsl/parser_impl_loop_stmt_test.cc
index 6b4aa2f..f9198a0 100644
--- a/src/reader/wgsl/parser_impl_loop_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_loop_stmt_test.cc
@@ -29,10 +29,10 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_EQ(e.value->body()->size(), 1u);
-  EXPECT_TRUE(e.value->body()->get(0)->IsDiscard());
+  ASSERT_EQ(e->body()->size(), 1u);
+  EXPECT_TRUE(e->body()->get(0)->IsDiscard());
 
-  EXPECT_EQ(e.value->continuing()->size(), 0u);
+  EXPECT_EQ(e->continuing()->size(), 0u);
 }
 
 TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
@@ -43,11 +43,11 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_EQ(e.value->body()->size(), 1u);
-  EXPECT_TRUE(e.value->body()->get(0)->IsDiscard());
+  ASSERT_EQ(e->body()->size(), 1u);
+  EXPECT_TRUE(e->body()->get(0)->IsDiscard());
 
-  EXPECT_EQ(e.value->continuing()->size(), 1u);
-  EXPECT_TRUE(e.value->continuing()->get(0)->IsDiscard());
+  EXPECT_EQ(e->continuing()->size(), 1u);
+  EXPECT_TRUE(e->continuing()->get(0)->IsDiscard());
 }
 
 TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
@@ -57,8 +57,8 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_EQ(e.value->body()->size(), 0u);
-  ASSERT_EQ(e.value->continuing()->size(), 0u);
+  ASSERT_EQ(e->body()->size(), 0u);
+  ASSERT_EQ(e->continuing()->size(), 0u);
 }
 
 TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
@@ -68,9 +68,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_EQ(e.value->body()->size(), 0u);
-  ASSERT_EQ(e.value->continuing()->size(), 1u);
-  EXPECT_TRUE(e.value->continuing()->get(0)->IsDiscard());
+  ASSERT_EQ(e->body()->size(), 0u);
+  ASSERT_EQ(e->continuing()->size(), 1u);
+  EXPECT_TRUE(e->continuing()->get(0)->IsDiscard());
 }
 
 TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
diff --git a/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc b/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc
index d311020..19936e9 100644
--- a/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -56,8 +56,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kDivide, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -79,8 +79,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kModulo, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -120,7 +120,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc b/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
index e55bc89..9cdcf4f 100644
--- a/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
@@ -27,7 +27,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsBinary());
+  ASSERT_TRUE(e->IsBinary());
 }
 
 TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) {
diff --git a/src/reader/wgsl/parser_impl_postfix_expression_test.cc b/src/reader/wgsl/parser_impl_postfix_expression_test.cc
index 952103b..90b5cfe 100644
--- a/src/reader/wgsl/parser_impl_postfix_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_postfix_expression_test.cc
@@ -36,8 +36,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsArrayAccessor());
-  auto* ary = e.value->AsArrayAccessor();
+  ASSERT_TRUE(e->IsArrayAccessor());
+  auto* ary = e->AsArrayAccessor();
 
   ASSERT_TRUE(ary->array()->IsIdentifier());
   auto* ident = ary->array()->AsIdentifier();
@@ -58,8 +58,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsArrayAccessor());
-  auto* ary = e.value->AsArrayAccessor();
+  ASSERT_TRUE(e->IsArrayAccessor());
+  auto* ary = e->AsArrayAccessor();
 
   ASSERT_TRUE(ary->array()->IsIdentifier());
   auto* ident = ary->array()->AsIdentifier();
@@ -106,8 +106,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsCall());
-  auto* c = e.value->AsCall();
+  ASSERT_TRUE(e->IsCall());
+  auto* c = e->AsCall();
 
   ASSERT_TRUE(c->func()->IsIdentifier());
   auto* func = c->func()->AsIdentifier();
@@ -124,8 +124,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsCall());
-  auto* c = e.value->AsCall();
+  ASSERT_TRUE(e->IsCall());
+  auto* c = e->AsCall();
 
   ASSERT_TRUE(c->func()->IsIdentifier());
   auto* func = c->func()->AsIdentifier();
@@ -174,9 +174,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsMemberAccessor());
+  ASSERT_TRUE(e->IsMemberAccessor());
 
-  auto* m = e.value->AsMemberAccessor();
+  auto* m = e->AsMemberAccessor();
   ASSERT_TRUE(m->structure()->IsIdentifier());
   EXPECT_EQ(m->structure()->AsIdentifier()->name(), "a");
 
@@ -211,7 +211,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc
index 3ef055d..249105e 100644
--- a/src/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -39,8 +39,8 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
-  auto* ident = e.value->AsIdentifier();
+  ASSERT_TRUE(e->IsIdentifier());
+  auto* ident = e->AsIdentifier();
   EXPECT_EQ(ident->name(), "a");
 }
 
@@ -51,9 +51,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsConstructor());
-  ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
-  auto* ty = e.value->AsConstructor()->AsTypeConstructor();
+  ASSERT_TRUE(e->IsConstructor());
+  ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor());
+  auto* ty = e->AsConstructor()->AsTypeConstructor();
 
   ASSERT_EQ(ty->values().size(), 4u);
   const auto& val = ty->values();
@@ -89,9 +89,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsConstructor());
-  ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
-  auto* ty = e.value->AsConstructor()->AsTypeConstructor();
+  ASSERT_TRUE(e->IsConstructor());
+  ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor());
+  auto* ty = e->AsConstructor()->AsTypeConstructor();
 
   ASSERT_EQ(ty->values().size(), 0u);
 }
@@ -143,9 +143,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsConstructor());
-  ASSERT_TRUE(e.value->AsConstructor()->IsScalarConstructor());
-  auto* init = e.value->AsConstructor()->AsScalarConstructor();
+  ASSERT_TRUE(e->IsConstructor());
+  ASSERT_TRUE(e->AsConstructor()->IsScalarConstructor());
+  auto* init = e->AsConstructor()->AsScalarConstructor();
   ASSERT_TRUE(init->literal()->IsBool());
   EXPECT_TRUE(init->literal()->AsBool()->IsTrue());
 }
@@ -157,7 +157,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsBinary());
+  ASSERT_TRUE(e->IsBinary());
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) {
@@ -199,10 +199,10 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsConstructor());
-  ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
+  ASSERT_TRUE(e->IsConstructor());
+  ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor());
 
-  auto* c = e.value->AsConstructor()->AsTypeConstructor();
+  auto* c = e->AsConstructor()->AsTypeConstructor();
   ASSERT_EQ(c->type(), f32_type);
   ASSERT_EQ(c->values().size(), 1u);
 
@@ -219,9 +219,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsBitcast());
+  ASSERT_TRUE(e->IsBitcast());
 
-  auto* c = e.value->AsBitcast();
+  auto* c = e->AsBitcast();
   ASSERT_EQ(c->type(), f32_type);
 
   ASSERT_TRUE(c->expr()->IsConstructor());
diff --git a/src/reader/wgsl/parser_impl_relational_expression_test.cc b/src/reader/wgsl/parser_impl_relational_expression_test.cc
index be712b9..f679dd8 100644
--- a/src/reader/wgsl/parser_impl_relational_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_relational_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -56,8 +56,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -79,8 +79,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kLessThanEqual, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -102,8 +102,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kGreaterThanEqual, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -141,7 +141,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_sampler_type_test.cc b/src/reader/wgsl/parser_impl_sampler_type_test.cc
index caf313c..d1c69ed 100644
--- a/src/reader/wgsl/parser_impl_sampler_type_test.cc
+++ b/src/reader/wgsl/parser_impl_sampler_type_test.cc
@@ -37,8 +37,8 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsSampler());
-  EXPECT_FALSE(t.value->AsSampler()->IsComparison());
+  ASSERT_TRUE(t->IsSampler());
+  EXPECT_FALSE(t->AsSampler()->IsComparison());
   EXPECT_FALSE(p->has_error());
 }
 
@@ -48,8 +48,8 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsSampler());
-  EXPECT_TRUE(t.value->AsSampler()->IsComparison());
+  ASSERT_TRUE(t->IsSampler());
+  EXPECT_TRUE(t->AsSampler()->IsComparison());
   EXPECT_FALSE(p->has_error());
 }
 
diff --git a/src/reader/wgsl/parser_impl_shift_expression_test.cc b/src/reader/wgsl/parser_impl_shift_expression_test.cc
index 2122bfd..9118cfd 100644
--- a/src/reader/wgsl/parser_impl_shift_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_shift_expression_test.cc
@@ -33,8 +33,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -56,8 +56,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsBinary());
-  auto* rel = e.value->AsBinary();
+  ASSERT_TRUE(e->IsBinary());
+  auto* rel = e->AsBinary();
   EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op());
 
   ASSERT_TRUE(rel->lhs()->IsIdentifier());
@@ -97,7 +97,7 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsIdentifier());
+  ASSERT_TRUE(e->IsIdentifier());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_statement_test.cc b/src/reader/wgsl/parser_impl_statement_test.cc
index 57c5cb1..bdef088 100644
--- a/src/reader/wgsl/parser_impl_statement_test.cc
+++ b/src/reader/wgsl/parser_impl_statement_test.cc
@@ -29,7 +29,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsReturn());
+  ASSERT_TRUE(e->IsReturn());
 }
 
 TEST_F(ParserImplTest, Statement_Semicolon) {
@@ -44,8 +44,8 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsReturn());
-  auto* ret = e.value->AsReturn();
+  ASSERT_TRUE(e->IsReturn());
+  auto* ret = e->AsReturn();
   ASSERT_EQ(ret->value(), nullptr);
 }
 
@@ -56,8 +56,8 @@
 
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsReturn());
-  auto* ret = e.value->AsReturn();
+  ASSERT_TRUE(e->IsReturn());
+  auto* ret = e->AsReturn();
   ASSERT_NE(ret->value(), nullptr);
   EXPECT_TRUE(ret->value()->IsBinary());
 }
@@ -88,7 +88,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsIf());
+  ASSERT_TRUE(e->IsIf());
 }
 
 TEST_F(ParserImplTest, Statement_If_Invalid) {
@@ -107,7 +107,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsVariableDecl());
+  ASSERT_TRUE(e->IsVariableDecl());
 }
 
 TEST_F(ParserImplTest, Statement_Variable_Invalid) {
@@ -136,7 +136,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsSwitch());
+  ASSERT_TRUE(e->IsSwitch());
 }
 
 TEST_F(ParserImplTest, Statement_Switch_Invalid) {
@@ -155,7 +155,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsLoop());
+  ASSERT_TRUE(e->IsLoop());
 }
 
 TEST_F(ParserImplTest, Statement_Loop_Invalid) {
@@ -174,7 +174,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsAssign());
+  ASSERT_TRUE(e->IsAssign());
 }
 
 TEST_F(ParserImplTest, Statement_Assignment_Invalid) {
@@ -203,7 +203,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsBreak());
+  ASSERT_TRUE(e->IsBreak());
 }
 
 TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) {
@@ -222,7 +222,7 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsContinue());
+  ASSERT_TRUE(e->IsContinue());
 }
 
 TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) {
@@ -242,7 +242,7 @@
   ASSERT_NE(e.value, nullptr);
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsDiscard());
+  ASSERT_TRUE(e->IsDiscard());
 }
 
 TEST_F(ParserImplTest, Statement_Discard_MissingSemicolon) {
@@ -261,8 +261,8 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e.value->IsBlock());
-  EXPECT_TRUE(e.value->AsBlock()->get(0)->IsVariableDecl());
+  ASSERT_TRUE(e->IsBlock());
+  EXPECT_TRUE(e->AsBlock()->get(0)->IsVariableDecl());
 }
 
 TEST_F(ParserImplTest, Statement_Body_Invalid) {
diff --git a/src/reader/wgsl/parser_impl_statements_test.cc b/src/reader/wgsl/parser_impl_statements_test.cc
index c7417e9..58cdc21 100644
--- a/src/reader/wgsl/parser_impl_statements_test.cc
+++ b/src/reader/wgsl/parser_impl_statements_test.cc
@@ -27,9 +27,9 @@
   auto e = p->expect_statements();
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e.value->size(), 2u);
-  EXPECT_TRUE(e.value->get(0)->IsDiscard());
-  EXPECT_TRUE(e.value->get(1)->IsReturn());
+  ASSERT_EQ(e->size(), 2u);
+  EXPECT_TRUE(e->get(0)->IsDiscard());
+  EXPECT_TRUE(e->get(1)->IsReturn());
 }
 
 TEST_F(ParserImplTest, Statements_Empty) {
@@ -37,7 +37,7 @@
   auto e = p->expect_statements();
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e.value->size(), 0u);
+  ASSERT_EQ(e->size(), 0u);
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_struct_decl_test.cc b/src/reader/wgsl/parser_impl_struct_decl_test.cc
index 81fac22..37c5f06 100644
--- a/src/reader/wgsl/parser_impl_struct_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_decl_test.cc
@@ -38,10 +38,10 @@
   EXPECT_FALSE(s.errored);
   EXPECT_TRUE(s.matched);
   ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s.value->name(), "S");
-  ASSERT_EQ(s.value->impl()->members().size(), 2u);
-  EXPECT_EQ(s.value->impl()->members()[0]->name(), "a");
-  EXPECT_EQ(s.value->impl()->members()[1]->name(), "b");
+  ASSERT_EQ(s->name(), "S");
+  ASSERT_EQ(s->impl()->members().size(), 2u);
+  EXPECT_EQ(s->impl()->members()[0]->name(), "a");
+  EXPECT_EQ(s->impl()->members()[1]->name(), "b");
 }
 
 TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) {
@@ -60,12 +60,12 @@
   EXPECT_FALSE(s.errored);
   EXPECT_TRUE(s.matched);
   ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s.value->name(), "B");
-  ASSERT_EQ(s.value->impl()->members().size(), 2u);
-  EXPECT_EQ(s.value->impl()->members()[0]->name(), "a");
-  EXPECT_EQ(s.value->impl()->members()[1]->name(), "b");
-  ASSERT_EQ(s.value->impl()->decorations().size(), 1u);
-  EXPECT_TRUE(s.value->impl()->decorations()[0]->IsBlock());
+  ASSERT_EQ(s->name(), "B");
+  ASSERT_EQ(s->impl()->members().size(), 2u);
+  EXPECT_EQ(s->impl()->members()[0]->name(), "a");
+  EXPECT_EQ(s->impl()->members()[1]->name(), "b");
+  ASSERT_EQ(s->impl()->decorations().size(), 1u);
+  EXPECT_TRUE(s->impl()->decorations()[0]->IsBlock());
 }
 
 TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) {
@@ -85,13 +85,13 @@
   EXPECT_FALSE(s.errored);
   EXPECT_TRUE(s.matched);
   ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s.value->name(), "S");
-  ASSERT_EQ(s.value->impl()->members().size(), 2u);
-  EXPECT_EQ(s.value->impl()->members()[0]->name(), "a");
-  EXPECT_EQ(s.value->impl()->members()[1]->name(), "b");
-  ASSERT_EQ(s.value->impl()->decorations().size(), 2u);
-  EXPECT_TRUE(s.value->impl()->decorations()[0]->IsBlock());
-  EXPECT_TRUE(s.value->impl()->decorations()[1]->IsBlock());
+  ASSERT_EQ(s->name(), "S");
+  ASSERT_EQ(s->impl()->members().size(), 2u);
+  EXPECT_EQ(s->impl()->members()[0]->name(), "a");
+  EXPECT_EQ(s->impl()->members()[1]->name(), "b");
+  ASSERT_EQ(s->impl()->decorations().size(), 2u);
+  EXPECT_TRUE(s->impl()->decorations()[0]->IsBlock());
+  EXPECT_TRUE(s->impl()->decorations()[1]->IsBlock());
 }
 
 TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
@@ -106,7 +106,7 @@
   EXPECT_FALSE(s.errored);
   EXPECT_TRUE(s.matched);
   ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s.value->impl()->members().size(), 0u);
+  ASSERT_EQ(s->impl()->members().size(), 0u);
 }
 
 TEST_F(ParserImplTest, StructDecl_MissingIdent) {
diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc
index b63ee50..d8c3fe7 100644
--- a/src/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_test.cc
@@ -38,14 +38,14 @@
   ASSERT_FALSE(m.errored);
   ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m.value->name(), "a");
-  EXPECT_EQ(m.value->type(), i32);
-  EXPECT_EQ(m.value->decorations().size(), 0u);
+  EXPECT_EQ(m->name(), "a");
+  EXPECT_EQ(m->type(), i32);
+  EXPECT_EQ(m->decorations().size(), 0u);
 
-  ASSERT_EQ(m.value->source().range.begin.line, 1u);
-  ASSERT_EQ(m.value->source().range.begin.column, 1u);
-  ASSERT_EQ(m.value->source().range.end.line, 1u);
-  ASSERT_EQ(m.value->source().range.end.column, 2u);
+  ASSERT_EQ(m->source().range.begin.line, 1u);
+  ASSERT_EQ(m->source().range.begin.column, 1u);
+  ASSERT_EQ(m->source().range.end.line, 1u);
+  ASSERT_EQ(m->source().range.end.column, 2u);
 }
 
 TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
@@ -62,16 +62,16 @@
   ASSERT_FALSE(m.errored);
   ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m.value->name(), "a");
-  EXPECT_EQ(m.value->type(), i32);
-  EXPECT_EQ(m.value->decorations().size(), 1u);
-  EXPECT_TRUE(m.value->decorations()[0]->IsOffset());
-  EXPECT_EQ(m.value->decorations()[0]->AsOffset()->offset(), 2u);
+  EXPECT_EQ(m->name(), "a");
+  EXPECT_EQ(m->type(), i32);
+  EXPECT_EQ(m->decorations().size(), 1u);
+  EXPECT_TRUE(m->decorations()[0]->IsOffset());
+  EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u);
 
-  ASSERT_EQ(m.value->source().range.begin.line, 1u);
-  ASSERT_EQ(m.value->source().range.begin.column, 15u);
-  ASSERT_EQ(m.value->source().range.end.line, 1u);
-  ASSERT_EQ(m.value->source().range.end.column, 16u);
+  ASSERT_EQ(m->source().range.begin.line, 1u);
+  ASSERT_EQ(m->source().range.begin.column, 15u);
+  ASSERT_EQ(m->source().range.end.line, 1u);
+  ASSERT_EQ(m->source().range.end.column, 16u);
 }
 
 TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
@@ -89,18 +89,18 @@
   ASSERT_FALSE(m.errored);
   ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m.value->name(), "a");
-  EXPECT_EQ(m.value->type(), i32);
-  EXPECT_EQ(m.value->decorations().size(), 2u);
-  EXPECT_TRUE(m.value->decorations()[0]->IsOffset());
-  EXPECT_EQ(m.value->decorations()[0]->AsOffset()->offset(), 2u);
-  EXPECT_TRUE(m.value->decorations()[1]->IsOffset());
-  EXPECT_EQ(m.value->decorations()[1]->AsOffset()->offset(), 4u);
+  EXPECT_EQ(m->name(), "a");
+  EXPECT_EQ(m->type(), i32);
+  EXPECT_EQ(m->decorations().size(), 2u);
+  EXPECT_TRUE(m->decorations()[0]->IsOffset());
+  EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u);
+  EXPECT_TRUE(m->decorations()[1]->IsOffset());
+  EXPECT_EQ(m->decorations()[1]->AsOffset()->offset(), 4u);
 
-  ASSERT_EQ(m.value->source().range.begin.line, 2u);
-  ASSERT_EQ(m.value->source().range.begin.column, 15u);
-  ASSERT_EQ(m.value->source().range.end.line, 2u);
-  ASSERT_EQ(m.value->source().range.end.column, 16u);
+  ASSERT_EQ(m->source().range.begin.line, 2u);
+  ASSERT_EQ(m->source().range.begin.column, 15u);
+  ASSERT_EQ(m->source().range.end.line, 2u);
+  ASSERT_EQ(m->source().range.end.column, 16u);
 }
 
 TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
diff --git a/src/reader/wgsl/parser_impl_switch_body_test.cc b/src/reader/wgsl/parser_impl_switch_body_test.cc
index 69af79f..ae2f1b7 100644
--- a/src/reader/wgsl/parser_impl_switch_body_test.cc
+++ b/src/reader/wgsl/parser_impl_switch_body_test.cc
@@ -29,10 +29,10 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsCase());
-  EXPECT_FALSE(e.value->IsDefault());
-  ASSERT_EQ(e.value->body()->size(), 1u);
-  EXPECT_TRUE(e.value->body()->get(0)->IsAssign());
+  ASSERT_TRUE(e->IsCase());
+  EXPECT_FALSE(e->IsDefault());
+  ASSERT_EQ(e->body()->size(), 1u);
+  EXPECT_TRUE(e->body()->get(0)->IsAssign());
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
@@ -112,10 +112,10 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsCase());
-  EXPECT_TRUE(e.value->IsDefault());
-  ASSERT_EQ(e.value->body()->size(), 1u);
-  EXPECT_TRUE(e.value->body()->get(0)->IsAssign());
+  ASSERT_TRUE(e->IsCase());
+  EXPECT_TRUE(e->IsDefault());
+  ASSERT_EQ(e->body()->size(), 1u);
+  EXPECT_TRUE(e->body()->get(0)->IsAssign());
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) {
diff --git a/src/reader/wgsl/parser_impl_switch_stmt_test.cc b/src/reader/wgsl/parser_impl_switch_stmt_test.cc
index d0ea352..85a5a97 100644
--- a/src/reader/wgsl/parser_impl_switch_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_switch_stmt_test.cc
@@ -33,10 +33,10 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsSwitch());
-  ASSERT_EQ(e.value->body().size(), 2u);
-  EXPECT_FALSE(e.value->body()[0]->IsDefault());
-  EXPECT_FALSE(e.value->body()[1]->IsDefault());
+  ASSERT_TRUE(e->IsSwitch());
+  ASSERT_EQ(e->body().size(), 2u);
+  EXPECT_FALSE(e->body()[0]->IsDefault());
+  EXPECT_FALSE(e->body()[1]->IsDefault());
 }
 
 TEST_F(ParserImplTest, SwitchStmt_Empty) {
@@ -46,8 +46,8 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsSwitch());
-  ASSERT_EQ(e.value->body().size(), 0u);
+  ASSERT_TRUE(e->IsSwitch());
+  ASSERT_EQ(e->body().size(), 0u);
 }
 
 TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
@@ -61,12 +61,12 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsSwitch());
+  ASSERT_TRUE(e->IsSwitch());
 
-  ASSERT_EQ(e.value->body().size(), 3u);
-  ASSERT_FALSE(e.value->body()[0]->IsDefault());
-  ASSERT_TRUE(e.value->body()[1]->IsDefault());
-  ASSERT_FALSE(e.value->body()[2]->IsDefault());
+  ASSERT_EQ(e->body().size(), 3u);
+  ASSERT_FALSE(e->body()[0]->IsDefault());
+  ASSERT_TRUE(e->body()[1]->IsDefault());
+  ASSERT_FALSE(e->body()[2]->IsDefault());
 }
 
 TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) {
diff --git a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
index b040fad..2913771 100644
--- a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
+++ b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
@@ -40,8 +40,8 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsSampler());
-  ASSERT_FALSE(t.value->AsSampler()->IsComparison());
+  ASSERT_TRUE(t->IsSampler());
+  ASSERT_FALSE(t->AsSampler()->IsComparison());
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
@@ -51,8 +51,8 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsSampler());
-  ASSERT_TRUE(t.value->AsSampler()->IsComparison());
+  ASSERT_TRUE(t->IsSampler());
+  ASSERT_TRUE(t->AsSampler()->IsComparison());
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
@@ -62,9 +62,9 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsDepth());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsDepth());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32_Old) {
@@ -74,10 +74,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32_Old) {
@@ -87,10 +87,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsI32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32_Old) {
@@ -100,10 +100,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsU32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k3d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid_Old) {
@@ -154,10 +154,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
@@ -167,10 +167,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsI32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
@@ -180,10 +180,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsU32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k3d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) {
@@ -233,10 +233,10 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsMultisampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsMultisampled()->type()->IsI32());
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsMultisampled());
+  ASSERT_TRUE(t->AsTexture()->AsMultisampled()->type()->IsI32());
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) {
@@ -287,13 +287,13 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsStorage());
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsStorage());
+  EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(),
             ast::type::ImageFormat::kR8Unorm);
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
+  EXPECT_EQ(t->AsTexture()->AsStorage()->access(),
             ast::AccessControl::kReadOnly);
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d);
 }
 
 TEST_F(ParserImplTest,
@@ -304,13 +304,13 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsStorage());
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsStorage());
+  EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(),
             ast::type::ImageFormat::kR16Float);
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
+  EXPECT_EQ(t->AsTexture()->AsStorage()->access(),
             ast::AccessControl::kWriteOnly);
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType_Old) {
@@ -357,13 +357,13 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsStorage());
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsStorage());
+  EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(),
             ast::type::ImageFormat::kR8Unorm);
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
+  EXPECT_EQ(t->AsTexture()->AsStorage()->access(),
             ast::AccessControl::kReadOnly);
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) {
@@ -373,13 +373,13 @@
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsStorage());
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsStorage());
+  EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(),
             ast::type::ImageFormat::kR16Float);
-  EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
+  EXPECT_EQ(t->AsTexture()->AsStorage()->access(),
             ast::AccessControl::kWriteOnly);
-  EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
diff --git a/src/reader/wgsl/parser_impl_type_alias_test.cc b/src/reader/wgsl/parser_impl_type_alias_test.cc
index df97a4c..cbfb7a1 100644
--- a/src/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/src/reader/wgsl/parser_impl_type_alias_test.cc
@@ -35,8 +35,8 @@
   EXPECT_FALSE(t.errored);
   EXPECT_TRUE(t.matched);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsAlias());
-  auto* alias = t.value->AsAlias();
+  ASSERT_TRUE(t->IsAlias());
+  auto* alias = t->AsAlias();
   ASSERT_TRUE(alias->type()->IsI32());
   ASSERT_EQ(alias->type(), i32);
 }
@@ -52,8 +52,8 @@
   EXPECT_FALSE(t.errored);
   EXPECT_TRUE(t.matched);
   ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->IsAlias());
-  auto* alias = t.value->AsAlias();
+  ASSERT_TRUE(t->IsAlias());
+  auto* alias = t->AsAlias();
   EXPECT_EQ(alias->name(), "a");
   ASSERT_TRUE(alias->type()->IsStruct());
 
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index f0cc10d..a3d6eae 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -59,9 +59,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, alias_type);
-  ASSERT_TRUE(t.value->IsAlias());
+  ASSERT_TRUE(t->IsAlias());
 
-  auto* alias = t.value->AsAlias();
+  auto* alias = t->AsAlias();
   EXPECT_EQ(alias->name(), "A");
   EXPECT_EQ(alias->type(), int_type);
 }
@@ -87,7 +87,7 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, bool_type);
-  ASSERT_TRUE(t.value->IsBool());
+  ASSERT_TRUE(t->IsBool());
 }
 
 TEST_F(ParserImplTest, TypeDecl_F32) {
@@ -100,7 +100,7 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, float_type);
-  ASSERT_TRUE(t.value->IsF32());
+  ASSERT_TRUE(t->IsF32());
 }
 
 TEST_F(ParserImplTest, TypeDecl_I32) {
@@ -113,7 +113,7 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, int_type);
-  ASSERT_TRUE(t.value->IsI32());
+  ASSERT_TRUE(t->IsI32());
 }
 
 TEST_F(ParserImplTest, TypeDecl_U32) {
@@ -126,7 +126,7 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, uint_type);
-  ASSERT_TRUE(t.value->IsU32());
+  ASSERT_TRUE(t->IsU32());
 }
 
 struct VecData {
@@ -148,8 +148,8 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  EXPECT_TRUE(t.value->IsVector());
-  EXPECT_EQ(t.value->AsVector()->size(), params.count);
+  EXPECT_TRUE(t->IsVector());
+  EXPECT_EQ(t->AsVector()->size(), params.count);
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          VecTest,
@@ -236,9 +236,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsPointer());
+  ASSERT_TRUE(t->IsPointer());
 
-  auto* ptr = t.value->AsPointer();
+  auto* ptr = t->AsPointer();
   ASSERT_TRUE(ptr->type()->IsF32());
   ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
 }
@@ -250,9 +250,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsPointer());
+  ASSERT_TRUE(t->IsPointer());
 
-  auto* ptr = t.value->AsPointer();
+  auto* ptr = t->AsPointer();
   ASSERT_TRUE(ptr->type()->IsVector());
   ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
 
@@ -348,9 +348,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsArray());
+  ASSERT_TRUE(t->IsArray());
 
-  auto* a = t.value->AsArray();
+  auto* a = t->AsArray();
   ASSERT_FALSE(a->IsRuntimeArray());
   ASSERT_EQ(a->size(), 5u);
   ASSERT_TRUE(a->type()->IsF32());
@@ -364,9 +364,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsArray());
+  ASSERT_TRUE(t->IsArray());
 
-  auto* a = t.value->AsArray();
+  auto* a = t->AsArray();
   ASSERT_FALSE(a->IsRuntimeArray());
   ASSERT_EQ(a->size(), 5u);
   ASSERT_TRUE(a->type()->IsF32());
@@ -381,9 +381,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsArray());
+  ASSERT_TRUE(t->IsArray());
 
-  auto* a = t.value->AsArray();
+  auto* a = t->AsArray();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsF32());
   ASSERT_TRUE(a->has_array_stride());
@@ -397,9 +397,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsArray());
+  ASSERT_TRUE(t->IsArray());
 
-  auto* a = t.value->AsArray();
+  auto* a = t->AsArray();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsF32());
 
@@ -418,9 +418,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsArray());
+  ASSERT_TRUE(t->IsArray());
 
-  auto* a = t.value->AsArray();
+  auto* a = t->AsArray();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsF32());
 
@@ -521,9 +521,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->IsArray());
+  ASSERT_TRUE(t->IsArray());
 
-  auto* a = t.value->AsArray();
+  auto* a = t->AsArray();
   ASSERT_TRUE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type()->IsU32());
 }
@@ -618,8 +618,8 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
-  EXPECT_TRUE(t.value->IsMatrix());
-  auto* mat = t.value->AsMatrix();
+  EXPECT_TRUE(t->IsMatrix());
+  auto* mat = t->AsMatrix();
   EXPECT_EQ(mat->rows(), params.rows);
   EXPECT_EQ(mat->columns(), params.columns);
 }
@@ -743,8 +743,8 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, type);
-  ASSERT_TRUE(t.value->IsSampler());
-  ASSERT_FALSE(t.value->AsSampler()->IsComparison());
+  ASSERT_TRUE(t->IsSampler());
+  ASSERT_FALSE(t->AsSampler()->IsComparison());
 }
 
 TEST_F(ParserImplTest, TypeDecl_Texture_Old) {
@@ -759,9 +759,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr) << p->error();
   EXPECT_EQ(t.value, type);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32());
 }
 
 TEST_F(ParserImplTest, TypeDecl_Texture) {
@@ -776,9 +776,9 @@
   EXPECT_FALSE(t.errored);
   ASSERT_NE(t.value, nullptr);
   EXPECT_EQ(t.value, type);
-  ASSERT_TRUE(t.value->IsTexture());
-  ASSERT_TRUE(t.value->AsTexture()->IsSampled());
-  ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsSampled());
+  ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32());
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_unary_expression_test.cc b/src/reader/wgsl/parser_impl_unary_expression_test.cc
index d9c645c..57787ca 100644
--- a/src/reader/wgsl/parser_impl_unary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_unary_expression_test.cc
@@ -34,8 +34,8 @@
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e.value->IsArrayAccessor());
-  auto* ary = e.value->AsArrayAccessor();
+  ASSERT_TRUE(e->IsArrayAccessor());
+  auto* ary = e->AsArrayAccessor();
   ASSERT_TRUE(ary->array()->IsIdentifier());
   auto* ident = ary->array()->AsIdentifier();
   EXPECT_EQ(ident->name(), "a");
@@ -54,9 +54,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsUnaryOp());
+  ASSERT_TRUE(e->IsUnaryOp());
 
-  auto* u = e.value->AsUnaryOp();
+  auto* u = e->AsUnaryOp();
   ASSERT_EQ(u->op(), ast::UnaryOp::kNegation);
 
   ASSERT_TRUE(u->expr()->IsConstructor());
@@ -84,9 +84,9 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsUnaryOp());
+  ASSERT_TRUE(e->IsUnaryOp());
 
-  auto* u = e.value->AsUnaryOp();
+  auto* u = e->AsUnaryOp();
   ASSERT_EQ(u->op(), ast::UnaryOp::kNot);
 
   ASSERT_TRUE(u->expr()->IsConstructor());
diff --git a/src/reader/wgsl/parser_impl_variable_decl_test.cc b/src/reader/wgsl/parser_impl_variable_decl_test.cc
index 3ff51ac..f84f0d9 100644
--- a/src/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -29,14 +29,14 @@
   EXPECT_TRUE(var.matched);
   EXPECT_FALSE(var.errored);
   ASSERT_NE(var.value, nullptr);
-  EXPECT_EQ(var.value->name(), "my_var");
-  EXPECT_NE(var.value->type(), nullptr);
-  EXPECT_TRUE(var.value->type()->IsF32());
+  EXPECT_EQ(var->name(), "my_var");
+  EXPECT_NE(var->type(), nullptr);
+  EXPECT_TRUE(var->type()->IsF32());
 
-  EXPECT_EQ(var.value->source().range.begin.line, 1u);
-  EXPECT_EQ(var.value->source().range.begin.column, 5u);
-  EXPECT_EQ(var.value->source().range.end.line, 1u);
-  EXPECT_EQ(var.value->source().range.end.column, 11u);
+  EXPECT_EQ(var->source().range.begin.line, 1u);
+  EXPECT_EQ(var->source().range.begin.column, 5u);
+  EXPECT_EQ(var->source().range.end.line, 1u);
+  EXPECT_EQ(var->source().range.end.column, 11u);
 }
 
 TEST_F(ParserImplTest, VariableDecl_MissingVar) {
@@ -68,14 +68,14 @@
   EXPECT_FALSE(v.errored);
   EXPECT_FALSE(p->has_error());
   ASSERT_NE(v.value, nullptr);
-  EXPECT_EQ(v.value->name(), "my_var");
-  EXPECT_TRUE(v.value->type()->IsF32());
-  EXPECT_EQ(v.value->storage_class(), ast::StorageClass::kPrivate);
+  EXPECT_EQ(v->name(), "my_var");
+  EXPECT_TRUE(v->type()->IsF32());
+  EXPECT_EQ(v->storage_class(), ast::StorageClass::kPrivate);
 
-  EXPECT_EQ(v.value->source().range.begin.line, 1u);
-  EXPECT_EQ(v.value->source().range.begin.column, 14u);
-  EXPECT_EQ(v.value->source().range.end.line, 1u);
-  EXPECT_EQ(v.value->source().range.end.column, 20u);
+  EXPECT_EQ(v->source().range.begin.line, 1u);
+  EXPECT_EQ(v->source().range.begin.column, 14u);
+  EXPECT_EQ(v->source().range.end.line, 1u);
+  EXPECT_EQ(v->source().range.end.column, 20u);
 }
 
 TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
diff --git a/src/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
index a0fba95..20a966c 100644
--- a/src/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -30,16 +30,16 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsVariableDecl());
-  ASSERT_NE(e.value->variable(), nullptr);
-  EXPECT_EQ(e.value->variable()->name(), "a");
+  ASSERT_TRUE(e->IsVariableDecl());
+  ASSERT_NE(e->variable(), nullptr);
+  EXPECT_EQ(e->variable()->name(), "a");
 
-  ASSERT_EQ(e.value->source().range.begin.line, 1u);
-  ASSERT_EQ(e.value->source().range.begin.column, 5u);
-  ASSERT_EQ(e.value->source().range.end.line, 1u);
-  ASSERT_EQ(e.value->source().range.end.column, 6u);
+  ASSERT_EQ(e->source().range.begin.line, 1u);
+  ASSERT_EQ(e->source().range.begin.column, 5u);
+  ASSERT_EQ(e->source().range.end.line, 1u);
+  ASSERT_EQ(e->source().range.end.column, 6u);
 
-  EXPECT_EQ(e.value->variable()->constructor(), nullptr);
+  EXPECT_EQ(e->variable()->constructor(), nullptr);
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
@@ -49,17 +49,17 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsVariableDecl());
-  ASSERT_NE(e.value->variable(), nullptr);
-  EXPECT_EQ(e.value->variable()->name(), "a");
+  ASSERT_TRUE(e->IsVariableDecl());
+  ASSERT_NE(e->variable(), nullptr);
+  EXPECT_EQ(e->variable()->name(), "a");
 
-  ASSERT_EQ(e.value->source().range.begin.line, 1u);
-  ASSERT_EQ(e.value->source().range.begin.column, 5u);
-  ASSERT_EQ(e.value->source().range.end.line, 1u);
-  ASSERT_EQ(e.value->source().range.end.column, 6u);
+  ASSERT_EQ(e->source().range.begin.line, 1u);
+  ASSERT_EQ(e->source().range.begin.column, 5u);
+  ASSERT_EQ(e->source().range.end.line, 1u);
+  ASSERT_EQ(e->source().range.end.column, 6u);
 
-  ASSERT_NE(e.value->variable()->constructor(), nullptr);
-  EXPECT_TRUE(e.value->variable()->constructor()->IsConstructor());
+  ASSERT_NE(e->variable()->constructor(), nullptr);
+  EXPECT_TRUE(e->variable()->constructor()->IsConstructor());
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) {
@@ -89,12 +89,12 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->IsVariableDecl());
+  ASSERT_TRUE(e->IsVariableDecl());
 
-  ASSERT_EQ(e.value->source().range.begin.line, 1u);
-  ASSERT_EQ(e.value->source().range.begin.column, 7u);
-  ASSERT_EQ(e.value->source().range.end.line, 1u);
-  ASSERT_EQ(e.value->source().range.end.column, 8u);
+  ASSERT_EQ(e->source().range.begin.line, 1u);
+  ASSERT_EQ(e->source().range.begin.column, 7u);
+  ASSERT_EQ(e->source().range.end.line, 1u);
+  ASSERT_EQ(e->source().range.end.column, 8u);
 }
 
 TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {