[tint][wgsl][reader] Expand expression Source spans

To include the whole sub-expression.

Bug: tint:2127
Change-Id: Icc6baf4acdc8daec4f4797db41a5ead82beb3acd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/167800
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/wgsl/reader/parser/additive_expression_test.cc b/src/tint/lang/wgsl/reader/parser/additive_expression_test.cc
index 782d922..0317b9a 100644
--- a/src/tint/lang/wgsl/reader/parser/additive_expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/additive_expression_test.cc
@@ -33,15 +33,15 @@
 TEST_F(WGSLParserTest, AdditiveExpression_Parses_Plus) {
     auto p = parser("a + b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 4u);
+    EXPECT_EQ(e->source.range.end.column, 6u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -59,7 +59,7 @@
 TEST_F(WGSLParserTest, AdditiveExpression_Parses_Minus) {
     auto p = parser("a - b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -80,7 +80,7 @@
 TEST_F(WGSLParserTest, AdditiveExpression_Parses_MinusMinus) {
     auto p = parser("a--b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -105,7 +105,7 @@
 TEST_F(WGSLParserTest, AdditiveExpression_Parses_MultipleOps) {
     auto p = parser("a - b + c - d");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -151,7 +151,7 @@
 TEST_F(WGSLParserTest, AdditiveExpression_Parses_MultipleOps_MixedMultiplication) {
     auto p = parser("a - b * c - d");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -197,7 +197,7 @@
 TEST_F(WGSLParserTest, AdditiveExpression_InvalidRHS) {
     auto p = parser("a + if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     EXPECT_TRUE(p->has_error());
@@ -207,7 +207,7 @@
 TEST_F(WGSLParserTest, AdditiveExpression_NoMatch_ReturnsLHS) {
     auto p = parser("a true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_additive_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_additive_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
diff --git a/src/tint/lang/wgsl/reader/parser/bitwise_expression_test.cc b/src/tint/lang/wgsl/reader/parser/bitwise_expression_test.cc
index 2a3fc71..4660dff 100644
--- a/src/tint/lang/wgsl/reader/parser/bitwise_expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/bitwise_expression_test.cc
@@ -33,7 +33,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_NoOp) {
     auto p = parser("a true");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
@@ -43,16 +43,16 @@
 TEST_F(WGSLParserTest, BitwiseExpr_Or_Parses) {
     auto p = parser("a | true");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 4u);
+    EXPECT_EQ(e->source.range.end.column, 9u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -69,7 +69,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_Or_Parses_Multiple) {
     auto p = parser("a | true | b");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
@@ -103,7 +103,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_Or_InvalidRHS) {
     auto p = parser("true | if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.matched);
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
@@ -114,16 +114,16 @@
 TEST_F(WGSLParserTest, BitwiseExpr_Xor_Parses) {
     auto p = parser("a ^ true");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 4u);
+    EXPECT_EQ(e->source.range.end.column, 9u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -140,7 +140,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_Xor_Parses_Multiple) {
     auto p = parser("a ^ true ^ b");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
@@ -173,7 +173,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_Xor_InvalidRHS) {
     auto p = parser("true ^ if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.matched);
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
@@ -184,16 +184,16 @@
 TEST_F(WGSLParserTest, BitwiseExpr_And_Parses) {
     auto p = parser("a & true");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 4u);
+    EXPECT_EQ(e->source.range.end.column, 9u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -210,7 +210,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_And_Parses_Multiple) {
     auto p = parser("a & true & b");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.matched);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
@@ -243,7 +243,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_And_Parses_AndAnd) {
     auto p = parser("a & true &&b");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     // bitwise_expression_post_unary_expression returns before parsing '&&'
 
     EXPECT_TRUE(e.matched);
@@ -264,7 +264,7 @@
 TEST_F(WGSLParserTest, BitwiseExpr_And_InvalidRHS) {
     auto p = parser("true & if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->bitwise_expression_post_unary_expression(lhs.value);
+    auto e = p->bitwise_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.matched);
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
diff --git a/src/tint/lang/wgsl/reader/parser/expression_test.cc b/src/tint/lang/wgsl/reader/parser/expression_test.cc
index 2b6c7a2..74d78df 100644
--- a/src/tint/lang/wgsl/reader/parser/expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/expression_test.cc
@@ -50,9 +50,9 @@
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -117,9 +117,9 @@
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -180,7 +180,11 @@
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:3: mixing '&&' and '||' requires parenthesis");
+    EXPECT_EQ(p->builder().Diagnostics().str(),
+              R"(test.wgsl:1:3 error: mixing '&&' and '||' requires parenthesis
+a && true || b
+  ^^^^^^^^^^
+)");
 }
 
 TEST_F(WGSLParserTest, Expression_Mixing_AndWithOr) {
@@ -190,7 +194,11 @@
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->error(), "1:3: mixing '||' and '&&' requires parenthesis");
+    EXPECT_EQ(p->builder().Diagnostics().str(),
+              R"(test.wgsl:1:3 error: mixing '||' and '&&' requires parenthesis
+a || true && b
+  ^^^^^^^^^^
+)");
 }
 
 TEST_F(WGSLParserTest, Expression_Bitwise) {
@@ -281,7 +289,7 @@
     EXPECT_TRUE(e.errored);
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(e.value, nullptr);
-    EXPECT_EQ(p->error(), R"(1:7: mixing '&&' and '||' requires parenthesis)");
+    EXPECT_EQ(p->error(), R"(1:3: mixing '&&' and '||' requires parenthesis)");
 }
 
 TEST_F(WGSLParserTest, Expression_SubtractionNoSpace) {
diff --git a/src/tint/lang/wgsl/reader/parser/math_expression_test.cc b/src/tint/lang/wgsl/reader/parser/math_expression_test.cc
index 04e1165..4ae6f8e 100644
--- a/src/tint/lang/wgsl/reader/parser/math_expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/math_expression_test.cc
@@ -33,7 +33,7 @@
 TEST_F(WGSLParserTest, MathExpression_Parses_Multiplicative) {
     auto p = parser("a * b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_math_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_math_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -54,7 +54,7 @@
 TEST_F(WGSLParserTest, MathExpression_Parses_Mixed_MultiplicativeStart) {
     auto p = parser("a * b + c");
     auto lhs = p->unary_expression();
-    auto e = p->expect_math_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_math_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -89,7 +89,7 @@
 TEST_F(WGSLParserTest, MathExpression_Parses_Additive) {
     auto p = parser("a + b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_math_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_math_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -110,7 +110,7 @@
 TEST_F(WGSLParserTest, MathExpression_Parses_Mixed_AdditiveStart) {
     auto p = parser("a + b * c");
     auto lhs = p->unary_expression();
-    auto e = p->expect_math_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_math_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -145,7 +145,7 @@
 TEST_F(WGSLParserTest, MathExpression_NoMatch_ReturnLHS) {
     auto p = parser("a if");
     auto lhs = p->unary_expression();
-    auto e = p->expect_math_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_math_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -155,7 +155,7 @@
 TEST_F(WGSLParserTest, MathExpression_InvalidRHS) {
     auto p = parser("a * if");
     auto lhs = p->unary_expression();
-    auto e = p->expect_math_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_math_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.errored);
     EXPECT_TRUE(p->has_error());
     ASSERT_EQ(e.value, nullptr);
diff --git a/src/tint/lang/wgsl/reader/parser/multiplicative_expression_test.cc b/src/tint/lang/wgsl/reader/parser/multiplicative_expression_test.cc
index b41347c..d0e11b7 100644
--- a/src/tint/lang/wgsl/reader/parser/multiplicative_expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/multiplicative_expression_test.cc
@@ -33,7 +33,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_Parses_Multiply) {
     auto p = parser("a * b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -54,7 +54,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_Parses_Multiply_UnaryIndirect) {
     auto p = parser("a **b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -79,7 +79,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_Parses_Divide) {
     auto p = parser("a / b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -100,7 +100,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_Parses_Modulo) {
     auto p = parser("a % b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -121,7 +121,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_Parses_Grouping) {
     auto p = parser("a * b / c % d * e");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -178,7 +178,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_InvalidRHS) {
     auto p = parser("a * if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     ASSERT_TRUE(p->has_error());
@@ -188,7 +188,7 @@
 TEST_F(WGSLParserTest, MultiplicativeExpression_NoMatch_ReturnsLHS) {
     auto p = parser("a + b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_multiplicative_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index e3698f9..104f37d 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -173,7 +173,11 @@
 
     /// @returns the Source that returns the combined source from start to the current last token's
     /// source.
-    tint::Source Source() const {
+    tint::Source operator()() const { return *this; }
+
+    /// @returns the Source that returns the combined source from start to the current last token's
+    /// source.
+    operator tint::Source() const {
         auto end = parser_->last_source().End();
         if (end < start_) {
             end = start_;
@@ -181,10 +185,6 @@
         return Source::Combine(start_, end);
     }
 
-    /// Implicit conversion to Source that returns the combined source from start to the current
-    /// last token's source.
-    operator tint::Source() const { return Source(); }
-
   private:
     Parser* parser_;
     tint::Source start_;
@@ -447,7 +447,7 @@
             return Failure::kErrored;
         }
 
-        builder_.AST().AddEnable(create<ast::Enable>(decl_source.Source(), std::move(extensions)));
+        builder_.AST().AddEnable(create<ast::Enable>(decl_source(), std::move(extensions)));
         return kSuccess;
     });
 }
@@ -508,8 +508,7 @@
             return Failure::kErrored;
         }
 
-        builder_.AST().AddRequires(
-            create<ast::Requires>(decl_source.Source(), std::move(features)));
+        builder_.AST().AddRequires(create<ast::Requires>(decl_source(), std::move(features)));
         return kSuccess;
     });
 }
@@ -857,8 +856,8 @@
 // type_alias_decl
 //   : ALIAS IDENT EQUAL type_specifier
 Maybe<const ast::Alias*> Parser::type_alias_decl() {
-    Source source;
-    if (!match(Token::Type::kAlias, &source)) {
+    MultiTokenSource source(this);
+    if (!match(Token::Type::kAlias)) {
         return Failure::kNoMatch;
     }
 
@@ -881,7 +880,7 @@
         return add_error(peek(), "invalid type alias");
     }
 
-    return builder_.ty.alias(make_source_range_from(source), name.value, type.value);
+    return builder_.ty.alias(source(), name.value, type.value);
 }
 
 // type_specifier
@@ -894,7 +893,7 @@
     }
 
     if (!peek_is(Token::Type::kTemplateArgsLeft)) {
-        return builder_.ty(builder_.Ident(source.Source(), ident.to_str()));
+        return builder_.ty(builder_.Ident(source(), ident.to_str()));
     }
 
     auto args = expect_template_arg_block("type template arguments", [&] {
@@ -904,7 +903,7 @@
     if (args.errored) {
         return Failure::kErrored;
     }
-    return builder_.ty(builder_.Ident(source.Source(), ident.to_str(), std::move(args.value)));
+    return builder_.ty(builder_.Ident(source(), ident.to_str(), std::move(args.value)));
 }
 
 template <typename ENUM>
@@ -1042,8 +1041,8 @@
 // const_assert_statement
 //   : STATIC_ASSERT expression
 Maybe<const ast::ConstAssert*> Parser::const_assert_statement() {
-    Source start;
-    if (!match(Token::Type::kConstAssert, &start)) {
+    MultiTokenSource source(this);
+    if (!match(Token::Type::kConstAssert)) {
         return Failure::kNoMatch;
     }
 
@@ -1055,8 +1054,7 @@
         return add_error(peek(), "unable to parse condition expression");
     }
 
-    Source source = make_source_range_from(start);
-    return create<ast::ConstAssert>(source, condition.value);
+    return create<ast::ConstAssert>(source(), condition.value);
 }
 
 // function_decl
@@ -1213,16 +1211,14 @@
 //   : attribute* BRACE_LEFT statement* BRACE_RIGHT
 Expect<ast::BlockStatement*> Parser::expect_compound_statement(AttributeList& attrs,
                                                                std::string_view use) {
-    auto source_start = peek().source();
+    MultiTokenSource source(this);
     auto stmts =
         expect_brace_block(use, [&]() -> Expect<StatementList> { return expect_statements(); });
-    auto source_end = last_source();
     if (stmts.errored) {
         return Failure::kErrored;
     }
     TINT_DEFER(attrs.Clear());
-    return create<ast::BlockStatement>(Source::Combine(source_start, source_end), stmts.value,
-                                       std::move(attrs));
+    return create<ast::BlockStatement>(source(), stmts.value, std::move(attrs));
 }
 
 // paren_expression
@@ -1454,14 +1450,14 @@
 //   | LET optionally_typed_ident EQUAL expression
 //   | CONST optionally_typed_ident EQUAL expression
 Maybe<const ast::VariableDeclStatement*> Parser::variable_statement() {
-    auto decl_source_range = make_source_range();
+    MultiTokenSource decl_source_range(this);
     if (match(Token::Type::kConst)) {
         auto typed_ident = expect_optionally_typed_ident("'const' declaration");
         if (typed_ident.errored) {
             return Failure::kErrored;
         }
 
-        auto decl_source = decl_source_range.Source();
+        auto decl_source = decl_source_range();
 
         if (!expect("'const' declaration", Token::Type::kEqual)) {
             return Failure::kErrored;
@@ -1489,7 +1485,7 @@
             return Failure::kErrored;
         }
 
-        auto decl_source = decl_source_range.Source();
+        auto decl_source = decl_source_range();
 
         if (!expect("'let' declaration", Token::Type::kEqual)) {
             return Failure::kErrored;
@@ -1519,7 +1515,7 @@
         return Failure::kNoMatch;
     }
 
-    auto decl_source = decl_source_range.Source();
+    auto decl_source = decl_source_range();
 
     const ast::Expression* initializer = nullptr;
     if (match(Token::Type::kEqual)) {
@@ -1779,7 +1775,7 @@
     }
 
     Maybe<const ast::BlockStatement*> continuing(Failure::kErrored);
-    auto body_start = peek().source();
+    MultiTokenSource body_source(this);
     auto body = expect_brace_block("loop", [&]() -> Maybe<StatementList> {
         auto stmts = expect_statements();
         if (stmts.errored) {
@@ -1795,13 +1791,10 @@
     if (body.errored) {
         return Failure::kErrored;
     }
-    auto body_end = last_source();
 
     TINT_DEFER(attrs.Clear());
     return create<ast::LoopStatement>(
-        source,
-        create<ast::BlockStatement>(Source::Combine(body_start, body_end), body.value,
-                                    std::move(body_attrs.value)),
+        source, create<ast::BlockStatement>(body_source(), body.value, std::move(body_attrs.value)),
         continuing.value, std::move(attrs));
 }
 
@@ -2017,7 +2010,7 @@
         return Failure::kErrored;
     }
 
-    auto source_start = peek().source();
+    MultiTokenSource source(this);
     auto body = expect_brace_block("", [&]() -> Expect<StatementList> {
         StatementList stmts;
 
@@ -2047,10 +2040,8 @@
     if (body.errored) {
         return Failure::kErrored;
     }
-    auto source_end = last_source();
 
-    return create<ast::BlockStatement>(Source::Combine(source_start, source_end), body.value,
-                                       std::move(attrs.value));
+    return create<ast::BlockStatement>(source(), body.value, std::move(attrs.value));
 }
 
 // continuing_statement
@@ -2109,9 +2100,9 @@
                 return expect_expression_list("template argument list",
                                               Token::Type::kTemplateArgsRight);
             });
-            ident = builder_.Ident(source.Source(), t.to_str(), std::move(tmpl_args.value));
+            ident = builder_.Ident(source(), t.to_str(), std::move(tmpl_args.value));
         } else {
-            ident = builder_.Ident(source.Source(), t.to_str());
+            ident = builder_.Ident(source(), t.to_str());
         }
 
         if (peek_is(Token::Type::kParenLeft)) {
@@ -2120,7 +2111,7 @@
                 return Failure::kErrored;
             }
 
-            return builder_.Call(source.Source(), ident, std::move(params.value));
+            return builder_.Call(source(), ident, std::move(params.value));
         }
 
         return builder_.Expr(ident);
@@ -2162,7 +2153,7 @@
                     return Failure::kErrored;
                 }
 
-                return create<ast::IndexAccessorExpression>(source.Source(), prefix, param.value);
+                return create<ast::IndexAccessorExpression>(source(), prefix, param.value);
             });
 
             if (res.errored) {
@@ -2178,7 +2169,7 @@
                 return Failure::kErrored;
             }
 
-            prefix = builder_.MemberAccessor(source.Source(), prefix, ident.value);
+            prefix = builder_.MemberAccessor(source(), prefix, ident.value);
             continue;
         }
 
@@ -2205,7 +2196,9 @@
 //   | OR unary_expression (OR unary_expression)*
 //   | XOR unary_expression (XOR unary_expression)*
 Maybe<const ast::Expression*> Parser::bitwise_expression_post_unary_expression(
-    const ast::Expression* lhs) {
+    const ast::Expression* lhs,
+    const Source& lhs_source) {
+    MultiTokenSource source(this, lhs_source);
     auto& t = peek();
 
     std::optional<core::BinaryOp> op;
@@ -2234,7 +2227,7 @@
                                          std::string(t.to_name()) + " expression");
         }
 
-        lhs = create<ast::BinaryExpression>(t.source(), *op, lhs, rhs.value);
+        lhs = create<ast::BinaryExpression>(source(), *op, lhs, rhs.value);
 
         if (!match(t.type())) {
             return lhs;
@@ -2264,7 +2257,9 @@
 // multiplicative_expression.post.unary_expression
 //   : (multiplicative_operator unary_expression)*
 Expect<const ast::Expression*> Parser::expect_multiplicative_expression_post_unary_expression(
-    const ast::Expression* lhs) {
+    const ast::Expression* lhs,
+    const Source& lhs_source) {
+    MultiTokenSource source(this, lhs_source);
     while (continue_parsing()) {
         auto& t = peek();
 
@@ -2285,7 +2280,7 @@
                                          std::string(t.to_name()) + " expression");
         }
 
-        lhs = create<ast::BinaryExpression>(t.source(), op.value, lhs, rhs.value);
+        lhs = create<ast::BinaryExpression>(source(), op.value, lhs, rhs.value);
     }
     return Failure::kErrored;
 }
@@ -2320,7 +2315,9 @@
 // This is `( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*`
 // split apart.
 Expect<const ast::Expression*> Parser::expect_additive_expression_post_unary_expression(
-    const ast::Expression* lhs) {
+    const ast::Expression* lhs,
+    const Source& lhs_source) {
+    MultiTokenSource source(this, lhs_source);
     while (continue_parsing()) {
         auto& t = peek();
 
@@ -2341,14 +2338,14 @@
                                          std::string(t.to_name()) + " expression");
         }
 
-        // The multiplicative binds tigher, so pass the unary into that and build that expression
-        // before creating the additve expression.
-        auto rhs = expect_multiplicative_expression_post_unary_expression(unary.value);
+        // The multiplicative binds tighter, so pass the unary into that and build that expression
+        // before creating the additive expression.
+        auto rhs = expect_multiplicative_expression_post_unary_expression(unary.value, lhs_source);
         if (rhs.errored) {
             return Failure::kErrored;
         }
 
-        lhs = create<ast::BinaryExpression>(t.source(), op.value, lhs, rhs.value);
+        lhs = create<ast::BinaryExpression>(source(), op.value, lhs, rhs.value);
     }
     return Failure::kErrored;
 }
@@ -2359,18 +2356,22 @@
 // This is `( multiplicative_operator unary_expression )* ( additive_operator unary_expression (
 // multiplicative_operator unary_expression )* )*` split apart.
 Expect<const ast::Expression*> Parser::expect_math_expression_post_unary_expression(
-    const ast::Expression* lhs) {
-    auto rhs = expect_multiplicative_expression_post_unary_expression(lhs);
+    const ast::Expression* lhs,
+    const Source& lhs_source) {
+    MultiTokenSource source(this, lhs_source);
+
+    auto rhs = expect_multiplicative_expression_post_unary_expression(lhs, source);
     if (rhs.errored) {
         return Failure::kErrored;
     }
 
-    return expect_additive_expression_post_unary_expression(rhs.value);
+    return expect_additive_expression_post_unary_expression(rhs.value, source());
 }
 
 // shift_expression
 //   : unary_expression shift_expression.post.unary_expression
 Maybe<const ast::Expression*> Parser::shift_expression() {
+    MultiTokenSource source(this);
     auto lhs = unary_expression();
     if (lhs.errored) {
         return Failure::kErrored;
@@ -2378,7 +2379,7 @@
     if (!lhs.matched) {
         return Failure::kNoMatch;
     }
-    return expect_shift_expression_post_unary_expression(lhs.value);
+    return expect_shift_expression_post_unary_expression(lhs.value, source);
 }
 
 // shift_expression.post.unary_expression
@@ -2389,7 +2390,10 @@
 // Note, add the `math_expression.post.unary_expression` is added here to make
 // implementation simpler.
 Expect<const ast::Expression*> Parser::expect_shift_expression_post_unary_expression(
-    const ast::Expression* lhs) {
+    const ast::Expression* lhs,
+    const Source& lhs_source) {
+    MultiTokenSource source(this, lhs_source);
+
     auto& t = peek();
     if (match(Token::Type::kShiftLeft) || match(Token::Type::kShiftRight)) {
         std::string name;
@@ -2411,15 +2415,16 @@
             return add_error(rhs_start,
                              std::string("unable to parse right side of ") + name + " expression");
         }
-        return create<ast::BinaryExpression>(t.source(), *op, lhs, rhs.value);
+        return create<ast::BinaryExpression>(source(), *op, lhs, rhs.value);
     }
 
-    return expect_math_expression_post_unary_expression(lhs);
+    return expect_math_expression_post_unary_expression(lhs, source);
 }
 
 // relational_expression
 //   : unary_expression relational_expression.post.unary_expression
 Maybe<const ast::Expression*> Parser::relational_expression() {
+    MultiTokenSource source(this);
     auto lhs = unary_expression();
     if (lhs.errored) {
         return Failure::kErrored;
@@ -2427,7 +2432,7 @@
     if (!lhs.matched) {
         return Failure::kNoMatch;
     }
-    return expect_relational_expression_post_unary_expression(lhs.value);
+    return expect_relational_expression_post_unary_expression(lhs.value, source);
 }
 
 // relational_expression.post.unary_expression
@@ -2441,8 +2446,11 @@
 //
 // Note, a `shift_expression` element was added to simplify many of the right sides
 Expect<const ast::Expression*> Parser::expect_relational_expression_post_unary_expression(
-    const ast::Expression* lhs) {
-    auto lhs_result = expect_shift_expression_post_unary_expression(lhs);
+    const ast::Expression* lhs,
+    const Source& lhs_source) {
+    MultiTokenSource source(this, lhs_source);
+
+    auto lhs_result = expect_shift_expression_post_unary_expression(lhs, source);
     if (lhs_result.errored) {
         return Failure::kErrored;
     }
@@ -2486,7 +2494,7 @@
                                       std::string(tok_op.to_name()) + " expression");
     }
 
-    return create<ast::BinaryExpression>(tok_op.source(), *op, lhs, rhs.value);
+    return create<ast::BinaryExpression>(source(), *op, lhs, rhs.value);
 }
 
 Expect<const ast::Expression*> Parser::expect_expression(std::string_view use) {
@@ -2560,6 +2568,8 @@
 //
 // Note, a `relational_expression` element was added to simplify many of the right sides
 Maybe<const ast::Expression*> Parser::expression() {
+    MultiTokenSource source(this);
+    Source first_op;
     auto expr = [&]() -> Maybe<const ast::Expression*> {
         auto lhs = unary_expression();
         if (lhs.errored) {
@@ -2569,7 +2579,9 @@
             return Failure::kNoMatch;
         }
 
-        auto bitwise = bitwise_expression_post_unary_expression(lhs.value);
+        first_op = peek().source();
+
+        auto bitwise = bitwise_expression_post_unary_expression(lhs.value, source);
         if (bitwise.errored) {
             return Failure::kErrored;
         }
@@ -2577,7 +2589,7 @@
             return bitwise.value;
         }
 
-        auto relational = expect_relational_expression_post_unary_expression(lhs.value);
+        auto relational = expect_relational_expression_post_unary_expression(lhs.value, source);
         if (relational.errored) {
             return Failure::kErrored;
         }
@@ -2608,7 +2620,7 @@
                                                  std::string(t.to_name()) + " expression");
                 }
 
-                ret = create<ast::BinaryExpression>(t.source(), op, ret, rhs.value);
+                ret = create<ast::BinaryExpression>(source(), op, ret, rhs.value);
             }
         }
         return ret;
@@ -2620,9 +2632,9 @@
         // after this then it _must_ be a different one, and hence an error.
         if (auto* lhs = expr->As<ast::BinaryExpression>()) {
             if (auto& n = peek(); n.IsBinaryOperator()) {
-                auto source = Source::Combine(expr->source, n.source());
-                add_error(source, std::string("mixing '") + ast::Operator(lhs->op) + "' and '" +
-                                      std::string(n.to_name()) + "' requires parenthesis");
+                add_error(Source::Combine(first_op, n.source()),
+                          std::string("mixing '") + ast::Operator(lhs->op) + "' and '" +
+                              std::string(n.to_name()) + "' requires parenthesis");
                 return Failure::kErrored;
             }
         }
@@ -2656,10 +2668,11 @@
 // The `primary_expression component_or_swizzle_specifier ?` is moved out into a
 // `singular_expression`
 Maybe<const ast::Expression*> Parser::unary_expression() {
-    auto& t = peek();
+    MultiTokenSource source(this);
 
+    auto& t = peek();
     if (match(Token::Type::kPlusPlus) || match(Token::Type::kMinusMinus)) {
-        add_error(t.source(),
+        add_error(source,
                   "prefix increment and decrement operators are reserved for a "
                   "future WGSL version");
         return Failure::kErrored;
@@ -2700,7 +2713,7 @@
             peek(), "unable to parse right side of " + std::string(t.to_name()) + " expression");
     }
 
-    return create<ast::UnaryOpExpression>(t.source(), op, expr.value);
+    return create<ast::UnaryOpExpression>(source(), op, expr.value);
 }
 
 // compound_assignment_operator
@@ -3500,12 +3513,4 @@
     return result;
 }
 
-Parser::MultiTokenSource Parser::make_source_range() {
-    return MultiTokenSource(this);
-}
-
-Parser::MultiTokenSource Parser::make_source_range_from(const Source& start) {
-    return MultiTokenSource(this, start);
-}
-
 }  // namespace tint::wgsl::reader
diff --git a/src/tint/lang/wgsl/reader/parser/parser.h b/src/tint/lang/wgsl/reader/parser/parser.h
index 0e6c152..58f231e 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.h
+++ b/src/tint/lang/wgsl/reader/parser/parser.h
@@ -586,43 +586,55 @@
                                                           Token::Type terminator);
     /// Parses the `bitwise_expression.post.unary_expression` grammar element
     /// @param lhs the left side of the expression
+    /// @param lhs_source the source span for the left side of the expression
     /// @returns the parsed expression or nullptr
     Maybe<const ast::Expression*> bitwise_expression_post_unary_expression(
-        const ast::Expression* lhs);
+        const ast::Expression* lhs,
+        const Source& lhs_source);
     /// Parse the `multiplicative_operator` grammar element
     /// @returns the parsed operator if successful
     Maybe<core::BinaryOp> multiplicative_operator();
     /// Parses multiplicative elements
     /// @param lhs the left side of the expression
+    /// @param lhs_source the source span for the left side of the expression
     /// @returns the parsed expression or `lhs` if no match
     Expect<const ast::Expression*> expect_multiplicative_expression_post_unary_expression(
-        const ast::Expression* lhs);
+        const ast::Expression* lhs,
+        const Source& lhs_source);
     /// Parses additive elements
     /// @param lhs the left side of the expression
+    /// @param lhs_source the source span for the left side of the expression
     /// @returns the parsed expression or `lhs` if no match
     Expect<const ast::Expression*> expect_additive_expression_post_unary_expression(
-        const ast::Expression* lhs);
+        const ast::Expression* lhs,
+        const Source& lhs_source);
     /// Parses math elements
     /// @param lhs the left side of the expression
+    /// @param lhs_source the source span for the left side of the expression
     /// @returns the parsed expression or `lhs` if no match
     Expect<const ast::Expression*> expect_math_expression_post_unary_expression(
-        const ast::Expression* lhs);
+        const ast::Expression* lhs,
+        const Source& lhs_source);
     /// Parses a `unary_expression shift.post.unary_expression`
     /// @returns the parsed expression or nullptr
     Maybe<const ast::Expression*> shift_expression();
     /// Parses a `shift_expression.post.unary_expression` grammar element
     /// @param lhs the left side of the expression
+    /// @param lhs_source the source span for the left side of the expression
     /// @returns the parsed expression or `lhs` if no match
     Expect<const ast::Expression*> expect_shift_expression_post_unary_expression(
-        const ast::Expression* lhs);
+        const ast::Expression* lhs,
+        const Source& lhs_source);
     /// Parses a `unary_expression relational_expression.post.unary_expression`
     /// @returns the parsed expression or nullptr
     Maybe<const ast::Expression*> relational_expression();
     /// Parses a `relational_expression.post.unary_expression` grammar element
     /// @param lhs the left side of the expression
+    /// @param lhs_source the source span for the left side of the expression
     /// @returns the parsed expression or `lhs` if no match
     Expect<const ast::Expression*> expect_relational_expression_post_unary_expression(
-        const ast::Expression* lhs);
+        const ast::Expression* lhs,
+        const Source& lhs_source);
     /// Parse the `additive_operator` grammar element
     /// @returns the parsed operator if successful
     Maybe<core::BinaryOp> additive_operator();
@@ -881,8 +893,6 @@
     Maybe<const ast::Statement*> for_header_continuing();
 
     class MultiTokenSource;
-    MultiTokenSource make_source_range();
-    MultiTokenSource make_source_range_from(const Source& start);
 
     /// Creates a new `ast::Node` owned by the Module. When the Module is
     /// destructed, the `ast::Node` will also be destructed.
diff --git a/src/tint/lang/wgsl/reader/parser/relational_expression_test.cc b/src/tint/lang/wgsl/reader/parser/relational_expression_test.cc
index e2122ca..97b0d91 100644
--- a/src/tint/lang/wgsl/reader/parser/relational_expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/relational_expression_test.cc
@@ -33,15 +33,15 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_Parses_LessThan) {
     auto p = parser("a < true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 4u);
+    EXPECT_EQ(e->source.range.end.column, 9u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -58,15 +58,15 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_Parses_GreaterThan) {
     auto p = parser("a > true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 4u);
+    EXPECT_EQ(e->source.range.end.column, 9u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -83,15 +83,15 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_Parses_LessThanEqual) {
     auto p = parser("a <= true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -108,15 +108,15 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_Parses_GreaterThanEqual) {
     auto p = parser("a >= true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -133,15 +133,15 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_Parses_Equal) {
     auto p = parser("a == true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -158,15 +158,15 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_Parses_NotEqual) {
     auto p = parser("a != true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -183,7 +183,7 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_InvalidRHS) {
     auto p = parser("true < if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     ASSERT_TRUE(p->has_error());
     EXPECT_EQ(e.value, nullptr);
     EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression");
@@ -192,7 +192,7 @@
 TEST_F(WGSLParserTest, RelationalExpression_PostUnary_NoMatch_ReturnsLHS) {
     auto p = parser("a true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_relational_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_relational_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -247,9 +247,9 @@
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -272,9 +272,9 @@
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
diff --git a/src/tint/lang/wgsl/reader/parser/shift_expression_test.cc b/src/tint/lang/wgsl/reader/parser/shift_expression_test.cc
index 77ec7db..011b131 100644
--- a/src/tint/lang/wgsl/reader/parser/shift_expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/shift_expression_test.cc
@@ -33,15 +33,15 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_Parses_ShiftLeft) {
     auto p = parser("a << true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -58,15 +58,15 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_Parses_ShiftRight) {
     auto p = parser("a >> true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
 
     EXPECT_EQ(e->source.range.begin.line, 1u);
-    EXPECT_EQ(e->source.range.begin.column, 3u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
     EXPECT_EQ(e->source.range.end.line, 1u);
-    EXPECT_EQ(e->source.range.end.column, 5u);
+    EXPECT_EQ(e->source.range.end.column, 10u);
 
     ASSERT_TRUE(e->Is<ast::BinaryExpression>());
     auto* rel = e->As<ast::BinaryExpression>();
@@ -83,7 +83,7 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_Parses_Additive) {
     auto p = parser("a + b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -104,7 +104,7 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_Parses_Multiplicative) {
     auto p = parser("a * b");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
@@ -125,7 +125,7 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_InvalidSpaceLeft) {
     auto p = parser("a < < true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     ASSERT_NE(e.value, nullptr);
     EXPECT_FALSE(e.value->Is<ast::BinaryExpression>());
@@ -134,7 +134,7 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_InvalidSpaceRight) {
     auto p = parser("a > > true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     ASSERT_NE(e.value, nullptr);
     EXPECT_FALSE(e.value->Is<ast::BinaryExpression>());
@@ -143,7 +143,7 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_InvalidRHS) {
     auto p = parser("a << if (a) {}");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_TRUE(e.errored);
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(e.value, nullptr);
@@ -153,7 +153,7 @@
 TEST_F(WGSLParserTest, ShiftExpression_PostUnary_NoOr_ReturnsLHS) {
     auto p = parser("a true");
     auto lhs = p->unary_expression();
-    auto e = p->expect_shift_expression_post_unary_expression(lhs.value);
+    auto e = p->expect_shift_expression_post_unary_expression(lhs.value, lhs->source);
     EXPECT_FALSE(e.errored);
     EXPECT_FALSE(p->has_error()) << p->error();
     ASSERT_NE(e.value, nullptr);
diff --git a/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc b/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc
index 50b7908..f4169ac 100644
--- a/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc
@@ -233,7 +233,11 @@
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
 
-    EXPECT_EQ(p->error(), "1:9: mixing '+' and '<<' requires parenthesis");
+    EXPECT_EQ(p->builder().Diagnostics().str(),
+              R"(test.wgsl:1:9 error: mixing '+' and '<<' requires parenthesis
+align(4 + 5 << 6)
+        ^^^^^^
+)");
 }
 
 TEST_F(WGSLParserTest, Attribute_Index) {
diff --git a/src/tint/lang/wgsl/resolver/uniformity_test.cc b/src/tint/lang/wgsl/resolver/uniformity_test.cc
index 85f6c6f..cbab7db 100644
--- a/src/tint/lang/wgsl/resolver/uniformity_test.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity_test.cc
@@ -2543,9 +2543,9 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:34 note: control flow depends on possibly non-uniform value
+test:7:7 note: control flow depends on possibly non-uniform value
   if ((non_uniform_global == 42) && false) {
-                                 ^^
+      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 test:7:8 note: reading from read_write storage buffer 'non_uniform_global' may result in a non-uniform value
   if ((non_uniform_global == 42) && false) {
@@ -2601,9 +2601,9 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:34 note: control flow depends on possibly non-uniform value
+test:7:7 note: control flow depends on possibly non-uniform value
   if ((non_uniform_global == 42) || true) {
-                                 ^^
+      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 test:7:8 note: reading from read_write storage buffer 'non_uniform_global' may result in a non-uniform value
   if ((non_uniform_global == 42) || true) {
@@ -3750,7 +3750,7 @@
 
 test:12:7 note: possibly non-uniform value passed via pointer here
   bar(&v);
-      ^
+      ^^
 
 test:11:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = non_uniform;
@@ -3885,7 +3885,7 @@
 
 test:13:7 note: possibly non-uniform value passed via pointer here
   bar(&v);
-      ^
+      ^^
 
 test:12:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = non_uniform;
@@ -3926,7 +3926,7 @@
 
 test:12:7 note: possibly non-uniform value passed via pointer here
   bar(&v);
-      ^
+      ^^
 
 test:11:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = non_uniform;
@@ -4431,7 +4431,7 @@
 
 test:10:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
-      ^
+      ^^
 )");
 }
 
@@ -4695,7 +4695,7 @@
 
 test:16:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
-      ^
+      ^^
 )");
 }
 
@@ -4732,7 +4732,7 @@
 
 test:14:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
-      ^
+      ^^
 )");
 }
 
@@ -4769,7 +4769,7 @@
 
 test:14:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
-      ^
+      ^^
 )");
 }
 
@@ -4814,7 +4814,7 @@
 
 test:22:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
-      ^
+      ^^
 )");
 }
 
@@ -4853,7 +4853,7 @@
 
 test:16:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
-      ^
+      ^^
 )");
 }
 
@@ -5156,7 +5156,7 @@
 
 test:12:11 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&a, &b);
-          ^
+          ^^
 )");
 }
 
@@ -5249,7 +5249,7 @@
 
 test:12:11 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&a, &b);
-          ^
+          ^^
 )");
 }
 
@@ -8058,7 +8058,7 @@
 
 test:15:9 note: possibly non-uniform value passed via pointer here
   v[bar(&f)] += 1;
-        ^
+        ^^
 
 test:14:11 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
   var f = rw;
@@ -8134,7 +8134,7 @@
 
 test:15:9 note: possibly non-uniform value passed via pointer here
   v[bar(&f)]++;
-        ^
+        ^^
 
 test:14:11 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
   var f = rw;
@@ -8207,11 +8207,11 @@
 
 test:19:22 note: possibly non-uniform value passed via pointer here
   arr[a(&i)] = arr[b(&i)];
-                     ^
+                     ^^
 
 test:19:9 note: contents of pointer may become non-uniform after calling 'a'
   arr[a(&i)] = arr[b(&i)];
-        ^
+        ^^
 )");
 }
 
@@ -8444,11 +8444,11 @@
 
 test:19:23 note: possibly non-uniform value passed via pointer here
   arr[a(&i)] += arr[b(&i)];
-                      ^
+                      ^^
 
 test:19:9 note: contents of pointer may become non-uniform after calling 'a'
   arr[a(&i)] += arr[b(&i)];
-        ^
+        ^^
 )");
 }
 
@@ -8582,9 +8582,9 @@
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
                                         ^^^^^^^^^
 
-test:5:37 note: control flow depends on possibly non-uniform value
+test:5:11 note: control flow depends on possibly non-uniform value
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
-                                    ^^
+          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 test:5:12 note: reading from read_write storage buffer 'non_uniform_global' may result in a non-uniform value
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
@@ -8903,7 +8903,7 @@
     EXPECT_EQ(error_,
               R"(test:8:28 error: possibly non-uniform value passed here
   if (workgroupUniformLoad(&data[idx]) > 0) {
-                           ^
+                           ^^^^^^^^^^
 
 test:8:34 note: builtin 'idx' of 'main' may be non-uniform
   if (workgroupUniformLoad(&data[idx]) > 0) {
@@ -8943,7 +8943,7 @@
 
 test:14:11 note: possibly non-uniform value passed here
   if (foo(&data[idx]) > 0) {
-          ^
+          ^^^^^^^^^^
 
 test:14:17 note: builtin 'idx' of 'main' may be non-uniform
   if (foo(&data[idx]) > 0) {
diff --git a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.dxc.hlsl
index 2da3980..d8caf58 100644
--- a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.dxc.hlsl
+++ b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.dxc.hlsl
@@ -2,9 +2,9 @@
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
                           ^^^^^^^^^
 
-<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:24 note: control flow depends on possibly non-uniform value
+<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: control flow depends on possibly non-uniform value
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
-                       ^^
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 <dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: user-defined input 'x' of 'main' may be non-uniform
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
diff --git a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.fxc.hlsl
index 2da3980..d8caf58 100644
--- a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.fxc.hlsl
+++ b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.fxc.hlsl
@@ -2,9 +2,9 @@
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
                           ^^^^^^^^^
 
-<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:24 note: control flow depends on possibly non-uniform value
+<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: control flow depends on possibly non-uniform value
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
-                       ^^
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 <dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: user-defined input 'x' of 'main' may be non-uniform
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
diff --git a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.glsl
index bb50f5f..19ab2cb 100644
--- a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.glsl
+++ b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.glsl
@@ -2,9 +2,9 @@
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
                           ^^^^^^^^^
 
-<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:24 note: control flow depends on possibly non-uniform value
+<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: control flow depends on possibly non-uniform value
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
-                       ^^
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 <dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: user-defined input 'x' of 'main' may be non-uniform
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
diff --git a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.msl
index cd78f8c..a0e4688 100644
--- a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.msl
+++ b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.msl
@@ -2,9 +2,9 @@
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
                           ^^^^^^^^^
 
-<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:24 note: control flow depends on possibly non-uniform value
+<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: control flow depends on possibly non-uniform value
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
-                       ^^
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 <dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: user-defined input 'x' of 'main' may be non-uniform
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
diff --git a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.spvasm
index e11f582..9de664b 100644
--- a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.spvasm
+++ b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.spvasm
@@ -2,9 +2,9 @@
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
                           ^^^^^^^^^
 
-<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:24 note: control flow depends on possibly non-uniform value
+<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: control flow depends on possibly non-uniform value
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
-                       ^^
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 <dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: user-defined input 'x' of 'main' may be non-uniform
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
diff --git a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.wgsl
index 428a4c1..a4c93ee 100644
--- a/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.wgsl
+++ b/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl.expected.wgsl
@@ -2,9 +2,9 @@
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
                           ^^^^^^^^^
 
-<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:24 note: control flow depends on possibly non-uniform value
+<dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: control flow depends on possibly non-uniform value
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {
-                       ^^
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 <dawn>/test/tint/diagnostic_filtering/switch_statement_attribute.wgsl:7:15 note: user-defined input 'x' of 'main' may be non-uniform
   switch (i32(x == 0.0 && dpdx(1.0) == 0.0)) {