[tint][wgsl] Migrate more resolver diagnostics over to StyledText

Change-Id: I1ab81074215171650227a77d51b4362e9c1b3e4c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/176040
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index dd96db5..b888362 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -205,9 +205,9 @@
     }
     out << "(";
     PrintTypeList(out, args);
-    out << ")" << style::Plain;
+    out << ")";
 
-    return out;
+    return out << style::Plain;
 }
 
 Result<Overload, StyledText> MatchIntrinsic(Context& context,
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index e0feca2..3fd6ae4 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -72,6 +72,7 @@
 #include "src/tint/utils/containers/transform.h"
 #include "src/tint/utils/macros/scoped_assignment.h"
 #include "src/tint/utils/rtti/switch.h"
+#include "src/tint/utils/text/text_style.h"
 
 /// If set to 1 then the Tint will dump the IR when validating.
 #define TINT_DUMP_IR_WHEN_VALIDATING 0
@@ -307,8 +308,8 @@
 
     for (auto& func : mod_.functions) {
         if (!all_functions_.Add(func.Get())) {
-            AddError(Source{}) << "function '" << Name(func.Get())
-                               << "' added to module multiple times";
+            AddError(Source{}) << "function " << style::Function << Name(func.Get()) << style::Plain
+                               << " added to module multiple times";
         }
     }
 
diff --git a/src/tint/lang/wgsl/resolver/address_space_layout_validation_test.cc b/src/tint/lang/wgsl/resolver/address_space_layout_validation_test.cc
index a1bfe87..4fe832a 100644
--- a/src/tint/lang/wgsl/resolver/address_space_layout_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/address_space_layout_validation_test.cc
@@ -59,7 +59,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: the offset of a struct member of type 'f32' in address space 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
+        R"(34:56 error: the offset of a struct member of type 'f32' in address space 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting '@align(4)' on this member
 12:34 note: see layout of struct:
 /*           align(4) size(12) */ struct S {
 /* offset(0) align(4) size( 5) */   a : f32;
@@ -120,7 +120,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: the offset of a struct member of type 'Inner' in address space 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
+        R"(56:78 error: the offset of a struct member of type 'Inner' in address space 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting '@align(16)' on this member
 34:56 note: see layout of struct:
 /*           align(4) size(8) */ struct Outer {
 /* offset(0) align(4) size(4) */   scalar : f32;
@@ -189,7 +189,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in address space 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
+        R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in address space 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting '@align(16)' on this member
 12:34 note: see layout of struct:
 /*             align(4) size(164) */ struct Outer {
 /* offset(  0) align(4) size(  4) */   scalar : f32;
@@ -254,7 +254,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 8 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
+        R"(78:90 error: 'uniform' storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 8 bytes between 'inner' and 'scalar'. Consider setting '@align(16)' on this member
 34:56 note: see layout of struct:
 /*            align(4) size(12) */ struct Outer {
 /* offset( 0) align(1) size( 5) */   inner : Inner;
@@ -306,7 +306,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
+        R"(78:90 error: 'uniform' storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting '@align(16)' on this member
 34:56 note: see layout of struct:
 /*            align(4) size(24) */ struct Outer {
 /* offset( 0) align(4) size(20) */   inner : Inner;
@@ -424,7 +424,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
+        R"(34:56 error: 'uniform' storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
 12:34 note: see layout of struct:
 /*            align(4) size(44) */ struct Outer {
 /* offset( 0) align(4) size(40) */   inner : array<f32, 10>;
@@ -458,7 +458,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'vec2<f32>' has a stride of 8 bytes. Consider using a vec4 instead.
+        R"(34:56 error: 'uniform' storage requires that array elements are aligned to 16 bytes, but array element of type 'vec2<f32>' has a stride of 8 bytes. Consider using a vec4 instead.
 12:34 note: see layout of struct:
 /*            align(8) size(88) */ struct Outer {
 /* offset( 0) align(8) size(80) */   inner : array<vec2<f32>, 10>;
@@ -501,7 +501,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'ArrayElem' has a stride of 8 bytes. Consider using the @size attribute on the last struct member.
+        R"(34:56 error: 'uniform' storage requires that array elements are aligned to 16 bytes, but array element of type 'ArrayElem' has a stride of 8 bytes. Consider using the '@size' attribute on the last struct member.
 12:34 note: see layout of struct:
 /*            align(4) size(84) */ struct Outer {
 /* offset( 0) align(4) size(80) */   inner : array<ArrayElem, 10>;
@@ -519,7 +519,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(78:90 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.)");
+        R"(78:90 error: 'uniform' storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.)");
 }
 
 TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_NestedArray) {
@@ -541,7 +541,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
+        R"(34:56 error: 'uniform' storage requires that array elements are aligned to 16 bytes, but array element of type 'f32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
 12:34 note: see layout of struct:
 /*            align(4) size(64) */ struct Outer {
 /* offset( 0) align(4) size(64) */   inner : array<array<f32, 4>, 4>;
@@ -591,7 +591,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(34:56 error: the offset of a struct member of type 'f32' in address space 'push_constant' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
+        R"(34:56 error: the offset of a struct member of type 'f32' in address space 'push_constant' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting '@align(4)' on this member
 12:34 note: see layout of struct:
 /*           align(4) size(12) */ struct S {
 /* offset(0) align(4) size( 5) */   a : f32;
diff --git a/src/tint/lang/wgsl/resolver/address_space_validation_test.cc b/src/tint/lang/wgsl/resolver/address_space_validation_test.cc
index f8c2f27b..aacf005 100644
--- a/src/tint/lang/wgsl/resolver/address_space_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/address_space_validation_test.cc
@@ -171,7 +171,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -183,7 +183,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 note: while instantiating ptr<storage, bool, read>)");
 }
 
@@ -198,7 +198,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -212,7 +212,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 note: while instantiating ptr<storage, bool, read>)");
 }
 
@@ -225,7 +225,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'ptr<private, f32, read_write>' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'ptr<private, f32, read_write>' cannot be used in address space 'storage' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -557,7 +557,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: uniform storage requires that array elements are aligned to 16 bytes, but array element of type 'i32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
+        R"(12:34 error: 'uniform' storage requires that array elements are aligned to 16 bytes, but array element of type 'i32' has a stride of 4 bytes. Consider using a vector or struct as the element type instead.
 note: see layout of struct:
 /*           align(4) size(4) */ struct S {
 /* offset(0) align(4) size(4) */   m : array<i32>;
@@ -574,7 +574,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -586,7 +586,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
 56:78 note: while instantiating ptr<uniform, bool, read>)");
 }
 
@@ -601,7 +601,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -615,7 +615,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
 56:78 note: while instantiating ptr<uniform, bool, read>)");
 }
 
@@ -628,7 +628,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'ptr<private, f32, read_write>' cannot be used in address space 'uniform' as it is non-host-shareable
+        R"(12:34 error: type 'ptr<private, f32, read_write>' cannot be used in address space 'uniform' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -852,7 +852,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'push_constant' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'push_constant' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
@@ -865,7 +865,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'push_constant' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'push_constant' as it is non-host-shareable
 note: while instantiating ptr<push_constant, bool, read_write>)");
 }
 
@@ -879,7 +879,7 @@
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "error: using f16 types in 'push_constant' address space is not implemented yet");
+              "error: using 'f16' in 'push_constant' address space is not implemented yet");
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_PushConstantF16) {
@@ -892,7 +892,7 @@
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "error: using f16 types in 'push_constant' address space is not implemented yet");
+              "error: using 'f16' in 'push_constant' address space is not implemented yet");
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_PushConstantPointer) {
@@ -905,7 +905,7 @@
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'ptr<private, f32, read_write>' cannot be used in address space 'push_constant' as it is non-host-shareable
+        R"(12:34 error: type 'ptr<private, f32, read_write>' cannot be used in address space 'push_constant' as it is non-host-shareable
 56:78 note: while instantiating 'var' g)");
 }
 
diff --git a/src/tint/lang/wgsl/resolver/assignment_validation_test.cc b/src/tint/lang/wgsl/resolver/assignment_validation_test.cc
index 1df19ab..61eb5a5 100644
--- a/src/tint/lang/wgsl/resolver/assignment_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/assignment_validation_test.cc
@@ -365,10 +365,9 @@
     WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: cannot assign 'S' to '_'. "
-              "'_' can only be assigned a constructible, pointer, texture or "
-              "sampler type");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: cannot assign 'S' to '_'. '_' can only be assigned a constructible, pointer, texture or sampler type)");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignToPhony_DynamicArray_Fail) {
@@ -387,10 +386,9 @@
     WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: cannot assign 'array<i32>' to '_'. "
-              "'_' can only be assigned a constructible, pointer, texture or sampler "
-              "type");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: cannot assign 'array<i32>' to '_'. '_' can only be assigned a constructible, pointer, texture or sampler type)");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignToPhony_Pass) {
diff --git a/src/tint/lang/wgsl/resolver/atomics_validation_test.cc b/src/tint/lang/wgsl/resolver/atomics_validation_test.cc
index 890e076..bd8cf06 100644
--- a/src/tint/lang/wgsl/resolver/atomics_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/atomics_validation_test.cc
@@ -74,7 +74,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: atomic variables must have <storage> or <workgroup> address space");
+              "12:34 error: 'atomic' variables must have 'storage' or 'workgroup' address space");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Array) {
@@ -82,7 +82,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: atomic variables must have <storage> or <workgroup> address space");
+              "12:34 error: 'atomic' variables must have 'storage' or 'workgroup' address space");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Struct) {
@@ -91,8 +91,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "56:78 error: atomic variables must have <storage> or <workgroup> address space\n"
-              "note: atomic sub-type of 's' is declared here");
+              R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space
+note: atomic sub-type of 's' is declared here)");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_StructOfStruct) {
@@ -106,8 +106,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "56:78 error: atomic variables must have <storage> or <workgroup> address space\n"
-              "note: atomic sub-type of 'Outer' is declared here");
+              R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space
+note: atomic sub-type of 'Outer' is declared here)");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_StructOfStructOfArray) {
@@ -121,7 +121,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(56:78 error: atomic variables must have <storage> or <workgroup> address space
+              R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space
 12:34 note: atomic sub-type of 'Outer' is declared here)");
 }
 
@@ -134,8 +134,9 @@
     GlobalVar(Source{{56, 78}}, "v", ty.Of(atomic_array), core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "56:78 error: atomic variables must have <storage> or <workgroup> address space");
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space)");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_ArrayOfStruct) {
@@ -149,7 +150,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(56:78 error: atomic variables must have <storage> or <workgroup> address space
+              R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space
 12:34 note: atomic sub-type of 'array<S, 5>' is declared here)");
 }
 
@@ -166,7 +167,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(56:78 error: atomic variables must have <storage> or <workgroup> address space
+              R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space
 12:34 note: atomic sub-type of 'array<S, 5>' is declared here)");
 }
 
@@ -205,7 +206,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(56:78 error: atomic variables must have <storage> or <workgroup> address space
+              R"(56:78 error: 'atomic' variables must have 'storage' or 'workgroup' address space
 12:34 note: atomic sub-type of 'S0' is declared here)");
 }
 
@@ -217,7 +218,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: atomic variables in <storage> address space must have read_write access mode
+        R"(56:78 error: atomic variables in 'storage' address space must have 'read_write' access mode
 12:34 note: atomic sub-type of 's' is declared here)");
 }
 
@@ -229,7 +230,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: atomic variables in <storage> address space must have read_write access mode
+        R"(56:78 error: atomic variables in 'storage' address space must have 'read_write' access mode
 12:34 note: atomic sub-type of 's' is declared here)");
 }
 
@@ -246,7 +247,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: atomic variables in <storage> address space must have read_write access mode
+        R"(56:78 error: atomic variables in 'storage' address space must have 'read_write' access mode
 12:34 note: atomic sub-type of 'Outer' is declared here)");
 }
 
@@ -263,7 +264,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: atomic variables in <storage> address space must have read_write access mode
+        R"(56:78 error: atomic variables in 'storage' address space must have 'read_write' access mode
 12:34 note: atomic sub-type of 'Outer' is declared here)");
 }
 
@@ -304,7 +305,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: atomic variables in <storage> address space must have read_write access mode
+        R"(12:34 error: atomic variables in 'storage' address space must have 'read_write' access mode
 56:78 note: atomic sub-type of 'S0' is declared here)");
 }
 
diff --git a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
index 78a967d..a36e21f 100644
--- a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
@@ -136,23 +136,23 @@
 static std::vector<TestParams> OnlyDiagnosticValidFor(std::string thing) {
     return {TestParams{
                 {AttributeKind::kAlign},
-                "1:2 error: @align is not valid for " + thing,
+                "1:2 error: '@align' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kBinding},
-                "1:2 error: @binding is not valid for " + thing,
+                "1:2 error: '@binding' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kBlendSrc},
-                "1:2 error: @blend_src is not valid for " + thing,
+                "1:2 error: '@blend_src' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kBuiltinPosition},
-                "1:2 error: @builtin is not valid for " + thing,
+                "1:2 error: '@builtin' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kColor},
-                "1:2 error: @color is not valid for " + thing,
+                "1:2 error: '@color' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kDiagnostic},
@@ -160,51 +160,51 @@
             },
             TestParams{
                 {AttributeKind::kGroup},
-                "1:2 error: @group is not valid for " + thing,
+                "1:2 error: '@group' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kId},
-                "1:2 error: @id is not valid for " + thing,
+                "1:2 error: '@id' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kInterpolate},
-                "1:2 error: @interpolate is not valid for " + thing,
+                "1:2 error: '@interpolate' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kInvariant},
-                "1:2 error: @invariant is not valid for " + thing,
+                "1:2 error: '@invariant' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kLocation},
-                "1:2 error: @location is not valid for " + thing,
+                "1:2 error: '@location' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kMustUse},
-                "1:2 error: @must_use is not valid for " + thing,
+                "1:2 error: '@must_use' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kOffset},
-                "1:2 error: @offset is not valid for " + thing,
+                "1:2 error: '@offset' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kSize},
-                "1:2 error: @size is not valid for " + thing,
+                "1:2 error: '@size' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kStageCompute},
-                "1:2 error: @stage is not valid for " + thing,
+                "1:2 error: '@stage' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kStride},
-                "1:2 error: @stride is not valid for " + thing,
+                "1:2 error: '@stride' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kWorkgroupSize},
-                "1:2 error: @workgroup_size is not valid for " + thing,
+                "1:2 error: '@workgroup_size' is not valid for " + thing,
             },
             TestParams{
                 {AttributeKind::kBinding, AttributeKind::kGroup},
-                "1:2 error: @binding is not valid for " + thing,
+                "1:2 error: '@binding' is not valid for " + thing,
             }};
 }
 
@@ -316,23 +316,23 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for functions)",
+            R"(1:2 error: '@align' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for functions)",
+            R"(1:2 error: '@binding' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for functions)",
+            R"(1:2 error: '@blend_src' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for functions)",
+            R"(1:2 error: '@builtin' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for functions)",
+            R"(1:2 error: '@color' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
@@ -340,39 +340,39 @@
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for functions)",
+            R"(1:2 error: '@group' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for functions)",
+            R"(1:2 error: '@id' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for functions)",
+            R"(1:2 error: '@interpolate' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for functions)",
+            R"(1:2 error: '@invariant' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for functions)",
+            R"(1:2 error: '@location' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use can only be applied to functions that return a value)",
+            R"(1:2 error: '@must_use' can only be applied to functions that return a value)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for functions)",
+            R"(1:2 error: '@offset' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for functions)",
+            R"(1:2 error: '@size' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(9:9 error: a compute shader must include 'workgroup_size' in its attributes)",
+            R"(9:9 error: a compute shader must include '@workgroup_size' in its attributes)",
         },
         TestParams{
             {AttributeKind::kStageCompute, AttributeKind::kWorkgroupSize},
@@ -380,11 +380,11 @@
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for functions)",
+            R"(1:2 error: '@stride' is not valid for functions)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is only valid for compute stages)",
+            R"(1:2 error: '@workgroup_size' is only valid for compute stages)",
         }));
 
 using NonVoidFunctionAttributeTest = TestWithParams;
@@ -400,23 +400,23 @@
                          testing::Values(
                              TestParams{
                                  {AttributeKind::kAlign},
-                                 R"(1:2 error: @align is not valid for functions)",
+                                 R"(1:2 error: '@align' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kBinding},
-                                 R"(1:2 error: @binding is not valid for functions)",
+                                 R"(1:2 error: '@binding' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kBlendSrc},
-                                 R"(1:2 error: @blend_src is not valid for functions)",
+                                 R"(1:2 error: '@blend_src' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kBuiltinPosition},
-                                 R"(1:2 error: @builtin is not valid for functions)",
+                                 R"(1:2 error: '@builtin' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kColor},
-                                 R"(1:2 error: @color is not valid for functions)",
+                                 R"(1:2 error: '@color' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kDiagnostic},
@@ -424,23 +424,23 @@
                              },
                              TestParams{
                                  {AttributeKind::kGroup},
-                                 R"(1:2 error: @group is not valid for functions)",
+                                 R"(1:2 error: '@group' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kId},
-                                 R"(1:2 error: @id is not valid for functions)",
+                                 R"(1:2 error: '@id' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kInterpolate},
-                                 R"(1:2 error: @interpolate is not valid for functions)",
+                                 R"(1:2 error: '@interpolate' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kInvariant},
-                                 R"(1:2 error: @invariant is not valid for functions)",
+                                 R"(1:2 error: '@invariant' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kLocation},
-                                 R"(1:2 error: @location is not valid for functions)",
+                                 R"(1:2 error: '@location' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kMustUse},
@@ -448,11 +448,11 @@
                              },
                              TestParams{
                                  {AttributeKind::kOffset},
-                                 R"(1:2 error: @offset is not valid for functions)",
+                                 R"(1:2 error: '@offset' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kSize},
-                                 R"(1:2 error: @size is not valid for functions)",
+                                 R"(1:2 error: '@size' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kStageCompute},
@@ -464,11 +464,11 @@
                              },
                              TestParams{
                                  {AttributeKind::kStride},
-                                 R"(1:2 error: @stride is not valid for functions)",
+                                 R"(1:2 error: '@stride' is not valid for functions)",
                              },
                              TestParams{
                                  {AttributeKind::kWorkgroupSize},
-                                 R"(1:2 error: @workgroup_size is only valid for compute stages)",
+                                 R"(1:2 error: '@workgroup_size' is only valid for compute stages)",
                              }));
 }  // namespace FunctionTests
 
@@ -491,71 +491,71 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for function parameters)",
+            R"(1:2 error: '@align' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for function parameters)",
+            R"(1:2 error: '@binding' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for function parameters)",
+            R"(1:2 error: '@blend_src' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for non-entry point function parameters)",
+            R"(1:2 error: '@builtin' is not valid for non-entry point function parameters)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for function parameters)",
+            R"(1:2 error: '@color' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for function parameters)",
+            R"(1:2 error: '@diagnostic' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for function parameters)",
+            R"(1:2 error: '@group' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for function parameters)",
+            R"(1:2 error: '@id' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for non-entry point function parameters)",
+            R"(1:2 error: '@interpolate' is not valid for non-entry point function parameters)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for non-entry point function parameters)",
+            R"(1:2 error: '@invariant' is not valid for non-entry point function parameters)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for non-entry point function parameters)",
+            R"(1:2 error: '@location' is not valid for non-entry point function parameters)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for function parameters)",
+            R"(1:2 error: '@must_use' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for function parameters)",
+            R"(1:2 error: '@offset' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for function parameters)",
+            R"(1:2 error: '@size' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for function parameters)",
+            R"(1:2 error: '@stage' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for function parameters)",
+            R"(1:2 error: '@stride' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for function parameters)",
+            R"(1:2 error: '@workgroup_size' is not valid for function parameters)",
         }));
 
 using FunctionReturnTypeAttributeTest = TestWithParams;
@@ -576,71 +576,71 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for non-entry point function return types)",
+            R"(1:2 error: '@align' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for non-entry point function return types)",
+            R"(1:2 error: '@binding' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for non-entry point function return types)",
+            R"(1:2 error: '@blend_src' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for non-entry point function return types)",
+            R"(1:2 error: '@builtin' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for non-entry point function return types)",
+            R"(1:2 error: '@color' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for non-entry point function return types)",
+            R"(1:2 error: '@diagnostic' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for non-entry point function return types)",
+            R"(1:2 error: '@group' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for non-entry point function return types)",
+            R"(1:2 error: '@id' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for non-entry point function return types)",
+            R"(1:2 error: '@interpolate' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for non-entry point function return types)",
+            R"(1:2 error: '@invariant' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for non-entry point function return types)",
+            R"(1:2 error: '@location' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for non-entry point function return types)",
+            R"(1:2 error: '@must_use' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for non-entry point function return types)",
+            R"(1:2 error: '@offset' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for non-entry point function return types)",
+            R"(1:2 error: '@size' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for non-entry point function return types)",
+            R"(1:2 error: '@stage' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for non-entry point function return types)",
+            R"(1:2 error: '@stride' is not valid for non-entry point function return types)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for non-entry point function return types)",
+            R"(1:2 error: '@workgroup_size' is not valid for non-entry point function return types)",
         }));
 }  // namespace FunctionInputAndOutputTests
 
@@ -666,71 +666,71 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for function parameters)",
+            R"(1:2 error: '@align' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for function parameters)",
+            R"(1:2 error: '@binding' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for function parameters)",
+            R"(1:2 error: '@blend_src' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin(position) cannot be used for compute shader input)",
+            R"(1:2 error: '@builtin(position)' cannot be used for compute shader input)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color can only be used for fragment shader input)",
+            R"(1:2 error: '@color' can only be used for fragment shader input)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for function parameters)",
+            R"(1:2 error: '@diagnostic' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for function parameters)",
+            R"(1:2 error: '@group' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for function parameters)",
+            R"(1:2 error: '@id' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate cannot be used by compute shaders)",
+            R"(1:2 error: '@interpolate' cannot be used by compute shaders)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant cannot be used by compute shaders)",
+            R"(1:2 error: '@invariant' cannot be used by compute shaders)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location cannot be used by compute shaders)",
+            R"(1:2 error: '@location' cannot be used by compute shaders)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for function parameters)",
+            R"(1:2 error: '@must_use' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for function parameters)",
+            R"(1:2 error: '@offset' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for function parameters)",
+            R"(1:2 error: '@size' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for function parameters)",
+            R"(1:2 error: '@stage' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for function parameters)",
+            R"(1:2 error: '@stride' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for function parameters)",
+            R"(1:2 error: '@workgroup_size' is not valid for function parameters)",
         }));
 
 using FragmentShaderParameterAttributeTest = TestWithParams;
@@ -750,15 +750,15 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for function parameters)",
+            R"(1:2 error: '@align' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for function parameters)",
+            R"(1:2 error: '@binding' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for function parameters)",
+            R"(1:2 error: '@blend_src' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
@@ -771,19 +771,19 @@
         TestParams{
             {AttributeKind::kColor, AttributeKind::kLocation},
             R"(3:4 error: multiple entry point IO attributes
-1:2 note: previously consumed @color)",
+1:2 note: previously consumed '@color')",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for function parameters)",
+            R"(1:2 error: '@diagnostic' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for function parameters)",
+            R"(1:2 error: '@group' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for function parameters)",
+            R"(1:2 error: '@id' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
@@ -791,7 +791,7 @@
         },
         TestParams{
             {AttributeKind::kInterpolate, AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @interpolate can only be used with @location)",
+            R"(1:2 error: '@interpolate' can only be used with '@location')",
         },
         TestParams{
             {AttributeKind::kInterpolate, AttributeKind::kLocation},
@@ -811,27 +811,27 @@
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for function parameters)",
+            R"(1:2 error: '@must_use' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for function parameters)",
+            R"(1:2 error: '@offset' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for function parameters)",
+            R"(1:2 error: '@size' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for function parameters)",
+            R"(1:2 error: '@stage' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for function parameters)",
+            R"(1:2 error: '@stride' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for function parameters)",
+            R"(1:2 error: '@workgroup_size' is not valid for function parameters)",
         }));
 
 using VertexShaderParameterAttributeTest = TestWithParams;
@@ -858,35 +858,35 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for function parameters)",
+            R"(1:2 error: '@align' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for function parameters)",
+            R"(1:2 error: '@binding' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for function parameters)",
+            R"(1:2 error: '@blend_src' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin(position) cannot be used for vertex shader input)",
+            R"(1:2 error: '@builtin(position)' cannot be used for vertex shader input)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color can only be used for fragment shader input)",
+            R"(1:2 error: '@color' can only be used for fragment shader input)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for function parameters)",
+            R"(1:2 error: '@diagnostic' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for function parameters)",
+            R"(1:2 error: '@group' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for function parameters)",
+            R"(1:2 error: '@id' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
@@ -898,7 +898,7 @@
         },
         TestParams{
             {AttributeKind::kInterpolate, AttributeKind::kBuiltinPosition},
-            R"(3:4 error: @builtin(position) cannot be used for vertex shader input)",
+            R"(3:4 error: '@builtin(position)' cannot be used for vertex shader input)",
         },
         TestParams{
             {AttributeKind::kInvariant},
@@ -906,11 +906,11 @@
         },
         TestParams{
             {AttributeKind::kInvariant, AttributeKind::kLocation},
-            R"(1:2 error: @invariant must be applied to a position builtin)",
+            R"(1:2 error: '@invariant' must be applied to a '@builtin(position)')",
         },
         TestParams{
             {AttributeKind::kInvariant, AttributeKind::kBuiltinPosition},
-            R"(3:4 error: @builtin(position) cannot be used for vertex shader input)",
+            R"(3:4 error: '@builtin(position)' cannot be used for vertex shader input)",
         },
         TestParams{
             {AttributeKind::kLocation},
@@ -918,27 +918,27 @@
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for function parameters)",
+            R"(1:2 error: '@must_use' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for function parameters)",
+            R"(1:2 error: '@offset' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for function parameters)",
+            R"(1:2 error: '@size' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for function parameters)",
+            R"(1:2 error: '@stage' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for function parameters)",
+            R"(1:2 error: '@stride' is not valid for function parameters)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for function parameters)",
+            R"(1:2 error: '@workgroup_size' is not valid for function parameters)",
         }));
 
 using ComputeShaderReturnTypeAttributeTest = TestWithParams;
@@ -963,71 +963,71 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for entry point return types)",
+            R"(1:2 error: '@align' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for entry point return types)",
+            R"(1:2 error: '@binding' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src can only be used for fragment shader output)",
+            R"(1:2 error: '@blend_src' can only be used for fragment shader output)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin(position) cannot be used for compute shader output)",
+            R"(1:2 error: '@builtin(position)' cannot be used for compute shader output)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for entry point return types)",
+            R"(1:2 error: '@color' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for entry point return types)",
+            R"(1:2 error: '@diagnostic' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for entry point return types)",
+            R"(1:2 error: '@group' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for entry point return types)",
+            R"(1:2 error: '@id' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate cannot be used by compute shaders)",
+            R"(1:2 error: '@interpolate' cannot be used by compute shaders)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant cannot be used by compute shaders)",
+            R"(1:2 error: '@invariant' cannot be used by compute shaders)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location cannot be used by compute shaders)",
+            R"(1:2 error: '@location' cannot be used by compute shaders)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for entry point return types)",
+            R"(1:2 error: '@must_use' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for entry point return types)",
+            R"(1:2 error: '@offset' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for entry point return types)",
+            R"(1:2 error: '@size' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for entry point return types)",
+            R"(1:2 error: '@stage' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for entry point return types)",
+            R"(1:2 error: '@stride' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for entry point return types)",
+            R"(1:2 error: '@workgroup_size' is not valid for entry point return types)",
         }));
 
 using FragmentShaderReturnTypeAttributeTest = TestWithParams;
@@ -1049,11 +1049,11 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for entry point return types)",
+            R"(1:2 error: '@align' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for entry point return types)",
+            R"(1:2 error: '@binding' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
@@ -1065,23 +1065,23 @@
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin(position) cannot be used for fragment shader output)",
+            R"(1:2 error: '@builtin(position)' cannot be used for fragment shader output)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for entry point return types)",
+            R"(1:2 error: '@color' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for entry point return types)",
+            R"(1:2 error: '@diagnostic' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for entry point return types)",
+            R"(1:2 error: '@group' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for entry point return types)",
+            R"(1:2 error: '@id' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
@@ -1097,7 +1097,7 @@
         },
         TestParams{
             {AttributeKind::kInvariant, AttributeKind::kLocation},
-            R"(1:2 error: @invariant must be applied to a position builtin)",
+            R"(1:2 error: '@invariant' must be applied to a '@builtin(position)')",
         },
         TestParams{
             {AttributeKind::kLocation},
@@ -1105,31 +1105,31 @@
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for entry point return types)",
+            R"(1:2 error: '@must_use' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for entry point return types)",
+            R"(1:2 error: '@offset' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for entry point return types)",
+            R"(1:2 error: '@size' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for entry point return types)",
+            R"(1:2 error: '@stage' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for entry point return types)",
+            R"(1:2 error: '@stride' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for entry point return types)",
+            R"(1:2 error: '@workgroup_size' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBinding, AttributeKind::kGroup},
-            R"(1:2 error: @binding is not valid for entry point return types)",
+            R"(1:2 error: '@binding' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBlendSrc, AttributeKind::kLocation},
@@ -1161,15 +1161,15 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for entry point return types)",
+            R"(1:2 error: '@align' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for entry point return types)",
+            R"(1:2 error: '@binding' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src can only be used for fragment shader output)",
+            R"(1:2 error: '@blend_src' can only be used for fragment shader output)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
@@ -1177,23 +1177,23 @@
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for entry point return types)",
+            R"(1:2 error: '@color' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for entry point return types)",
+            R"(1:2 error: '@diagnostic' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for entry point return types)",
+            R"(1:2 error: '@group' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for entry point return types)",
+            R"(1:2 error: '@id' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate can only be used with @location)",
+            R"(1:2 error: '@interpolate' can only be used with '@location')",
         },
         TestParams{
             {AttributeKind::kInvariant},
@@ -1202,35 +1202,35 @@
         TestParams{
             {AttributeKind::kLocation},
             R"(9:9 error: multiple entry point IO attributes
-1:2 note: previously consumed @location)",
+1:2 note: previously consumed '@location')",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for entry point return types)",
+            R"(1:2 error: '@must_use' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for entry point return types)",
+            R"(1:2 error: '@offset' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for entry point return types)",
+            R"(1:2 error: '@size' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for entry point return types)",
+            R"(1:2 error: '@stage' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for entry point return types)",
+            R"(1:2 error: '@stride' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for entry point return types)",
+            R"(1:2 error: '@workgroup_size' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kBinding, AttributeKind::kGroup},
-            R"(1:2 error: @binding is not valid for entry point return types)",
+            R"(1:2 error: '@binding' is not valid for entry point return types)",
         },
         TestParams{
             {AttributeKind::kLocation, AttributeKind::kLocation},
@@ -1286,75 +1286,75 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for struct declarations)",
+            R"(1:2 error: '@align' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for struct declarations)",
+            R"(1:2 error: '@binding' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for struct declarations)",
+            R"(1:2 error: '@blend_src' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for struct declarations)",
+            R"(1:2 error: '@builtin' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for struct declarations)",
+            R"(1:2 error: '@diagnostic' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kColor},
-            R"(1:2 error: @color is not valid for struct declarations)",
+            R"(1:2 error: '@color' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for struct declarations)",
+            R"(1:2 error: '@group' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for struct declarations)",
+            R"(1:2 error: '@id' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for struct declarations)",
+            R"(1:2 error: '@interpolate' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for struct declarations)",
+            R"(1:2 error: '@invariant' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for struct declarations)",
+            R"(1:2 error: '@location' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for struct declarations)",
+            R"(1:2 error: '@must_use' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for struct declarations)",
+            R"(1:2 error: '@offset' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for struct declarations)",
+            R"(1:2 error: '@size' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for struct declarations)",
+            R"(1:2 error: '@stage' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for struct declarations)",
+            R"(1:2 error: '@stride' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for struct declarations)",
+            R"(1:2 error: '@workgroup_size' is not valid for 'struct' declarations)",
         },
         TestParams{
             {AttributeKind::kBinding, AttributeKind::kGroup},
-            R"(1:2 error: @binding is not valid for struct declarations)",
+            R"(1:2 error: '@binding' is not valid for 'struct' declarations)",
         }));
 
 using StructMemberAttributeTest = TestWithParams;
@@ -1364,94 +1364,95 @@
 
     CHECK();
 }
-INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
-                         StructMemberAttributeTest,
-                         testing::Values(
-                             TestParams{
-                                 {AttributeKind::kAlign},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kBinding},
-                                 R"(1:2 error: @binding is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kBlendSrc},
-                                 R"(1:2 error: @blend_src can only be used with @location(0))",
-                             },
-                             TestParams{
-                                 {AttributeKind::kBuiltinPosition},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kColor},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kDiagnostic},
-                                 R"(1:2 error: @diagnostic is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kGroup},
-                                 R"(1:2 error: @group is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kId},
-                                 R"(1:2 error: @id is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kInterpolate},
-                                 R"(1:2 error: @interpolate can only be used with @location)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kInterpolate, AttributeKind::kLocation},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kInvariant},
-                                 R"(1:2 error: @invariant must be applied to a position builtin)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kInvariant, AttributeKind::kBuiltinPosition},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kLocation},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kMustUse},
-                                 R"(1:2 error: @must_use is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kOffset},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kSize},
-                                 Pass,
-                             },
-                             TestParams{
-                                 {AttributeKind::kStageCompute},
-                                 R"(1:2 error: @stage is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kStride},
-                                 R"(1:2 error: @stride is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kWorkgroupSize},
-                                 R"(1:2 error: @workgroup_size is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kBinding, AttributeKind::kGroup},
-                                 R"(1:2 error: @binding is not valid for struct members)",
-                             },
-                             TestParams{
-                                 {AttributeKind::kAlign, AttributeKind::kAlign},
-                                 R"(3:4 error: duplicate align attribute
+INSTANTIATE_TEST_SUITE_P(
+    ResolverAttributeValidationTest,
+    StructMemberAttributeTest,
+    testing::Values(
+        TestParams{
+            {AttributeKind::kAlign},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kBinding},
+            R"(1:2 error: '@binding' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kBlendSrc},
+            R"(1:2 error: '@blend_src' can only be used with '@location(0)')",
+        },
+        TestParams{
+            {AttributeKind::kBuiltinPosition},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kColor},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kDiagnostic},
+            R"(1:2 error: '@diagnostic' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kGroup},
+            R"(1:2 error: '@group' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kId},
+            R"(1:2 error: '@id' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kInterpolate},
+            R"(1:2 error: '@interpolate' can only be used with '@location')",
+        },
+        TestParams{
+            {AttributeKind::kInterpolate, AttributeKind::kLocation},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kInvariant},
+            R"(1:2 error: '@invariant' must be applied to a position builtin)",
+        },
+        TestParams{
+            {AttributeKind::kInvariant, AttributeKind::kBuiltinPosition},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kLocation},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kMustUse},
+            R"(1:2 error: '@must_use' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kOffset},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kSize},
+            Pass,
+        },
+        TestParams{
+            {AttributeKind::kStageCompute},
+            R"(1:2 error: '@stage' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kStride},
+            R"(1:2 error: '@stride' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kWorkgroupSize},
+            R"(1:2 error: '@workgroup_size' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kBinding, AttributeKind::kGroup},
+            R"(1:2 error: '@binding' is not valid for 'struct' members)",
+        },
+        TestParams{
+            {AttributeKind::kAlign, AttributeKind::kAlign},
+            R"(3:4 error: duplicate align attribute
 1:2 note: first attribute declared here)",
-                             }));
+        }));
 
 TEST_F(StructMemberAttributeTest, Align_Attribute_Const) {
     GlobalConst("val", ty.i32(), Expr(1_i));
@@ -1467,7 +1468,7 @@
               Vector{Member("a", ty.f32(), Vector{MemberAlign(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @align value must be a positive, power-of-two integer)");
+              R"(12:34 error: '@align' value must be a positive, power-of-two integer)");
 }
 
 TEST_F(StructMemberAttributeTest, Align_Attribute_ConstPowerOfTwo) {
@@ -1477,7 +1478,7 @@
               Vector{Member("a", ty.f32(), Vector{MemberAlign(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @align value must be a positive, power-of-two integer)");
+              R"(12:34 error: '@align' value must be a positive, power-of-two integer)");
 }
 
 TEST_F(StructMemberAttributeTest, Align_Attribute_ConstF32) {
@@ -1486,7 +1487,7 @@
     Structure("mystruct",
               Vector{Member("a", ty.f32(), Vector{MemberAlign(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @align must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@align' value must be an 'i32' or 'u32')");
 }
 
 TEST_F(StructMemberAttributeTest, Align_Attribute_ConstU32) {
@@ -1511,7 +1512,7 @@
     Structure("mystruct",
               Vector{Member("a", ty.f32(), Vector{MemberAlign(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @align must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@align' value must be an 'i32' or 'u32')");
 }
 
 TEST_F(StructMemberAttributeTest, Align_Attribute_Var) {
@@ -1550,7 +1551,7 @@
     Structure("mystruct",
               Vector{Member("a", ty.f32(), Vector{MemberSize(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @size must be a positive integer)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@size' value must be a positive integer)");
 }
 
 TEST_F(StructMemberAttributeTest, Size_Attribute_ConstF32) {
@@ -1559,7 +1560,7 @@
     Structure("mystruct",
               Vector{Member("a", ty.f32(), Vector{MemberSize(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @size must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@size' value must be an 'i32' or 'u32')");
 }
 
 TEST_F(StructMemberAttributeTest, Size_Attribute_ConstU32) {
@@ -1584,7 +1585,7 @@
     Structure("mystruct",
               Vector{Member("a", ty.f32(), Vector{MemberSize(Source{{12, 34}}, "val")})});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @size must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@size' value must be an 'i32' or 'u32')");
 }
 
 TEST_F(StructMemberAttributeTest, Size_Attribute_Var) {
@@ -1620,7 +1621,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: @size can only be applied to members where the member's type size can be fully determined at shader creation time)");
+        R"(12:34 error: '@size' can only be applied to members where the member's type size can be fully determined at shader creation time)");
 }
 
 }  // namespace StructAndStructMemberTests
@@ -1641,59 +1642,59 @@
                          testing::Values(
                              TestParams{
                                  {AttributeKind::kAlign},
-                                 R"(1:2 error: @align is not valid for array types)",
+                                 R"(1:2 error: '@align' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kBinding},
-                                 R"(1:2 error: @binding is not valid for array types)",
+                                 R"(1:2 error: '@binding' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kBlendSrc},
-                                 R"(1:2 error: @blend_src is not valid for array types)",
+                                 R"(1:2 error: '@blend_src' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kBuiltinPosition},
-                                 R"(1:2 error: @builtin is not valid for array types)",
+                                 R"(1:2 error: '@builtin' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kDiagnostic},
-                                 R"(1:2 error: @diagnostic is not valid for array types)",
+                                 R"(1:2 error: '@diagnostic' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kGroup},
-                                 R"(1:2 error: @group is not valid for array types)",
+                                 R"(1:2 error: '@group' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kId},
-                                 R"(1:2 error: @id is not valid for array types)",
+                                 R"(1:2 error: '@id' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kInterpolate},
-                                 R"(1:2 error: @interpolate is not valid for array types)",
+                                 R"(1:2 error: '@interpolate' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kInvariant},
-                                 R"(1:2 error: @invariant is not valid for array types)",
+                                 R"(1:2 error: '@invariant' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kLocation},
-                                 R"(1:2 error: @location is not valid for array types)",
+                                 R"(1:2 error: '@location' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kMustUse},
-                                 R"(1:2 error: @must_use is not valid for array types)",
+                                 R"(1:2 error: '@must_use' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kOffset},
-                                 R"(1:2 error: @offset is not valid for array types)",
+                                 R"(1:2 error: '@offset' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kSize},
-                                 R"(1:2 error: @size is not valid for array types)",
+                                 R"(1:2 error: '@size' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kStageCompute},
-                                 R"(1:2 error: @stage is not valid for array types)",
+                                 R"(1:2 error: '@stage' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kStride},
@@ -1701,11 +1702,11 @@
                              },
                              TestParams{
                                  {AttributeKind::kWorkgroupSize},
-                                 R"(1:2 error: @workgroup_size is not valid for array types)",
+                                 R"(1:2 error: '@workgroup_size' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kBinding, AttributeKind::kGroup},
-                                 R"(1:2 error: @binding is not valid for array types)",
+                                 R"(1:2 error: '@binding' is not valid for 'array' types)",
                              },
                              TestParams{
                                  {AttributeKind::kStride, AttributeKind::kStride},
@@ -1732,67 +1733,67 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for module-scope 'var')",
+            R"(1:2 error: '@align' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(9:9 error: resource variables require @group and @binding attributes)",
+            R"(9:9 error: resource variables require '@group' and '@binding' attributes)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for module-scope 'var')",
+            R"(1:2 error: '@blend_src' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for module-scope 'var')",
+            R"(1:2 error: '@builtin' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for module-scope 'var')",
+            R"(1:2 error: '@diagnostic' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(9:9 error: resource variables require @group and @binding attributes)",
+            R"(9:9 error: resource variables require '@group' and '@binding' attributes)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for module-scope 'var')",
+            R"(1:2 error: '@id' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for module-scope 'var')",
+            R"(1:2 error: '@interpolate' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for module-scope 'var')",
+            R"(1:2 error: '@invariant' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for module-scope 'var')",
+            R"(1:2 error: '@location' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for module-scope 'var')",
+            R"(1:2 error: '@must_use' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for module-scope 'var')",
+            R"(1:2 error: '@offset' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for module-scope 'var')",
+            R"(1:2 error: '@size' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for module-scope 'var')",
+            R"(1:2 error: '@stage' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for module-scope 'var')",
+            R"(1:2 error: '@stride' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for module-scope 'var')",
+            R"(1:2 error: '@workgroup_size' is not valid for module-scope 'var')",
         },
         TestParams{
             {AttributeKind::kBinding, AttributeKind::kGroup},
@@ -1810,7 +1811,7 @@
     WrapInFunction(v);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @binding is not valid for function-scope 'var'");
+    EXPECT_EQ(r()->error(), "12:34 error: '@binding' is not valid for function-scope 'var'");
 }
 
 TEST_F(VariableAttributeTest, LocalLet) {
@@ -1819,7 +1820,7 @@
     WrapInFunction(v);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @binding is not valid for 'let' declaration");
+    EXPECT_EQ(r()->error(), "12:34 error: '@binding' is not valid for 'let' declaration");
 }
 
 using ConstantAttributeTest = TestWithParams;
@@ -1836,71 +1837,71 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for 'const' declaration)",
+            R"(1:2 error: '@align' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for 'const' declaration)",
+            R"(1:2 error: '@binding' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for 'const' declaration)",
+            R"(1:2 error: '@blend_src' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for 'const' declaration)",
+            R"(1:2 error: '@builtin' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for 'const' declaration)",
+            R"(1:2 error: '@diagnostic' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for 'const' declaration)",
+            R"(1:2 error: '@group' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kId},
-            R"(1:2 error: @id is not valid for 'const' declaration)",
+            R"(1:2 error: '@id' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for 'const' declaration)",
+            R"(1:2 error: '@interpolate' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for 'const' declaration)",
+            R"(1:2 error: '@invariant' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for 'const' declaration)",
+            R"(1:2 error: '@location' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for 'const' declaration)",
+            R"(1:2 error: '@must_use' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for 'const' declaration)",
+            R"(1:2 error: '@offset' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for 'const' declaration)",
+            R"(1:2 error: '@size' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for 'const' declaration)",
+            R"(1:2 error: '@stage' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for 'const' declaration)",
+            R"(1:2 error: '@stride' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for 'const' declaration)",
+            R"(1:2 error: '@workgroup_size' is not valid for 'const' declaration)",
         },
         TestParams{
             {AttributeKind::kBinding, AttributeKind::kGroup},
-            R"(1:2 error: @binding is not valid for 'const' declaration)",
+            R"(1:2 error: '@binding' is not valid for 'const' declaration)",
         }));
 
 using OverrideAttributeTest = TestWithParams;
@@ -1917,27 +1918,27 @@
     testing::Values(
         TestParams{
             {AttributeKind::kAlign},
-            R"(1:2 error: @align is not valid for 'override' declaration)",
+            R"(1:2 error: '@align' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kBinding},
-            R"(1:2 error: @binding is not valid for 'override' declaration)",
+            R"(1:2 error: '@binding' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kBlendSrc},
-            R"(1:2 error: @blend_src is not valid for 'override' declaration)",
+            R"(1:2 error: '@blend_src' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kBuiltinPosition},
-            R"(1:2 error: @builtin is not valid for 'override' declaration)",
+            R"(1:2 error: '@builtin' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kDiagnostic},
-            R"(1:2 error: @diagnostic is not valid for 'override' declaration)",
+            R"(1:2 error: '@diagnostic' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kGroup},
-            R"(1:2 error: @group is not valid for 'override' declaration)",
+            R"(1:2 error: '@group' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kId},
@@ -1945,43 +1946,43 @@
         },
         TestParams{
             {AttributeKind::kInterpolate},
-            R"(1:2 error: @interpolate is not valid for 'override' declaration)",
+            R"(1:2 error: '@interpolate' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kInvariant},
-            R"(1:2 error: @invariant is not valid for 'override' declaration)",
+            R"(1:2 error: '@invariant' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kLocation},
-            R"(1:2 error: @location is not valid for 'override' declaration)",
+            R"(1:2 error: '@location' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kMustUse},
-            R"(1:2 error: @must_use is not valid for 'override' declaration)",
+            R"(1:2 error: '@must_use' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kOffset},
-            R"(1:2 error: @offset is not valid for 'override' declaration)",
+            R"(1:2 error: '@offset' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kSize},
-            R"(1:2 error: @size is not valid for 'override' declaration)",
+            R"(1:2 error: '@size' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kStageCompute},
-            R"(1:2 error: @stage is not valid for 'override' declaration)",
+            R"(1:2 error: '@stage' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kStride},
-            R"(1:2 error: @stride is not valid for 'override' declaration)",
+            R"(1:2 error: '@stride' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kWorkgroupSize},
-            R"(1:2 error: @workgroup_size is not valid for 'override' declaration)",
+            R"(1:2 error: '@workgroup_size' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kBinding, AttributeKind::kGroup},
-            R"(1:2 error: @binding is not valid for 'override' declaration)",
+            R"(1:2 error: '@binding' is not valid for 'override' declaration)",
         },
         TestParams{
             {AttributeKind::kId, AttributeKind::kId},
@@ -2011,7 +2012,7 @@
 }
 INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
                          SwitchBodyAttributeTest,
-                         testing::ValuesIn(OnlyDiagnosticValidFor("switch body")));
+                         testing::ValuesIn(OnlyDiagnosticValidFor("'switch' body")));
 
 using IfStatementAttributeTest = TestWithParams;
 TEST_P(IfStatementAttributeTest, IsValid) {
@@ -2278,7 +2279,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: resource variables require @group and @binding attributes)");
+              R"(12:34 error: resource variables require '@group' and '@binding' attributes)");
 }
 
 TEST_F(ResourceAttributeTest, StorageBufferMissingBinding) {
@@ -2289,7 +2290,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: resource variables require @group and @binding attributes)");
+              R"(12:34 error: resource variables require '@group' and '@binding' attributes)");
 }
 
 TEST_F(ResourceAttributeTest, TextureMissingBinding) {
@@ -2297,7 +2298,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: resource variables require @group and @binding attributes)");
+              R"(12:34 error: resource variables require '@group' and '@binding' attributes)");
 }
 
 TEST_F(ResourceAttributeTest, SamplerMissingBinding) {
@@ -2305,7 +2306,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: resource variables require @group and @binding attributes)");
+              R"(12:34 error: resource variables require '@group' and '@binding' attributes)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPairMissingBinding) {
@@ -2313,7 +2314,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: resource variables require @group and @binding attributes)");
+              R"(12:34 error: resource variables require '@group' and '@binding' attributes)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPairMissingGroup) {
@@ -2321,7 +2322,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: resource variables require @group and @binding attributes)");
+              R"(12:34 error: resource variables require '@group' and '@binding' attributes)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByEntryPoint) {
@@ -2346,7 +2347,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(56:78 error: entry point 'F' references multiple variables that use the same resource binding @group(2), @binding(1)
+        R"(56:78 error: entry point 'F' references multiple variables that use the same resource binding '@group(2)', '@binding(1)'
 12:34 note: first resource binding usage declared here)");
 }
 
@@ -2383,8 +2384,9 @@
               Group(2_a));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: non-resource variables must not have @group or @binding attributes)");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: non-resource variables must not have '@group' or '@binding' attributes)");
 }
 
 }  // namespace
@@ -2401,7 +2403,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @workgroup_size is only valid for compute stages)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' is only valid for compute stages)");
 }
 
 TEST_F(WorkgroupAttribute, NotAComputeShader) {
@@ -2412,7 +2414,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @workgroup_size is only valid for compute stages)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' is only valid for compute stages)");
 }
 
 TEST_F(WorkgroupAttribute, DuplicateAttribute) {
@@ -2560,7 +2562,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: integral user-defined fragment inputs must have a flat interpolation attribute)");
+        R"(12:34 error: integral user-defined fragment inputs must have a '@interpolate(flat)' attribute)");
 }
 
 TEST_F(InterpolateTest, VertexOutput_Integer_MissingFlatInterpolation) {
@@ -2580,7 +2582,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: integral user-defined vertex outputs must have a flat interpolation attribute
+        R"(12:34 error: integral user-defined vertex outputs must have a '@interpolate(flat)' attribute
 note: while analyzing entry point 'main')");
 }
 
@@ -2628,7 +2630,7 @@
               Binding(Source{{12, 34}}, -2_i), Group(1_i));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @binding value must be non-negative)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@binding' value must be non-negative)");
 }
 
 TEST_F(GroupAndBindingTest, Binding_F32) {
@@ -2636,7 +2638,7 @@
               Binding(Source{{12, 34}}, 2.0_f), Group(1_u));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @binding must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@binding' must be an 'i32' or 'u32' value)");
 }
 
 TEST_F(GroupAndBindingTest, Binding_AFloat) {
@@ -2644,7 +2646,7 @@
               Binding(Source{{12, 34}}, 2.0_a), Group(1_u));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @binding must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@binding' must be an 'i32' or 'u32' value)");
 }
 
 TEST_F(GroupAndBindingTest, Group_NonConstant) {
@@ -2662,7 +2664,7 @@
               Group(Source{{12, 34}}, -1_i));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @group value must be non-negative)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@group' value must be non-negative)");
 }
 
 TEST_F(GroupAndBindingTest, Group_F32) {
@@ -2670,7 +2672,7 @@
               Group(Source{{12, 34}}, 1.0_f));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @group must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@group' must be an 'i32' or 'u32' value)");
 }
 
 TEST_F(GroupAndBindingTest, Group_AFloat) {
@@ -2678,7 +2680,7 @@
               Group(Source{{12, 34}}, 1.0_a));
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @group must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@group' must be an 'i32' or 'u32' value)");
 }
 
 using IdTest = ResolverTest;
@@ -2709,19 +2711,19 @@
 TEST_F(IdTest, Negative) {
     Override("val", ty.f32(), Vector{Id(Source{{12, 34}}, -1_i)});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @id value must be non-negative)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@id' value must be non-negative)");
 }
 
 TEST_F(IdTest, F32) {
     Override("val", ty.f32(), Vector{Id(Source{{12, 34}}, 1_f)});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @id must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@id' must be an 'i32' or 'u32' value)");
 }
 
 TEST_F(IdTest, AFloat) {
     Override("val", ty.f32(), Vector{Id(Source{{12, 34}}, 1.0_a)});
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @id must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@id' must be an 'i32' or 'u32' value)");
 }
 
 enum class LocationAttributeType {
@@ -2795,19 +2797,19 @@
 TEST_P(LocationTest, Negative) {
     Build(Expr(-1_a));
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @location value must be non-negative)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' value must be non-negative)");
 }
 
 TEST_P(LocationTest, F32) {
     Build(Expr(1_f));
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @location must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' must be an 'i32' or 'u32' value)");
 }
 
 TEST_P(LocationTest, AFloat) {
     Build(Expr(1.0_a));
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @location must be an i32 or u32 value)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' must be an 'i32' or 'u32' value)");
 }
 
 INSTANTIATE_TEST_SUITE_P(LocationTest,
diff --git a/src/tint/lang/wgsl/resolver/builtin_validation_test.cc b/src/tint/lang/wgsl/resolver/builtin_validation_test.cc
index a6ff7e1..0c063d8 100644
--- a/src/tint/lang/wgsl/resolver/builtin_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_validation_test.cc
@@ -572,7 +572,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'dot4I8Packed' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -601,7 +601,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'dot4U8Packed' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -628,7 +628,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'pack4xI8' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -655,7 +655,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'pack4xU8' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -682,7 +682,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'pack4xI8Clamp' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -709,7 +709,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'pack4xU8Clamp' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -736,7 +736,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'unpack4xI8' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -763,7 +763,7 @@
     EXPECT_FALSE(resolver.Resolve());
     EXPECT_EQ(resolver.error(),
               "12:34 error: built-in function 'unpack4xU8' requires the "
-              "packed_4x8_integer_dot_product language feature, which is not allowed in the "
+              "'packed_4x8_integer_dot_product' language feature, which is not allowed in the "
               "current environment");
 }
 
@@ -990,10 +990,9 @@
 
     Resolver resolver{this, wgsl::AllowedFeatures{}};
     EXPECT_FALSE(resolver.Resolve());
-    EXPECT_EQ(resolver.error(),
-              "12:34 error: built-in function 'textureBarrier' requires the "
-              "readonly_and_readwrite_storage_textures language feature, which is not allowed in "
-              "the current environment");
+    EXPECT_EQ(
+        resolver.error(),
+        R"(12:34 error: built-in function 'textureBarrier' requires the 'readonly_and_readwrite_storage_textures' language feature, which is not allowed in the current environment)");
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/resolver/builtins_validation_test.cc b/src/tint/lang/wgsl/resolver/builtins_validation_test.cc
index 616161d..c108ab8 100644
--- a/src/tint/lang/wgsl/resolver/builtins_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtins_validation_test.cc
@@ -146,8 +146,8 @@
         EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
         StringStream err;
-        err << "12:34 error: @builtin(" << params.builtin << ")";
-        err << " cannot be used for " << params.stage << " shader input";
+        err << "12:34 error: '@builtin(" << params.builtin << ")' cannot be used for "
+            << params.stage << " shader input";
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(r()->error(), err.str());
     }
@@ -180,7 +180,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: @builtin(frag_depth) cannot be used for fragment shader input");
+              "12:34 error: '@builtin(frag_depth)' cannot be used for fragment shader input");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInputStruct_Fail) {
@@ -214,7 +214,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @builtin(frag_depth) cannot be used for fragment shader input
+              R"(12:34 error: '@builtin(frag_depth)' cannot be used for fragment shader input
 note: while analyzing entry point 'fragShader')");
 }
 
@@ -271,7 +271,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(position)' must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
@@ -287,7 +287,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(position)' must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionIsVec4h_Fail) {
@@ -304,7 +304,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(position)' must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
@@ -333,7 +333,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(frag_depth) must be 'f32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(frag_depth)' must be 'f32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
@@ -362,7 +362,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_mask) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(sample_mask)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
@@ -377,7 +377,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_mask) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(sample_mask)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
@@ -403,7 +403,7 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_mask) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(sample_mask)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Struct_Fail) {
@@ -432,7 +432,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(sample_index)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Fail) {
@@ -458,7 +458,7 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(sample_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(sample_index)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionIsNotF32_Fail) {
@@ -484,7 +484,7 @@
              Location(0_a),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(position) must be 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(position)' must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsNotF32_Fail) {
@@ -503,7 +503,7 @@
              Builtin(Source{{12, 34}}, core::BuiltinValue::kFragDepth),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(frag_depth) must be 'f32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(frag_depth)' must be 'f32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, VertexIndexIsNotU32_Fail) {
@@ -528,7 +528,7 @@
              Builtin(core::BuiltinValue::kPosition),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(vertex_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(vertex_index)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, InstanceIndexIsNotU32) {
@@ -553,7 +553,7 @@
              Builtin(core::BuiltinValue::kPosition),
          });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(instance_index) must be 'u32'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(instance_index)' must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltin_Pass) {
@@ -673,8 +673,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of @builtin(workgroup_id) must be "
-              "'vec3<u32>'");
+              R"(12:34 error: store type of '@builtin(workgroup_id)' must be 'vec3<u32>')");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_NumWorkgroupsNotVec3U32) {
@@ -688,8 +687,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of @builtin(num_workgroups) must be "
-              "'vec3<u32>'");
+              R"(12:34 error: store type of '@builtin(num_workgroups)' must be 'vec3<u32>')");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_GlobalInvocationNotVec3U32) {
@@ -703,8 +701,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of @builtin(global_invocation_id) must be "
-              "'vec3<u32>'");
+              R"(12:34 error: store type of '@builtin(global_invocation_id)' must be 'vec3<u32>')");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationIndexNotU32) {
@@ -718,8 +715,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of @builtin(local_invocation_index) must be "
-              "'u32'");
+              R"(12:34 error: store type of '@builtin(local_invocation_index)' must be 'u32')");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationNotVec3U32) {
@@ -733,8 +729,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: store type of @builtin(local_invocation_id) must be "
-              "'vec3<u32>'");
+              R"(12:34 error: store type of '@builtin(local_invocation_id)' must be 'vec3<u32>')");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltinStruct_Pass) {
@@ -800,7 +795,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(front_facing) must be 'bool'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(front_facing)' must be 'bool'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FrontFacingMemberIsNotBool_Fail) {
@@ -829,7 +824,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: store type of @builtin(front_facing) must be 'bool'");
+    EXPECT_EQ(r()->error(), "12:34 error: store type of '@builtin(front_facing)' must be 'bool'");
 }
 
 // TODO(crbug.com/tint/1846): This isn't a validation test, but this sits next to other @builtin
diff --git a/src/tint/lang/wgsl/resolver/call_validation_test.cc b/src/tint/lang/wgsl/resolver/call_validation_test.cc
index 5df9c73..001fb4e 100644
--- a/src/tint/lang/wgsl/resolver/call_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/call_validation_test.cc
@@ -481,7 +481,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: ignoring return value of function 'fn_must_use' annotated with @must_use
+        R"(12:34 error: ignoring return value of function 'fn_must_use' annotated with '@must_use'
 56:78 note: function 'fn_must_use' declared here)");
 }
 
diff --git a/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc b/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
index ab8677e..55c6704 100644
--- a/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
@@ -50,7 +50,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: use of @blend_src requires enabling extension 'chromium_internal_dual_source_blending')");
+        R"(12:34 error: use of '@blend_src' requires enabling extension 'chromium_internal_dual_source_blending')");
 }
 
 class DualSourceBlendingExtensionTests : public ResolverTest {
@@ -68,7 +68,7 @@
                         });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @location must be an i32 or u32 value");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_srci32' or 'u32' value");
 }
 
 // Using a floating point number as an index value should fail.
@@ -78,7 +78,7 @@
                                    Vector{Location(0_a), BlendSrc(Source{{12, 34}}, 1.0_a)}),
                         });
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @location must be an i32 or u32 value");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_srci32' or 'u32' value");
 }
 
 // Using a number less than zero as an index value should fail.
@@ -89,7 +89,7 @@
                         });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @blend_src value must be zero or one");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' value must be zero or one");
 }
 
 // Using a number greater than one as an index value should fail.
@@ -100,7 +100,7 @@
                         });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @blend_src value must be zero or one");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' value must be zero or one");
 }
 
 // Using an index value at the same location multiple times should fail.
@@ -112,7 +112,7 @@
                         });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @location(0) @blend_src(0) appears multiple times");
+    EXPECT_EQ(r()->error(), "12:34 error: '@location(0) @blend_src(0)' appears multiple times");
 }
 
 // Using the index attribute without a location attribute should fail.
@@ -123,7 +123,7 @@
                         });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @blend_src can only be used with @location(0)");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' can only be used with '@location(0)'");
 }
 
 // Using the index attribute without a location attribute should fail.
@@ -139,7 +139,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @blend_src can only be used with @location(0)");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' can only be used with '@location(0)'");
 }
 
 // Using an index attribute on a struct member should pass.
@@ -172,7 +172,7 @@
                         });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @blend_src can only be used with @location(0)");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' can only be used with '@location(0)'");
 }
 
 // Using the index attribute with a non-zero location should fail.
@@ -188,7 +188,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: @blend_src can only be used with @location(0)");
+    EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' can only be used with '@location(0)'");
 }
 
 TEST_F(DualSourceBlendingExtensionTests, NoNonZeroCollisionsBetweenInAndOut) {
@@ -253,8 +253,8 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: use of @blend_src requires all the output @location attributes of the entry point to be paired with a @blend_src attribute
-56:78 note: use of @blend_src here
+        R"(12:34 error: use of '@blend_src' requires all the output '@location' attributes of the entry point to be paired with a '@blend_src' attribute
+56:78 note: use of '@blend_src' here
 note: while analyzing entry point 'F')");
 }
 
@@ -286,8 +286,8 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(3:4 error: use of @blend_src requires all the output @location attributes of the entry point to be paired with a @blend_src attribute
-1:2 note: use of @blend_src here
+        R"(3:4 error: use of '@blend_src' requires all the output '@location' attributes of the entry point to be paired with a '@blend_src' attribute
+1:2 note: use of '@blend_src' here
 note: while analyzing entry point 'F')");
 }
 
@@ -311,8 +311,8 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(1:2 error: use of @blend_src requires all the output @location attributes of the entry point to be paired with a @blend_src attribute
-note: use of @blend_src here
+        R"(1:2 error: use of '@blend_src' requires all the output '@location' attributes of the entry point to be paired with a '@blend_src' attribute
+note: use of '@blend_src' here
 5:6 note: while analyzing entry point 'F')");
 }
 
diff --git a/src/tint/lang/wgsl/resolver/entry_point_validation_test.cc b/src/tint/lang/wgsl/resolver/entry_point_validation_test.cc
index 444f9e5..0a43290 100644
--- a/src/tint/lang/wgsl/resolver/entry_point_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/entry_point_validation_test.cc
@@ -119,7 +119,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed @location)");
+13:43 note: previously consumed '@location')");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
@@ -171,7 +171,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed @location
+13:43 note: previously consumed '@location'
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -227,7 +227,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @builtin(frag_depth) appears multiple times as pipeline output
+              R"(12:34 error: '@builtin(frag_depth)' appears multiple times as pipeline output
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -286,7 +286,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed @location)");
+13:43 note: previously consumed '@location')");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
@@ -338,7 +338,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
-13:43 note: previously consumed @location
+13:43 note: previously consumed '@location'
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -393,7 +393,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: @builtin(sample_index) appears multiple times as pipeline input");
+              "12:34 error: '@builtin(sample_index)' appears multiple times as pipeline input");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
@@ -427,7 +427,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @builtin(sample_index) appears multiple times as pipeline input
+              R"(12:34 error: '@builtin(sample_index)' appears multiple times as pipeline input
 12:34 note: while analyzing entry point 'main')");
 }
 
@@ -772,8 +772,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot apply @location to declaration of type 'bool'
-34:56 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(12:34 error: cannot apply '@location' to declaration of type 'bool'
+34:56 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadType_Output_Array) {
@@ -793,8 +793,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot apply @location to declaration of type 'array<f32, 2>'
-34:56 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(12:34 error: cannot apply '@location' to declaration of type 'array<f32, 2>'
+34:56 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct) {
@@ -821,8 +821,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot apply @location to declaration of type 'Input'
-13:43 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(12:34 error: cannot apply '@location' to declaration of type 'Input'
+13:43 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct_NestedStruct) {
@@ -879,8 +879,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(13:43 error: cannot apply @location to declaration of type 'array<f32>'
-note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(13:43 error: cannot apply '@location' to declaration of type 'array<f32>'
+note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Input) {
@@ -906,8 +906,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(34:56 error: cannot apply @location to declaration of type 'array<i32>'
-12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(34:56 error: cannot apply '@location' to declaration of type 'array<i32>'
+12:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Output) {
@@ -931,8 +931,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(34:56 error: cannot apply @location to declaration of type 'atomic<i32>'
-12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(34:56 error: cannot apply '@location' to declaration of type 'atomic<i32>'
+12:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Unused) {
@@ -946,8 +946,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(34:56 error: cannot apply @location to declaration of type 'mat3x2<f32>'
-12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(34:56 error: cannot apply '@location' to declaration of type 'mat3x2<f32>'
+12:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_Valid) {
@@ -998,8 +998,8 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: cannot apply @location to declaration of type 'Output'
-13:43 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot apply '@location' to declaration of type 'Output'
+13:43 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_NestedStruct) {
@@ -1054,8 +1054,8 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(13:43 error: cannot apply @location to declaration of type 'array<f32>'
-12:34 note: @location must only be applied to declarations of numeric scalar or numeric vector type)");
+              R"(13:43 error: cannot apply '@location' to declaration of type 'array<f32>'
+12:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocation_Input) {
@@ -1072,7 +1072,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @location cannot be used by compute shaders)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders)");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
@@ -1087,7 +1087,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @location cannot be used by compute shaders)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders)");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
@@ -1106,9 +1106,8 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: @location cannot be used by compute shaders\n"
-              "56:78 note: while analyzing entry point 'main'");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders
+56:78 note: while analyzing entry point 'main')");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Input) {
@@ -1125,9 +1124,8 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: @location cannot be used by compute shaders\n"
-              "56:78 note: while analyzing entry point 'main'");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders
+56:78 note: while analyzing entry point 'main')");
 }
 
 TEST_F(LocationAttributeTests, Duplicate_input) {
@@ -1153,7 +1151,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @location(1) appears multiple times)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@location(1)' appears multiple times)");
 }
 
 TEST_F(LocationAttributeTests, Duplicate_struct) {
@@ -1186,7 +1184,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(34:56 error: @location(1) appears multiple times
+              R"(34:56 error: '@location(1)' appears multiple times
 12:34 note: while analyzing entry point 'main')");
 }
 
diff --git a/src/tint/lang/wgsl/resolver/f16_extension_test.cc b/src/tint/lang/wgsl/resolver/f16_extension_test.cc
index c7f7fbd..632f790 100644
--- a/src/tint/lang/wgsl/resolver/f16_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/f16_extension_test.cc
@@ -53,7 +53,7 @@
     GlobalVar("v", ty.f16(Source{{12, 34}}), core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
+    EXPECT_EQ(r()->error(), "12:34 error: 'f16' type used without 'f16' extension enabled");
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeUsedWithExtension) {
@@ -71,7 +71,7 @@
     GlobalVar("v", ty.vec2(ty.f16(Source{{12, 34}})), core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
+    EXPECT_EQ(r()->error(), "12:34 error: 'f16' type used without 'f16' extension enabled");
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeInitUsedWithExtension) {
@@ -89,7 +89,7 @@
     GlobalVar("v", Call(ty.vec2(ty.f16(Source{{12, 34}}))), core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
+    EXPECT_EQ(r()->error(), "12:34 error: 'f16' type used without 'f16' extension enabled");
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeConvUsedWithExtension) {
@@ -108,7 +108,7 @@
               core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
+    EXPECT_EQ(r()->error(), "12:34 error: 'f16' type used without 'f16' extension enabled");
 }
 
 TEST_F(ResolverF16ExtensionTest, F16LiteralUsedWithExtension) {
@@ -126,7 +126,7 @@
     GlobalVar("v", Expr(Source{{12, 34}}, 16_h), core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
+    EXPECT_EQ(r()->error(), "12:34 error: 'f16' type used without 'f16' extension enabled");
 }
 
 using ResolverF16ExtensionBuiltinTypeAliasTest = ResolverTestWithParam<const char*>;
@@ -146,7 +146,7 @@
     GlobalVar("v", ty(Source{{12, 34}}, GetParam()), core::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
+    EXPECT_EQ(r()->error(), "12:34 error: 'f16' type used without 'f16' extension enabled");
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverF16ExtensionBuiltinTypeAliasTest,
diff --git a/src/tint/lang/wgsl/resolver/framebuffer_fetch_extension_test.cc b/src/tint/lang/wgsl/resolver/framebuffer_fetch_extension_test.cc
index a9c6576..b18be5c 100644
--- a/src/tint/lang/wgsl/resolver/framebuffer_fetch_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/framebuffer_fetch_extension_test.cc
@@ -66,7 +66,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: use of @color requires enabling extension 'chromium_experimental_framebuffer_fetch')");
+        R"(12:34 error: use of '@color' requires enabling extension 'chromium_experimental_framebuffer_fetch')");
 }
 
 TEST_F(FramebufferFetchExtensionTest, ColorMemberUsedWithExtension) {
@@ -94,7 +94,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: use of @color requires enabling extension 'chromium_experimental_framebuffer_fetch')");
+        R"(12:34 error: use of '@color' requires enabling extension 'chromium_experimental_framebuffer_fetch')");
 }
 
 TEST_F(FramebufferFetchExtensionTest, DuplicateColorParams) {
@@ -112,7 +112,7 @@
          ty.void_(), Empty, Vector{Stage(ast::PipelineStage::kFragment)});
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(1:2 error: @color(1) appears multiple times)");
+    EXPECT_EQ(r()->error(), R"(1:2 error: '@color(1)' appears multiple times)");
 }
 
 TEST_F(FramebufferFetchExtensionTest, DuplicateColorStruct) {
@@ -136,7 +136,7 @@
          Vector{Stage(ast::PipelineStage::kFragment)});
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(1:2 error: @color(1) appears multiple times)");
+    EXPECT_EQ(r()->error(), R"(1:2 error: '@color(1)' appears multiple times)");
 }
 
 TEST_F(FramebufferFetchExtensionTest, DuplicateColorParamAndStruct) {
@@ -163,7 +163,7 @@
          ty.void_(), Empty, Vector{Stage(ast::PipelineStage::kFragment)});
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(1:2 error: @color(2) appears multiple times
+    EXPECT_EQ(r()->error(), R"(1:2 error: '@color(2)' appears multiple times
 note: while analyzing entry point 'f')");
 }
 
@@ -206,8 +206,8 @@
     } else {
         EXPECT_FALSE(r()->Resolve());
         auto expected =
-            ReplaceAll(R"(12:34 error: cannot apply @color to declaration of type '$TYPE'
-56:78 note: @color must only be applied to declarations of numeric scalar or numeric vector type)",
+            ReplaceAll(R"(12:34 error: cannot apply '@color' to declaration of type '$TYPE'
+56:78 note: '@color' must only be applied to declarations of numeric scalar or numeric vector type)",
                        "$TYPE", GetParam().name);
         EXPECT_EQ(r()->error(), expected);
     }
@@ -230,8 +230,8 @@
     } else {
         EXPECT_FALSE(r()->Resolve());
         auto expected =
-            ReplaceAll(R"(12:34 error: cannot apply @color to declaration of type '$TYPE'
-56:78 note: @color must only be applied to declarations of numeric scalar or numeric vector type)",
+            ReplaceAll(R"(12:34 error: cannot apply '@color' to declaration of type '$TYPE'
+56:78 note: '@color' must only be applied to declarations of numeric scalar or numeric vector type)",
                        "$TYPE", GetParam().name);
         EXPECT_EQ(r()->error(), expected);
     }
diff --git a/src/tint/lang/wgsl/resolver/function_validation_test.cc b/src/tint/lang/wgsl/resolver/function_validation_test.cc
index 2a01da4..3de0b09 100644
--- a/src/tint/lang/wgsl/resolver/function_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/function_validation_test.cc
@@ -150,7 +150,7 @@
 
     ASSERT_TRUE(r()->Resolve());
 
-    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_EQ(r()->error(), R"(12:34 warning: code is unreachable)");
     EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
     EXPECT_TRUE(Sem().Get(ret)->IsReachable());
     EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
@@ -170,7 +170,7 @@
     Func("func", tint::Empty, ty.void_(), Vector{decl_a, Block(Block(Block(ret))), assign_a});
 
     ASSERT_TRUE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_EQ(r()->error(), R"(12:34 warning: code is unreachable)");
     EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
     EXPECT_TRUE(Sem().Get(ret)->IsReachable());
     EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
@@ -207,7 +207,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: discard statement cannot be used in vertex pipeline stage");
+              R"(12:34 error: discard statement cannot be used in vertex pipeline stage)");
 }
 
 TEST_F(ResolverFunctionValidationTest, DiscardCalledIndirectlyFromComputeEntryPoint) {
@@ -260,7 +260,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
+    EXPECT_EQ(r()->error(), R"(12:34 error: missing return at end of function)");
 }
 
 TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
@@ -277,7 +277,7 @@
     Func(Source{{12, 34}}, "func", tint::Empty, ty.i32(), tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
+    EXPECT_EQ(r()->error(), R"(12:34 error: missing return at end of function)");
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_Pass) {
@@ -343,7 +343,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function 'v' does not return a value");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function 'v' does not return a value)");
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeMissing_fail) {
@@ -623,8 +623,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        "12:34 error: '@workgroup_size' arguments must be of the same type, either 'i32' or 'u32'");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchType_I32) {
@@ -638,8 +639,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        "12:34 error: '@workgroup_size' arguments must be of the same type, either 'i32' or 'u32'");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch) {
@@ -654,8 +656,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        "12:34 error: '@workgroup_size' arguments must be of the same type, either 'i32' or 'u32'");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch2) {
@@ -672,8 +675,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        "12:34 error: '@workgroup_size' arguments must be of the same type, either 'i32' or 'u32'");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Mismatch_ConstU32) {
@@ -690,8 +694,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size arguments must be of the same type, either i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        "12:34 error: '@workgroup_size' arguments must be of the same type, either 'i32' or 'u32'");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_BadType) {
@@ -707,8 +712,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        "12:34 error: workgroup_size argument must be a constant or override-expression of type "
-        "abstract-integer, i32 or u32");
+        R"(12:34 error: '@workgroup_size' argument must be a constant or override-expression of type 'abstract-integer', 'i32' or 'u32')");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Negative) {
@@ -722,7 +726,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' argument must be at least 1)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Zero) {
@@ -736,7 +740,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' argument must be at least 1)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_BadType) {
@@ -753,8 +757,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        "12:34 error: workgroup_size argument must be a constant or override-expression of type "
-        "abstract-integer, i32 or u32");
+        R"(12:34 error: '@workgroup_size' argument must be a constant or override-expression of type 'abstract-integer', 'i32' or 'u32')");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Negative) {
@@ -769,7 +772,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' argument must be at least 1)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Zero) {
@@ -784,7 +787,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' argument must be at least 1)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_NestedZeroValueInitializer) {
@@ -799,7 +802,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@workgroup_size' argument must be at least 1)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_OverflowsU32_0x10000_0x100_0x100) {
@@ -812,7 +815,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: total workgroup grid size cannot exceed 0xffffffff");
+    EXPECT_EQ(r()->error(), R"(12:34 error: total workgroup grid size cannot exceed 0xffffffff)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_OverflowsU32_0x10000_0x10000) {
@@ -825,7 +828,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: total workgroup grid size cannot exceed 0xffffffff");
+    EXPECT_EQ(r()->error(), R"(12:34 error: total workgroup grid size cannot exceed 0xffffffff)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_OverflowsU32_0x10000_C_0x10000) {
@@ -840,7 +843,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: total workgroup grid size cannot exceed 0xffffffff");
+    EXPECT_EQ(r()->error(), R"(12:34 error: total workgroup grid size cannot exceed 0xffffffff)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_OverflowsU32_0x10000_C) {
@@ -855,7 +858,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: total workgroup grid size cannot exceed 0xffffffff");
+    EXPECT_EQ(r()->error(), R"(12:34 error: total workgroup grid size cannot exceed 0xffffffff)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_OverflowsU32_0x10000_O_0x10000) {
@@ -870,7 +873,7 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: total workgroup grid size cannot exceed 0xffffffff");
+    EXPECT_EQ(r()->error(), R"(12:34 error: total workgroup grid size cannot exceed 0xffffffff)");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
@@ -885,9 +888,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size argument must be a constant or override-expression of "
-              "type abstract-integer, i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: '@workgroup_size' argument must be a constant or override-expression of type 'abstract-integer', 'i32' or 'u32')");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_x) {
@@ -901,9 +904,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size argument must be a constant or override-expression of "
-              "type abstract-integer, i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: '@workgroup_size' argument must be a constant or override-expression of type 'abstract-integer', 'i32' or 'u32')");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_y) {
@@ -917,9 +920,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size argument must be a constant or override-expression of "
-              "type abstract-integer, i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: '@workgroup_size' argument must be a constant or override-expression of type 'abstract-integer', 'i32' or 'u32')");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_z) {
@@ -933,9 +936,9 @@
          });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: workgroup_size argument must be a constant or override-expression of "
-              "type abstract-integer, i32 or u32");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: '@workgroup_size' argument must be a constant or override-expression of type 'abstract-integer', 'i32' or 'u32')");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
@@ -943,7 +946,7 @@
     Func("f", tint::Empty, ret_type, tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function return type must be a constructible type)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_AtomicInt) {
@@ -951,7 +954,7 @@
     Func("f", tint::Empty, ret_type, tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function return type must be a constructible type)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_ArrayOfAtomic) {
@@ -959,7 +962,7 @@
     Func("f", tint::Empty, ret_type, tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function return type must be a constructible type)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_StructOfAtomic) {
@@ -970,7 +973,7 @@
     Func("f", tint::Empty, ret_type, tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function return type must be a constructible type)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_RuntimeArray) {
@@ -978,7 +981,7 @@
     Func("f", tint::Empty, ret_type, tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function return type must be a constructible type)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterStoreType_NonAtomicFree) {
@@ -990,7 +993,7 @@
     Func("f", Vector{bar}, ty.void_(), tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: type of function parameter must be constructible");
+    EXPECT_EQ(r()->error(), R"(12:34 error: type of function parameter must be constructible)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterStoreType_AtomicFree) {
@@ -1022,7 +1025,7 @@
     Func(Source{{12, 34}}, "f", params, ty.void_(), tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: function declares 256 parameters, maximum is 255");
+    EXPECT_EQ(r()->error(), R"(12:34 error: function declares 256 parameters, maximum is 255)");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterVectorNoType) {
@@ -1032,7 +1035,7 @@
          tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'vec3'");
+    EXPECT_EQ(r()->error(), R"(12:34 error: expected '<' for 'vec3')");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterMatrixNoType) {
@@ -1042,7 +1045,7 @@
          tint::Empty);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'mat3x3'");
+    EXPECT_EQ(r()->error(), R"(12:34 error: expected '<' for 'mat3x3')");
 }
 
 enum class Expectation {
diff --git a/src/tint/lang/wgsl/resolver/host_shareable_validation_test.cc b/src/tint/lang/wgsl/resolver/host_shareable_validation_test.cc
index 50e7448..e4018af 100644
--- a/src/tint/lang/wgsl/resolver/host_shareable_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/host_shareable_validation_test.cc
@@ -50,7 +50,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 56:78 note: while analyzing structure member S.x
 90:12 note: while instantiating 'var' g)");
 }
@@ -66,7 +66,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'vec3<bool>' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'vec3<bool>' cannot be used in address space 'storage' as it is non-host-shareable
 56:78 note: while analyzing structure member S.x
 90:12 note: while instantiating 'var' g)");
 }
@@ -82,7 +82,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(12:34 error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 56:78 note: while analyzing structure member S.x
 90:12 note: while instantiating 'var' g)");
 }
@@ -101,7 +101,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
+        R"(error: type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
 1:2 note: while analyzing structure member I1.x
 3:4 note: while analyzing structure member I2.y
 5:6 note: while analyzing structure member I3.z
diff --git a/src/tint/lang/wgsl/resolver/increment_decrement_validation_test.cc b/src/tint/lang/wgsl/resolver/increment_decrement_validation_test.cc
index 2f4ea33..3f2d7ea 100644
--- a/src/tint/lang/wgsl/resolver/increment_decrement_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/increment_decrement_validation_test.cc
@@ -166,7 +166,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify 'let'
-12:34 note: 'a' is declared here:)");
+12:34 note: 'let a' declared here)");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Parameter) {
@@ -182,7 +182,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify function parameter
-12:34 note: 'a' is declared here:)");
+12:34 note: parameter 'a' declared here)");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ReturnValue) {
diff --git a/src/tint/lang/wgsl/resolver/override_test.cc b/src/tint/lang/wgsl/resolver/override_test.cc
index 3077e79..df09b2e 100644
--- a/src/tint/lang/wgsl/resolver/override_test.cc
+++ b/src/tint/lang/wgsl/resolver/override_test.cc
@@ -106,8 +106,8 @@
 
     EXPECT_FALSE(r()->Resolve());
 
-    EXPECT_EQ(r()->error(), R"(56:78 error: @id values must be unique
-12:34 note: a override with an ID of 7 was previously declared here:)");
+    EXPECT_EQ(r()->error(), R"(56:78 error: '@id' values must be unique
+12:34 note: a override with an ID of 7 was previously declared here)");
 }
 
 TEST_F(ResolverOverrideTest, IdTooLarge) {
@@ -115,7 +115,7 @@
 
     EXPECT_FALSE(r()->Resolve());
 
-    EXPECT_EQ(r()->error(), "12:34 error: @id value must be between 0 and 65535");
+    EXPECT_EQ(r()->error(), "12:34 error: '@id' value must be between 0 and 65535");
 }
 
 TEST_F(ResolverOverrideTest, TransitiveReferences_DirectUse) {
diff --git a/src/tint/lang/wgsl/resolver/pixel_local_extension_test.cc b/src/tint/lang/wgsl/resolver/pixel_local_extension_test.cc
index eceb5ae..74ea8e1 100644
--- a/src/tint/lang/wgsl/resolver/pixel_local_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/pixel_local_extension_test.cc
@@ -354,8 +354,8 @@
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(
             r()->error(),
-            R"(12:34 error: struct members used in the 'pixel_local' address space can only be of the type 'i32', 'u32' or 'f32'
-56:78 note: struct 'S' used in the 'pixel_local' address space here)");
+            R"(12:34 error: 'struct' members used in the 'pixel_local' address space can only be of the type 'i32', 'u32' or 'f32'
+56:78 note: 'struct S' used in the 'pixel_local' address space here)");
     }
 }
 
diff --git a/src/tint/lang/wgsl/resolver/ptr_ref_validation_test.cc b/src/tint/lang/wgsl/resolver/ptr_ref_validation_test.cc
index bbcbc13..e7b05da 100644
--- a/src/tint/lang/wgsl/resolver/ptr_ref_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/ptr_ref_validation_test.cc
@@ -306,7 +306,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: cannot initialize let of type "
+              "12:34 error: cannot initialize 'let' of type "
               "'ptr<storage, i32, read>' with value of type "
               "'ptr<storage, i32, read_write>'");
 }
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 0beaffe..20ec2a4 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -108,6 +108,8 @@
 #include "src/tint/utils/math/math.h"
 #include "src/tint/utils/text/string.h"
 #include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/text_style.h"
 
 using namespace tint::core::fluent_types;  // NOLINT
 
@@ -269,7 +271,8 @@
             attribute,  //
             [&](const ast::InternalAttribute* attr) -> bool { return InternalAttribute(attr); },
             [&](Default) {
-                ErrorInvalidAttribute(attribute, "'let' declaration");
+                ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "let"
+                                                              << style::Plain << " declaration");
                 return false;
             });
         if (!ok) {
@@ -278,7 +281,8 @@
     }
 
     if (TINT_UNLIKELY(!v->initializer)) {
-        AddError(v->source) << "'let' declaration must have an initializer";
+        AddError(v->source) << style::Keyword << "let" << style::Plain
+                            << " declaration must have an initializer";
         return nullptr;
     }
 
@@ -299,7 +303,8 @@
 
     if (!ApplyAddressSpaceUsageToType(core::AddressSpace::kUndefined,
                                       const_cast<core::type::Type*>(sem->Type()), v->source)) {
-        AddNote(v->source) << "while instantiating 'let' " << v->name->symbol.Name();
+        AddNote(v->source) << "while instantiating " << style::Keyword << "let " << style::Variable
+                           << v->name->symbol.Name();
         return nullptr;
     }
 
@@ -357,7 +362,8 @@
 
     if (!ApplyAddressSpaceUsageToType(core::AddressSpace::kUndefined,
                                       const_cast<core::type::Type*>(ty), v->source)) {
-        AddNote(v->source) << "while instantiating 'override' " << v->name->symbol.Name();
+        AddNote(v->source) << "while instantiating " << style::Keyword << "override "
+                           << style::Variable << v->name->symbol.Name();
         return nullptr;
     }
 
@@ -374,19 +380,24 @@
                     return false;
                 }
                 if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-                    AddError(attr->source) << "@id must be an i32 or u32 value";
+                    AddError(attr->source)
+                        << style::Attribute << "@id" << style::Plain << " must be an "
+                        << style::Type << "i32" << style::Plain << " or " << style::Type << "u32"
+                        << style::Plain << " value";
                     return false;
                 }
 
                 auto const_value = materialized->ConstantValue();
                 auto value = const_value->ValueAs<AInt>();
                 if (value < 0) {
-                    AddError(attr->source) << "@id value must be non-negative";
+                    AddError(attr->source) << style::Attribute << "@id" << style::Plain
+                                           << " value must be non-negative";
                     return false;
                 }
                 if (value > std::numeric_limits<decltype(OverrideId::value)>::max()) {
                     AddError(attr->source)
-                        << "@id value must be between 0 and "
+                        << style::Attribute << "@id" << style::Plain
+                        << " value must be between 0 and "
                         << std::numeric_limits<decltype(OverrideId::value)>::max();
                     return false;
                 }
@@ -399,7 +410,8 @@
                 return true;
             },
             [&](Default) {
-                ErrorInvalidAttribute(attribute, "'override' declaration");
+                ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "override"
+                                                              << style::Plain << " declaration");
                 return false;
             });
         if (!ok) {
@@ -425,7 +437,9 @@
         Mark(attribute);
         bool ok = Switch(attribute,  //
                          [&](Default) {
-                             ErrorInvalidAttribute(attribute, "'const' declaration");
+                             ErrorInvalidAttribute(attribute,
+                                                   StyledText{} << style::Keyword << "const"
+                                                                << style::Plain << " declaration");
                              return false;
                          });
         if (!ok) {
@@ -684,7 +698,8 @@
                 case kErrored:
                     return nullptr;
                 case kInvalid:
-                    ErrorInvalidAttribute(attribute, "module-scope 'var'");
+                    ErrorInvalidAttribute(
+                        attribute, StyledText{} << "module-scope " << style::Keyword << "var");
                     return nullptr;
             }
         }
@@ -700,7 +715,8 @@
                 attribute,
                 [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
                 [&](Default) {
-                    ErrorInvalidAttribute(attribute, "function-scope 'var'");
+                    ErrorInvalidAttribute(
+                        attribute, StyledText{} << "function-scope " << style::Keyword << "var");
                     return false;
                 });
             if (!ok) {
@@ -759,7 +775,7 @@
                 [&](const ast::GroupAttribute* attr) {
                     if (validator_.IsValidationEnabled(
                             param->attributes, ast::DisabledValidation::kEntryPointParameter)) {
-                        ErrorInvalidAttribute(attribute, "function parameters");
+                        ErrorInvalidAttribute(attribute, StyledText{} << "function parameters");
                         return false;
                     }
                     auto value = GroupAttribute(attr);
@@ -772,7 +788,7 @@
                 [&](const ast::BindingAttribute* attr) -> bool {
                     if (validator_.IsValidationEnabled(
                             param->attributes, ast::DisabledValidation::kEntryPointParameter)) {
-                        ErrorInvalidAttribute(attribute, "function parameters");
+                        ErrorInvalidAttribute(attribute, StyledText{} << "function parameters");
                         return false;
                     }
                     auto value = BindingAttribute(attr);
@@ -783,7 +799,7 @@
                     return true;
                 },
                 [&](Default) {
-                    ErrorInvalidAttribute(attribute, "function parameters");
+                    ErrorInvalidAttribute(attribute, StyledText{} << "function parameters");
                     return false;
                 });
             if (!ok) {
@@ -802,9 +818,10 @@
                 [&](Default) {
                     if (attribute->IsAnyOf<ast::LocationAttribute, ast::BuiltinAttribute,
                                            ast::InvariantAttribute, ast::InterpolateAttribute>()) {
-                        ErrorInvalidAttribute(attribute, "non-entry point function parameters");
+                        ErrorInvalidAttribute(
+                            attribute, StyledText{} << "non-entry point function parameters");
                     } else {
-                        ErrorInvalidAttribute(attribute, "function parameters");
+                        ErrorInvalidAttribute(attribute, StyledText{} << "function parameters");
                     }
                     return false;
                 });
@@ -996,7 +1013,7 @@
             },
             [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
             [&](Default) {
-                ErrorInvalidAttribute(attribute, "functions");
+                ErrorInvalidAttribute(attribute, StyledText{} << "functions");
                 return false;
             });
         if (!ok) {
@@ -1118,19 +1135,20 @@
                 case kErrored:
                     return nullptr;
                 case kInvalid:
-                    ErrorInvalidAttribute(attribute, "entry point return types");
+                    ErrorInvalidAttribute(attribute, StyledText{} << "entry point return types");
                     return nullptr;
             }
         }
     } else {
         for (auto* attribute : decl->return_type_attributes) {
             Mark(attribute);
-            bool ok = Switch(attribute,  //
-                             [&](Default) {
-                                 ErrorInvalidAttribute(attribute,
-                                                       "non-entry point function return types");
-                                 return false;
-                             });
+            bool ok =
+                Switch(attribute,  //
+                       [&](Default) {
+                           ErrorInvalidAttribute(
+                               attribute, StyledText{} << "non-entry point function return types");
+                           return false;
+                       });
             if (!ok) {
                 return nullptr;
             }
@@ -2987,7 +3005,8 @@
     if (!tmpl_ident) {
         if (TINT_UNLIKELY(min_args != 0)) {
             AddError(Source{ident->source.range.end})
-                << "expected '<' for '" << ident->symbol.Name() << "'";
+                << "expected " << style::Code << "<" << style::Plain << " for " << style::Code
+                << ident->symbol.Name();
         }
         return nullptr;
     }
@@ -3002,19 +3021,19 @@
     }
     if (min_args == max_args) {
         if (TINT_UNLIKELY(ident->arguments.Length() != min_args)) {
-            AddError(ident->source) << "'" << ident->symbol.Name() << "' requires " << min_args
-                                    << " template arguments";
+            AddError(ident->source) << style::Code << ident->symbol.Name() << style::Plain
+                                    << " requires " << min_args << " template arguments";
             return false;
         }
     } else {
         if (TINT_UNLIKELY(ident->arguments.Length() < min_args)) {
-            AddError(ident->source) << "'" << ident->symbol.Name() << "' requires at least "
-                                    << min_args << " template arguments";
+            AddError(ident->source) << style::Code << ident->symbol.Name() << style::Plain
+                                    << " requires at least " << min_args << " template arguments";
             return false;
         }
         if (TINT_UNLIKELY(ident->arguments.Length() > max_args)) {
-            AddError(ident->source) << "'" << ident->symbol.Name() << "' requires at most "
-                                    << max_args << " template arguments";
+            AddError(ident->source) << style::Code << ident->symbol.Name() << style::Plain
+                                    << " requires at most " << max_args << " template arguments";
             return false;
         }
     }
@@ -3687,8 +3706,8 @@
                                                      ptr->Access());
                 root_ident = expr->RootIdentifier();
             } else {
-                AddError(unary->expr->source)
-                    << "cannot dereference expression of type '" << sem_.TypeNameOf(expr_ty) << "'";
+                AddError(unary->expr->source) << "cannot dereference expression of type "
+                                              << style::Type << sem_.TypeNameOf(expr_ty);
                 return nullptr;
             }
             break;
@@ -3748,14 +3767,17 @@
     }
 
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-        AddError(attr->source) << "@location must be an i32 or u32 value";
+        AddError(attr->source) << style::Attribute << "@location" << style::Plain << " must be an "
+                               << style::Type << "i32" << style::Plain << " or " << style::Type
+                               << "u32" << style::Plain << " value";
         return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
-        AddError(attr->source) << "@location value must be non-negative";
+        AddError(attr->source) << style::Attribute << "@location" << style::Plain
+                               << " value must be non-negative";
         return Failure{};
     }
 
@@ -3772,14 +3794,17 @@
     }
 
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-        AddError(attr->source) << "@color must be an i32 or u32 value";
+        AddError(attr->source) << style::Attribute << "@color" << style::Plain << " must be an "
+                               << style::Type << "i32" << style::Plain << " or " << style::Type
+                               << "u32" << style::Plain << " value";
         return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
-        AddError(attr->source) << "@color value must be non-negative";
+        AddError(attr->source) << style::Attribute << "@color" << style::Plain
+                               << " value must be non-negative";
         return Failure{};
     }
 
@@ -3795,14 +3820,17 @@
     }
 
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-        AddError(attr->source) << "@location must be an i32 or u32 value";
+        AddError(attr->source) << style::Attribute << "@blend_src" << style::Plain << style::Type
+                               << "i32" << style::Plain << " or " << style::Type << "u32"
+                               << style::Plain << " value";
         return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value != 0 && value != 1) {
-        AddError(attr->source) << "@blend_src value must be zero or one";
+        AddError(attr->source) << style::Attribute << "@blend_src" << style::Plain
+                               << " value must be zero or one";
         return Failure{};
     }
 
@@ -3818,14 +3846,17 @@
         return Failure{};
     }
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-        AddError(attr->source) << "@binding must be an i32 or u32 value";
+        AddError(attr->source) << style::Attribute << "@binding" << style::Plain << " must be an "
+                               << style::Type << "i32" << style::Plain << " or " << style::Type
+                               << "u32" << style::Plain << " value";
         return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
-        AddError(attr->source) << "@binding value must be non-negative";
+        AddError(attr->source) << style::Attribute << "@binding" << style::Plain
+                               << " value must be non-negative";
         return Failure{};
     }
     return static_cast<uint32_t>(value);
@@ -3840,14 +3871,17 @@
         return Failure{};
     }
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-        AddError(attr->source) << "@group must be an i32 or u32 value";
+        AddError(attr->source) << style::Attribute << "@group" << style::Plain << " must be an "
+                               << style::Type << "i32" << style::Plain << " or " << style::Type
+                               << "u32" << style::Plain << " value";
         return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
-        AddError(attr->source) << "@group value must be non-negative";
+        AddError(attr->source) << style::Attribute << "@group" << style::Plain
+                               << " value must be non-negative";
         return Failure{};
     }
     return static_cast<uint32_t>(value);
@@ -3864,9 +3898,13 @@
     Vector<const sem::ValueExpression*, 3> args;
     Vector<const core::type::Type*, 3> arg_tys;
 
-    constexpr const char* kErrBadExpr =
-        "workgroup_size argument must be a constant or override-expression of type "
-        "abstract-integer, i32 or u32";
+    auto err_bad_expr = [&](const ast::Expression* value) {
+        AddError(value->source) << style::Attribute << "@workgroup_size" << style::Plain
+                                << " argument must be a constant or override-expression of type "
+                                << style::Type << "abstract-integer" << style::Plain << ", "
+                                << style::Type << "i32" << style::Plain << " or " << style::Type
+                                << "u32";
+    };
 
     for (size_t i = 0; i < 3; i++) {
         // Each argument to this attribute can either be a literal, an identifier for a
@@ -3881,13 +3919,13 @@
         }
         auto* ty = expr->Type();
         if (!ty->IsAnyOf<core::type::I32, core::type::U32, core::type::AbstractInt>()) {
-            AddError(value->source) << kErrBadExpr;
+            err_bad_expr(value);
             return Failure{};
         }
 
         if (expr->Stage() != core::EvaluationStage::kConstant &&
             expr->Stage() != core::EvaluationStage::kOverride) {
-            AddError(value->source) << kErrBadExpr;
+            err_bad_expr(value);
             return Failure{};
         }
 
@@ -3897,8 +3935,9 @@
 
     auto* common_ty = core::type::Type::Common(arg_tys);
     if (!common_ty) {
-        AddError(attr->source)
-            << "workgroup_size arguments must be of the same type, either i32 or u32";
+        AddError(attr->source) << style::Attribute << "@workgroup_size" << style::Plain
+                               << " arguments must be of the same type, either " << style::Type
+                               << "i32" << style::Plain << " or " << style::Type << "u32";
         return Failure{};
     }
 
@@ -3914,7 +3953,8 @@
         }
         if (auto* value = materialized->ConstantValue()) {
             if (value->ValueAs<AInt>() < 1) {
-                AddError(values[i]->source) << "workgroup_size argument must be at least 1";
+                AddError(values[i]->source) << style::Attribute << "@workgroup_size" << style::Plain
+                                            << " argument must be at least 1";
                 return Failure{};
             }
             ws[i] = value->ValueAs<u32>();
@@ -4007,7 +4047,8 @@
                 validator_.DiagnosticFilters().Set(rule, control.severity);
             } else {
                 auto& warning = AddWarning(control.rule_name->source)
-                                << "unrecognized diagnostic rule 'chromium." << name << "'\n";
+                                << "unrecognized diagnostic rule " << style::Code << "chromium."
+                                << name << style::Plain << "\n";
                 tint::SuggestAlternativeOptions opts;
                 opts.prefix = "chromium.";
                 tint::SuggestAlternatives(name, wgsl::kChromiumDiagnosticRuleStrings,
@@ -4022,7 +4063,8 @@
         validator_.DiagnosticFilters().Set(rule, control.severity);
     } else {
         auto& warning = AddWarning(control.rule_name->source)
-                        << "unrecognized diagnostic rule '" << name << "'\n";
+                        << "unrecognized diagnostic rule " << style::Code << name << style::Plain
+                        << "\n";
         tint::SuggestAlternatives(name, wgsl::kCoreDiagnosticRuleStrings, warning.message);
     }
     return true;
@@ -4033,8 +4075,8 @@
         Mark(ext);
         enabled_extensions_.Add(ext->name);
         if (!allowed_features_.extensions.count(ext->name)) {
-            AddError(ext->source) << "extension '" << ext->name
-                                  << "' is not allowed in the current environment";
+            AddError(ext->source) << "extension " << style::Code << ext->name << style::Plain
+                                  << " is not allowed in the current environment";
             return false;
         }
     }
@@ -4044,8 +4086,8 @@
 bool Resolver::Requires(const ast::Requires* req) {
     for (auto feature : req->features) {
         if (!allowed_features_.features.count(feature)) {
-            AddError(req->source) << "language feature '" << wgsl::ToString(feature)
-                                  << "' is not allowed in the current environment";
+            AddError(req->source) << "language feature " << style::Code << wgsl::ToString(feature)
+                                  << style::Plain << " is not allowed in the current environment";
             return false;
         }
     }
@@ -4101,8 +4143,8 @@
             auto* count_val = count_sem->ConstantValue();
             if (auto* ty = count_val->Type(); !ty->is_integer_scalar()) {
                 AddError(count_expr->source)
-                    << "array count must evaluate to a constant integer expression, but is type '"
-                    << ty->FriendlyName() << "'";
+                    << "array count must evaluate to a constant integer expression, but is type "
+                    << style::Type << ty->FriendlyName();
                 return nullptr;
             }
 
@@ -4150,7 +4192,8 @@
                 return true;
             },
             [&](Default) {
-                ErrorInvalidAttribute(attribute, "array types");
+                ErrorInvalidAttribute(
+                    attribute, StyledText{} << style::Type << "array" << style::Plain << " types");
                 return false;
             });
         if (!ok) {
@@ -4226,9 +4269,9 @@
         // https://gpuweb.github.io/gpuweb/wgsl/#limits
         const size_t kMaxNumStructMembers = 16383;
         if (str->members.Length() > kMaxNumStructMembers) {
-            AddError(str->source) << "struct '" << struct_name() << "' has "
-                                  << str->members.Length() << " members, maximum is "
-                                  << kMaxNumStructMembers;
+            AddError(str->source) << style::Keyword << "struct " << style::Type << struct_name()
+                                  << style::Plain << " has " << str->members.Length()
+                                  << " members, maximum is " << kMaxNumStructMembers;
             return nullptr;
         }
     }
@@ -4242,7 +4285,8 @@
         bool ok = Switch(
             attribute, [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
             [&](Default) {
-                ErrorInvalidAttribute(attribute, "struct declarations");
+                ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "struct"
+                                                              << style::Plain << " declarations");
                 return false;
             });
         if (!ok) {
@@ -4268,7 +4312,8 @@
         Mark(member);
         Mark(member->name);
         if (auto added = member_map.Add(member->name->symbol, member); !added) {
-            AddError(member->source) << "redefinition of '" << member->name->symbol.Name() << "'";
+            AddError(member->source)
+                << "redefinition of " << style::Code << member->name->symbol.Name();
             AddNote(added.value->source) << "previous definition is here";
             return nullptr;
         }
@@ -4339,20 +4384,23 @@
                         return false;
                     }
                     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
-                        AddError(attr->source) << "@align must be an i32 or u32 value";
+                        AddError(attr->source) << style::Attribute << "@align" << style::Plain
+                                               << " value must be an " << style::Type << "i32"
+                                               << style::Plain << " or " << style::Type << "u32";
                         return false;
                     }
 
                     auto const_value = materialized->ConstantValue();
                     if (!const_value) {
-                        AddError(attr->source) << "@align must be constant expression";
+                        AddError(attr->source) << style::Attribute << "@align" << style::Plain
+                                               << " value must be constant expression";
                         return false;
                     }
                     auto value = const_value->ValueAs<AInt>();
 
                     if (value <= 0 || !tint::IsPowerOfTwo(value)) {
-                        AddError(attr->source)
-                            << "@align value must be a positive, power-of-two integer";
+                        AddError(attr->source) << style::Attribute << "@align" << style::Plain
+                                               << " value must be a positive, power-of-two integer";
                         return false;
                     }
                     align = u32(value);
@@ -4368,26 +4416,31 @@
                         return false;
                     }
                     if (!materialized->Type()->IsAnyOf<core::type::U32, core::type::I32>()) {
-                        AddError(attr->source) << "@size must be an i32 or u32 value";
+                        AddError(attr->source) << style::Attribute << "@size" << style::Plain
+                                               << " value must be an " << style::Type << "i32"
+                                               << style::Plain << " or " << style::Type << "u32";
                         return false;
                     }
 
                     auto const_value = materialized->ConstantValue();
                     if (!const_value) {
-                        AddError(attr->expr->source) << "@size must be constant expression";
+                        AddError(attr->expr->source) << style::Attribute << "@size" << style::Plain
+                                                     << " value must be constant expression";
                         return false;
                     }
                     {
                         auto value = const_value->ValueAs<AInt>();
                         if (value <= 0) {
-                            AddError(attr->source) << "@size must be a positive integer";
+                            AddError(attr->source) << style::Attribute << "@size" << style::Plain
+                                                   << " value must be a positive integer";
                             return false;
                         }
                     }
                     auto value = const_value->ValueAs<uint64_t>();
                     if (value < size) {
                         AddError(attr->source)
-                            << "@size must be at least as big as the type's size (" << size << ")";
+                            << style::Attribute << "@size" << style::Plain
+                            << " must be at least as big as the type's size (" << size << ")";
                         return false;
                     }
                     size = u32(value);
@@ -4444,14 +4497,17 @@
                 [&](const ast::StrideAttribute* attr) {
                     if (validator_.IsValidationEnabled(
                             member->attributes, ast::DisabledValidation::kIgnoreStrideAttribute)) {
-                        ErrorInvalidAttribute(attribute, "struct members");
+                        ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "struct"
+                                                                      << style::Plain
+                                                                      << " members");
                         return false;
                     }
                     return StrideAttribute(attr);
                 },
                 [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
                 [&](Default) {
-                    ErrorInvalidAttribute(attribute, "struct members");
+                    ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "struct"
+                                                                  << style::Plain << " members");
                     return false;
                 });
             if (!ok) {
@@ -4460,7 +4516,9 @@
         }
 
         if (has_offset_attr && (has_align_attr || has_size_attr)) {
-            AddError(member->source) << "@offset cannot be used with @align or @size";
+            AddError(member->source) << style::Attribute << "@offset" << style::Plain
+                                     << " cannot be used with " << style::Attribute << "@align"
+                                     << style::Plain << " or " << style::Attribute << "@size";
             return nullptr;
         }
 
@@ -4525,8 +4583,9 @@
     //  https://gpuweb.github.io/gpuweb/wgsl/#limits
     const size_t nest_depth = 1 + members_nest_depth;
     if (nest_depth > kMaxNestDepthOfCompositeType) {
-        AddError(str->source) << "struct '" << struct_name() << "' has nesting depth of "
-                              << nest_depth << ", maximum is " << kMaxNestDepthOfCompositeType;
+        AddError(str->source) << style::Keyword << "struct " << style::Type << struct_name()
+                              << style::Plain << " has nesting depth of " << nest_depth
+                              << ", maximum is " << kMaxNestDepthOfCompositeType;
         return nullptr;
     }
     nest_depth_.Add(out, nest_depth);
@@ -4614,7 +4673,8 @@
                 attribute,
                 [&](const ast::DiagnosticAttribute* attr) { return DiagnosticAttribute(attr); },
                 [&](Default) {
-                    ErrorInvalidAttribute(attribute, "switch body");
+                    ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "switch"
+                                                                  << style::Plain << " body");
                     return false;
                 });
             if (!ok) {
@@ -4870,8 +4930,9 @@
     }
 
     if (core::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
-        AddError(usage) << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '"
-                        << address_space << "' as it is non-host-shareable";
+        AddError(usage) << "type " << style::Type << sem_.TypeNameOf(ty) << style::Plain
+                        << " cannot be used in address space " << style::Enum << address_space
+                        << style::Plain << " as it is non-host-shareable";
         return false;
     }
 
@@ -4893,7 +4954,7 @@
                 attribute,  //
                 [&](const ast::DiagnosticAttribute* attr) { return DiagnosticAttribute(attr); },
                 [&](Default) {
-                    ErrorInvalidAttribute(attribute, use);
+                    ErrorInvalidAttribute(attribute, StyledText{} << use);
                     return false;
                 });
             if (!ok) {
@@ -4979,8 +5040,8 @@
 
 bool Resolver::CheckNotTemplated(const char* use, const ast::Identifier* ident) {
     if (TINT_UNLIKELY(ident->Is<ast::TemplatedIdentifier>())) {
-        AddError(ident->source) << use << " '" << ident->symbol.Name()
-                                << "' does not take template arguments";
+        AddError(ident->source) << use << " " << style::Code << ident->symbol.Name() << style::Plain
+                                << " does not take template arguments";
         if (auto resolved = dependencies_.resolved_identifiers.Get(ident)) {
             if (auto* ast_node = resolved->Node()) {
                 sem_.NoteDeclarationSource(ast_node);
@@ -4991,8 +5052,9 @@
     return true;
 }
 
-void Resolver::ErrorInvalidAttribute(const ast::Attribute* attr, std::string_view use) {
-    AddError(attr->source) << "@" << attr->Name() << " is not valid for " << std::string(use);
+void Resolver::ErrorInvalidAttribute(const ast::Attribute* attr, StyledText use) {
+    AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+                           << " is not valid for " << use;
 }
 
 void Resolver::AddICE(std::string_view msg, const Source& source) const {
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 73b27ef..5dcab43 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -636,7 +636,7 @@
     /// Raises an error that the attribute is not valid for the given use.
     /// @param attr the invalue attribute
     /// @param use the thing that the attribute was applied to
-    void ErrorInvalidAttribute(const ast::Attribute* attr, std::string_view use);
+    void ErrorInvalidAttribute(const ast::Attribute* attr, StyledText use);
 
     /// Adds the given internal compiler error message to the diagnostics
     void AddICE(std::string_view msg, const Source& source) const;
diff --git a/src/tint/lang/wgsl/resolver/resolver_test.cc b/src/tint/lang/wgsl/resolver/resolver_test.cc
index 4f0af3b..3d21f7a 100644
--- a/src/tint/lang/wgsl/resolver/resolver_test.cc
+++ b/src/tint/lang/wgsl/resolver/resolver_test.cc
@@ -2533,7 +2533,7 @@
     }
     Structure(Source{{12, 34}}, "S", std::move(members));
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct 'S' has 16384 members, maximum is 16383");
+    EXPECT_EQ(r()->error(), "12:34 error: 'struct S' has 16384 members, maximum is 16383");
 }
 
 TEST_F(ResolverTest, MaxNumStructMembers_WithIgnoreStructMemberLimit_Valid) {
@@ -2574,7 +2574,7 @@
         s = Structure(source, "S" + std::to_string(i), Vector{Member("m", ty.Of(s))});
     }
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct 'S254' has nesting depth of 256, maximum is 255");
+    EXPECT_EQ(r()->error(), "12:34 error: 'struct S254' has nesting depth of 256, maximum is 255");
 }
 
 TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithVector_Valid) {
@@ -2596,7 +2596,7 @@
         s = Structure(source, "S" + std::to_string(i), Vector{Member("m", ty.Of(s))});
     }
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct 'S253' has nesting depth of 256, maximum is 255");
+    EXPECT_EQ(r()->error(), "12:34 error: 'struct S253' has nesting depth of 256, maximum is 255");
 }
 
 TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithMatrix_Valid) {
@@ -2618,7 +2618,7 @@
         s = Structure(source, "S" + std::to_string(i), Vector{Member("m", ty.Of(s))});
     }
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct 'S252' has nesting depth of 256, maximum is 255");
+    EXPECT_EQ(r()->error(), "12:34 error: 'struct S252' has nesting depth of 256, maximum is 255");
 }
 
 TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Arrays_Valid) {
@@ -2714,7 +2714,7 @@
         s = Structure(source, "S" + std::to_string(i), Vector{Member("m", ty.Of(s))});
     }
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 error: struct 'S251' has nesting depth of 256, maximum is 255");
+    EXPECT_EQ(r()->error(), "12:34 error: 'struct S251' has nesting depth of 256, maximum is 255");
 }
 
 TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfStruct_Valid) {
diff --git a/src/tint/lang/wgsl/resolver/sem_helper.cc b/src/tint/lang/wgsl/resolver/sem_helper.cc
index 25eeef5..5164284 100644
--- a/src/tint/lang/wgsl/resolver/sem_helper.cc
+++ b/src/tint/lang/wgsl/resolver/sem_helper.cc
@@ -72,7 +72,7 @@
     if (auto* incomplete = type->As<IncompleteType>(); TINT_UNLIKELY(incomplete)) {
         AddError(expr->Declaration()->source.End())
             << "expected " << style::Code << "<" << style::Plain << " for " << style::Type
-            << incomplete->builtin << style::Plain;
+            << incomplete->builtin;
         return nullptr;
     }
 
@@ -95,7 +95,7 @@
                 [&](const ast::Parameter*) { text << "parameter"; },                  //
                 [&](const ast::Override*) { text << style::Keyword << "override"; },  //
                 [&](Default) { text << "variable"; });
-            text << " " << style::Variable << name << style::Plain;
+            text << " " << style::Variable << name;
         },
         [&](const sem::ValueExpression* val_expr) {
             text << "value of type " << style::Type << val_expr->Type()->FriendlyName();
diff --git a/src/tint/lang/wgsl/resolver/subgroups_extension_test.cc b/src/tint/lang/wgsl/resolver/subgroups_extension_test.cc
index e8e784f..7fdb6c1 100644
--- a/src/tint/lang/wgsl/resolver/subgroups_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/subgroups_extension_test.cc
@@ -48,7 +48,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(error: use of @builtin(subgroup_size) attribute requires enabling extension 'chromium_experimental_subgroups')");
+        R"(error: use of '@builtin(subgroup_size)' attribute requires enabling extension 'chromium_experimental_subgroups')");
 }
 
 // Using a subgroup_invocation_id builtin attribute without chromium_experimental_subgroups enabled
@@ -62,7 +62,7 @@
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(
         r()->error(),
-        R"(error: use of @builtin(subgroup_invocation_id) attribute requires enabling extension 'chromium_experimental_subgroups')");
+        R"(error: use of '@builtin(subgroup_invocation_id)' attribute requires enabling extension 'chromium_experimental_subgroups')");
 }
 
 // Using an i32 for a subgroup_size builtin input should fail.
@@ -74,7 +74,7 @@
               });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "error: store type of @builtin(subgroup_size) must be 'u32'");
+    EXPECT_EQ(r()->error(), "error: store type of '@builtin(subgroup_size)' must be 'u32'");
 }
 
 // Using an i32 for a subgroup_invocation_id builtin input should fail.
@@ -86,7 +86,8 @@
               });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "error: store type of @builtin(subgroup_invocation_id) must be 'u32'");
+    EXPECT_EQ(r()->error(),
+              "error: store type of '@builtin(subgroup_invocation_id)' must be 'u32'");
 }
 
 // Using builtin(subgroup_size) for anything other than a compute shader input should fail.
@@ -98,7 +99,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "error: @builtin(subgroup_size) is only valid as a compute shader input");
+              "error: '@builtin(subgroup_size)' is only valid as a compute shader input");
 }
 
 // Using builtin(subgroup_invocation_id) for anything other than a compute shader input should fail.
@@ -110,7 +111,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "error: @builtin(subgroup_invocation_id) is only valid as a compute shader input");
+              "error: '@builtin(subgroup_invocation_id)' is only valid as a compute shader input");
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/resolver/type_validation_test.cc b/src/tint/lang/wgsl/resolver/type_validation_test.cc
index f89f25c..8d191a8 100644
--- a/src/tint/lang/wgsl/resolver/type_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/type_validation_test.cc
@@ -384,7 +384,7 @@
     GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), "size"), core::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
@@ -396,7 +396,7 @@
               core::AddressSpace::kWorkgroup);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
@@ -409,7 +409,7 @@
     Structure("S", Vector{Member("a", ty.array(Source{{12, 34}}, ty.f32(), "size"))});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
@@ -425,7 +425,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
@@ -441,7 +441,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
@@ -459,7 +459,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
@@ -477,7 +477,7 @@
          });
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: array with an 'override' element count can only be used as the store "
+              "12:34 error: 'array' with an 'override' element count can only be used as the store "
               "type of a 'var<workgroup>'");
 }
 
diff --git a/src/tint/lang/wgsl/resolver/validation_test.cc b/src/tint/lang/wgsl/resolver/validation_test.cc
index a3c74fd..809ade9 100644
--- a/src/tint/lang/wgsl/resolver/validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/validation_test.cc
@@ -1194,7 +1194,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @align value must be a positive, power-of-two integer)");
+              R"(12:34 error: '@align' value must be a positive, power-of-two integer)");
 }
 
 TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
@@ -1204,7 +1204,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @align value must be a positive, power-of-two integer)");
+              R"(12:34 error: '@align' value must be a positive, power-of-two integer)");
 }
 
 TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) {
@@ -1214,7 +1214,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(12:34 error: @align value must be a positive, power-of-two integer)");
+              R"(12:34 error: '@align' value must be a positive, power-of-two integer)");
 }
 
 TEST_F(ResolverValidationTest, ZeroStructMemberSizeAttribute) {
@@ -1223,7 +1223,8 @@
                    });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @size must be at least as big as the type's size (4))");
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: '@size' must be at least as big as the type's size (4))");
 }
 
 TEST_F(ResolverValidationTest, OffsetAndSizeAttribute) {
@@ -1233,7 +1234,7 @@
                    });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @offset cannot be used with @align or @size)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@offset' cannot be used with '@align' or '@size')");
 }
 
 TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) {
@@ -1243,7 +1244,7 @@
                    });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @offset cannot be used with @align or @size)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@offset' cannot be used with '@align' or '@size')");
 }
 
 TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) {
@@ -1253,7 +1254,7 @@
                    });
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), R"(12:34 error: @offset cannot be used with @align or @size)");
+    EXPECT_EQ(r()->error(), R"(12:34 error: '@offset' cannot be used with '@align' or '@size')");
 }
 
 TEST_F(ResolverTest, Expr_Initializer_Cast_Pointer) {
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index bf18b93..9546c27 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -88,6 +88,8 @@
 #include "src/tint/utils/math/math.h"
 #include "src/tint/utils/text/string.h"
 #include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/text_style.h"
 
 using namespace tint::core::fluent_types;  // NOLINT
 
@@ -134,11 +136,6 @@
     }
 }
 
-// Helper to stringify a pipeline IO attribute.
-StyledText AttrToStr(const ast::Attribute* attr) {
-    return StyledText{} << "@" << attr->Name();
-}
-
 template <typename CALLBACK>
 void TraverseCallChain(const sem::Function* from, const sem::Function* to, CALLBACK&& callback) {
     for (auto* f : from->TransitivelyCalledFunctions()) {
@@ -312,9 +309,10 @@
     for (auto pair : incompatible) {
         if (enabled_extensions_.Contains(pair.first) && enabled_extensions_.Contains(pair.second)) {
             AddError(source_of(pair.first))
-                << "extension '" << pair.first << "' cannot be used with extension '" << pair.second
-                << "'";
-            AddNote(source_of(pair.second)) << "'" << pair.second << "' enabled here";
+                << "extension " << style::Code << pair.first << style::Plain
+                << " cannot be used with extension " << style::Code << pair.second;
+            AddNote(source_of(pair.second))
+                << style::Code << pair.second << style::Plain << " enabled here";
             return false;
         }
     }
@@ -431,8 +429,8 @@
                             const core::type::Type* from,
                             const Source& source) const {
     if (core::type::Type::ConversionRank(from, to) == core::type::Type::kNoConversion) {
-        AddError(source) << "cannot convert value of type '" << sem_.TypeNameOf(from)
-                         << "' to type '" << sem_.TypeNameOf(to) << "'";
+        AddError(source) << "cannot convert value of type " << style::Type << sem_.TypeNameOf(from)
+                         << style::Plain << " to type " << style::Type << sem_.TypeNameOf(to);
         return false;
     }
     return true;
@@ -446,9 +444,10 @@
 
     // Value type has to match storage type
     if (storage_ty != value_type) {
-        AddError(v->source) << "cannot initialize " << v->Kind() << " of type '"
-                            << sem_.TypeNameOf(storage_ty) << "' with value of type '"
-                            << sem_.TypeNameOf(initializer_ty) << "'";
+        AddError(v->source) << "cannot initialize " << style::Keyword << v->Kind() << style::Plain
+                            << " of type " << style::Type << sem_.TypeNameOf(storage_ty)
+                            << style::Plain << " with value of type " << style::Type
+                            << sem_.TypeNameOf(initializer_ty);
         return false;
     }
 
@@ -490,16 +489,18 @@
     }
 
     auto note_usage = [&] {
-        AddNote(source) << "'" << store_ty->FriendlyName() << "' used in address space '"
-                        << address_space << "' here";
+        AddNote(source) << style::Type << store_ty->FriendlyName() << style::Plain
+                        << " used in address space " << style::Enum << address_space << style::Plain
+                        << " here";
     };
 
     // Among three host-shareable address spaces, f16 is supported in "uniform" and
     // "storage" address space, but not "push_constant" address space yet.
     if (Is<core::type::F16>(store_ty->DeepestElement()) &&
         address_space == core::AddressSpace::kPushConstant) {
-        AddError(source)
-            << "using f16 types in 'push_constant' address space is not implemented yet";
+        AddError(source) << "using " << style::Type << "f16" << style::Plain << " in "
+                         << style::Enum << "push_constant" << style::Plain
+                         << " address space is not implemented yet";
         return false;
     }
 
@@ -520,12 +521,14 @@
                 !enabled_extensions_.Contains(
                     wgsl::Extension::kChromiumInternalRelaxedUniformLayout)) {
                 AddError(m->Declaration()->source)
-                    << "the offset of a struct member of type '"
-                    << m->Type()->UnwrapRef()->FriendlyName() << "' in address space '"
-                    << address_space << "' must be a multiple of " << required_align
-                    << " bytes, but '" << member_name_of(m) << "' is currently at offset "
-                    << m->Offset() << ". Consider setting @align(" << required_align
-                    << ") on this member";
+                    << "the offset of a struct member of type " << style::Type
+                    << m->Type()->UnwrapRef()->FriendlyName() << style::Plain
+                    << " in address space " << style::Enum << address_space << style::Plain
+                    << " must be a multiple of " << required_align << " bytes, but "
+                    << style::Variable << member_name_of(m) << style::Plain
+                    << " is currently at offset " << m->Offset() << ". Consider setting "
+                    << style::Attribute << "@align" << style::Code << "(" << required_align << ")"
+                    << style::Plain << " on this member";
 
                 AddNote(str->Declaration()->source) << "see layout of struct:\n" << str->Layout();
 
@@ -547,12 +550,15 @@
                     !enabled_extensions_.Contains(
                         wgsl::Extension::kChromiumInternalRelaxedUniformLayout)) {
                     AddError(m->Declaration()->source)
-                        << "uniform storage requires that the number of bytes between the start of "
-                           "the previous member of type struct and the current member be a "
+                        << style::Enum << "uniform" << style::Plain
+                        << " storage requires that the number of bytes between the start of the "
+                           "previous member of type struct and the current member be a "
                            "multiple of 16 bytes, but there are currently "
-                        << prev_to_curr_offset << " bytes between '" << member_name_of(prev_member)
-                        << "' and '" << member_name_of(m)
-                        << "'. Consider setting @align(16) on this member";
+                        << prev_to_curr_offset << " bytes between " << style::Variable
+                        << member_name_of(prev_member) << style::Plain << " and " << style::Variable
+                        << member_name_of(m) << style::Plain << ". Consider setting "
+                        << style::Attribute << "@align" << style::Code << "(16)" << style::Plain
+                        << " on this member";
 
                     AddNote(str->Declaration()->source) << "see layout of struct:\n"
                                                         << str->Layout();
@@ -585,23 +591,24 @@
             if (arr->Stride() % 16 != 0) {
                 // Since WGSL has no stride attribute, try to provide a useful hint for how the
                 // shader author can resolve the issue.
-                std::string_view hint;
+                StyledText hint;
                 if (arr->ElemType()->Is<core::type::Scalar>()) {
-                    hint = "Consider using a vector or struct as the element type instead.";
+                    hint << "Consider using a vector or struct as the element type instead.";
                 } else if (auto* vec = arr->ElemType()->As<core::type::Vector>();
                            vec && vec->type()->Size() == 4) {
-                    hint = "Consider using a vec4 instead.";
+                    hint << "Consider using a vec4 instead.";
                 } else if (arr->ElemType()->Is<sem::Struct>()) {
-                    hint = "Consider using the @size attribute on the last struct member.";
+                    hint << "Consider using the " << style::Attribute << "@size" << style::Plain
+                         << " attribute on the last struct member.";
                 } else {
-                    hint =
-                        "Consider wrapping the element type in a struct and using the @size "
-                        "attribute.";
+                    hint << "Consider wrapping the element type in a struct and using the "
+                         << style::Attribute << "@size" << style::Plain << " attribute.";
                 }
-                AddError(source) << "uniform storage requires that array elements are aligned to "
-                                    "16 bytes, but array element of type '"
-                                 << arr->ElemType()->FriendlyName() << "' has a stride of "
-                                 << arr->Stride() << " bytes. " << hint;
+                AddError(source) << style::Enum << "uniform" << style::Plain
+                                 << " storage requires that array elements are aligned to "
+                                    "16 bytes, but array element of type "
+                                 << style::Type << arr->ElemType()->FriendlyName() << style::Plain
+                                 << " has a stride of " << arr->Stride() << " bytes. " << hint;
                 return false;
             }
         }
@@ -624,7 +631,8 @@
                                     ast::DisabledValidation::kIgnoreAddressSpace)) {
                 if (!local->Type()->UnwrapRef()->IsConstructible()) {
                     AddError(var->type ? var->type->source : var->source)
-                        << "function-scope 'var' must have a constructible type";
+                        << "function-scope " << style::Keyword << "var" << style::Plain
+                        << " must have a constructible type";
                     return false;
                 }
             }
@@ -651,13 +659,15 @@
             if (auto* init = global->Initializer();
                 init && init->Stage() > core::EvaluationStage::kOverride) {
                 AddError(init->Declaration()->source)
-                    << "module-scope 'var' initializer must be a constant or "
+                    << "module-scope " << style::Keyword << "var" << style::Plain
+                    << " initializer must be a constant or "
                        "override-expression";
                 return false;
             }
 
             if (!var->declared_address_space && !global->Type()->UnwrapRef()->is_handle()) {
-                AddError(decl->source) << "module-scope 'var' declarations that are not of texture "
+                AddError(decl->source) << "module-scope " << style::Keyword << "var" << style::Plain
+                                       << " declarations that are not of texture "
                                           "or sampler types must "
                                           "provide an address space";
                 return false;
@@ -674,7 +684,8 @@
     }
 
     if (global->AddressSpace() == core::AddressSpace::kFunction) {
-        AddError(decl->source) << "module-scope 'var' must not use address space 'function'";
+        AddError(decl->source) << "module-scope " << style::Keyword << "var" << style::Plain
+                               << " must not use address space " << style::Enum << "function";
         return false;
     }
 
@@ -686,7 +697,8 @@
             // Each resource variable must be declared with both group and binding attributes.
             if (!decl->HasBindingPoint()) {
                 AddError(decl->source)
-                    << "resource variables require @group and @binding attributes";
+                    << "resource variables require " << style::Attribute << "@group" << style::Plain
+                    << " and " << style::Attribute << "@binding" << style::Plain << " attributes";
                 return false;
             }
             break;
@@ -698,7 +710,9 @@
                 // https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
                 // Must only be applied to a resource variable
                 AddError(decl->source)
-                    << "non-resource variables must not have @group or @binding attributes";
+                    << "non-resource variables must not have " << style::Attribute << "@group"
+                    << style::Plain << " or " << style::Attribute << "@binding" << style::Plain
+                    << " attributes";
                 return false;
             }
         }
@@ -721,8 +735,8 @@
         // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
         // If the store type is a texture type or a sampler type, then the variable declaration must
         // not have a address space attribute. The address space will always be handle.
-        AddError(var->source) << "variables of type '" << sem_.TypeNameOf(store_ty)
-                              << "' must not specifiy an address space";
+        AddError(var->source) << "variables of type " << style::Type << sem_.TypeNameOf(store_ty)
+                              << style::Plain << " must not specifiy an address space";
         return false;
     }
 
@@ -748,9 +762,11 @@
                 // Optionally has an initializer expression, if the variable is in the private or
                 // function address spaces.
                 AddError(var->source)
-                    << "var of address space '" << v->AddressSpace()
-                    << "' cannot have an initializer. var initializers are only supported for "
-                       "the address spaces 'private' and 'function'";
+                    << "var of address space " << style::Enum << v->AddressSpace() << style::Plain
+                    << " cannot have an initializer. var initializers are only supported for "
+                       "the address spaces "
+                    << style::Enum << "private" << style::Plain << " and " << style::Enum
+                    << "function";
                 return false;
         }
     }
@@ -774,8 +790,8 @@
     auto* storage_ty = v->Type()->UnwrapRef();
 
     if (!(storage_ty->IsConstructible() || storage_ty->Is<core::type::Pointer>())) {
-        AddError(decl->source) << sem_.TypeNameOf(storage_ty)
-                               << " cannot be used as the type of a 'let'";
+        AddError(decl->source) << sem_.TypeNameOf(storage_ty) << " cannot be used as the type of a "
+                               << style::Keyword << "let";
         return false;
     }
     return true;
@@ -787,24 +803,25 @@
     auto* storage_ty = v->Type()->UnwrapRef();
 
     if (auto* init = v->Initializer(); init && init->Stage() > core::EvaluationStage::kOverride) {
-        AddError(init->Declaration()->source)
-            << "'override' initializer must be an override-expression";
+        AddError(init->Declaration()->source) << style::Keyword << "override" << style::Plain
+                                              << " initializer must be an override-expression";
         return false;
     }
 
     if (auto id = v->Attributes().override_id) {
         if (auto var = override_ids.Get(*id); var && *var != v) {
             auto* attr = ast::GetAttribute<ast::IdAttribute>(v->Declaration()->attributes);
-            AddError(attr->source) << "@id values must be unique";
+            AddError(attr->source)
+                << style::Attribute << "@id" << style::Plain << " values must be unique";
             AddNote(ast::GetAttribute<ast::IdAttribute>((*var)->Declaration()->attributes)->source)
-                << "a override with an ID of " << id->value << " was previously declared here:";
+                << "a override with an ID of " << id->value << " was previously declared here";
             return false;
         }
     }
 
     if (!storage_ty->Is<core::type::Scalar>()) {
-        AddError(decl->source) << sem_.TypeNameOf(storage_ty)
-                               << " cannot be used as the type of a 'override'";
+        AddError(decl->source) << sem_.TypeNameOf(storage_ty) << " cannot be used as the type of a "
+                               << style::Keyword << "override";
         return false;
     }
 
@@ -842,8 +859,8 @@
                     break;
             }
             if (!ok) {
-                AddError(decl->source) << "function parameter of pointer type cannot be in '" << sc
-                                       << "' address space";
+                AddError(decl->source) << "function parameter of pointer type cannot be in "
+                                       << style::Enum << sc << style::Plain << " address space";
                 return false;
             }
         }
@@ -874,6 +891,13 @@
     bool is_stage_mismatch = false;
     bool is_output = !is_input;
     auto builtin = sem_.Get(attr)->Value();
+
+    auto err_builtin_type = [&](const char* required) {
+        AddError(attr->source) << "store type of " << style::Attribute << "@builtin" << style::Code
+                               << "(" << style::Enum << builtin << style::Code << ")"
+                               << style::Plain << " must be " << style::Type << required;
+    };
+
     switch (builtin) {
         case core::BuiltinValue::kPosition: {
             if (stage != ast::PipelineStage::kNone &&
@@ -883,8 +907,7 @@
             }
             auto* vec = type->As<core::type::Vector>();
             if (!(vec && vec->Width() == 4 && vec->type()->Is<core::type::F32>())) {
-                AddError(attr->source)
-                    << "store type of @builtin(" << builtin << ") must be 'vec4<f32>'";
+                err_builtin_type("vec4<f32>");
                 return false;
             }
             break;
@@ -899,8 +922,7 @@
             }
             if (!(type->is_unsigned_integer_vector() &&
                   type->As<core::type::Vector>()->Width() == 3)) {
-                AddError(attr->source)
-                    << "store type of @builtin(" << builtin << ") must be 'vec3<u32>'";
+                err_builtin_type("vec3<u32>");
                 return false;
             }
             break;
@@ -910,7 +932,7 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<core::type::F32>()) {
-                AddError(attr->source) << "store type of @builtin(" << builtin << ") must be 'f32'";
+                err_builtin_type("f32");
                 return false;
             }
             break;
@@ -920,8 +942,7 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<core::type::Bool>()) {
-                AddError(attr->source)
-                    << "store type of @builtin(" << builtin << ") must be 'bool'";
+                err_builtin_type("bool");
                 return false;
             }
             break;
@@ -931,7 +952,7 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<core::type::U32>()) {
-                AddError(attr->source) << "store type of @builtin(" << builtin << ") must be 'u32'";
+                err_builtin_type("u32");
                 return false;
             }
             break;
@@ -942,7 +963,7 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<core::type::U32>()) {
-                AddError(attr->source) << "store type of @builtin(" << builtin << ") must be 'u32'";
+                err_builtin_type("u32");
                 return false;
             }
             break;
@@ -951,7 +972,7 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<core::type::U32>()) {
-                AddError(attr->source) << "store type of @builtin(" << builtin << ") must be 'u32'";
+                err_builtin_type("u32");
                 return false;
             }
             break;
@@ -961,25 +982,28 @@
                 is_stage_mismatch = true;
             }
             if (!type->Is<core::type::U32>()) {
-                AddError(attr->source) << "store type of @builtin(" << builtin << ") must be 'u32'";
+                err_builtin_type("u32");
                 return false;
             }
             break;
         case core::BuiltinValue::kSubgroupInvocationId:
         case core::BuiltinValue::kSubgroupSize:
             if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumExperimentalSubgroups)) {
-                AddError(attr->source)
-                    << "use of @builtin(" << builtin
-                    << ") attribute requires enabling extension 'chromium_experimental_subgroups'";
+                AddError(attr->source) << "use of " << style::Attribute << "@builtin" << style::Code
+                                       << "(" << style::Enum << builtin << style::Code << ")"
+                                       << style::Plain << " attribute requires enabling extension "
+                                       << style::Code << "chromium_experimental_subgroups";
                 return false;
             }
             if (!type->Is<core::type::U32>()) {
-                AddError(attr->source) << "store type of @builtin(" << builtin << ") must be 'u32'";
+                err_builtin_type("u32");
                 return false;
             }
             if (stage != ast::PipelineStage::kNone && stage != ast::PipelineStage::kCompute) {
                 AddError(attr->source)
-                    << "@builtin(" << builtin << ") is only valid as a compute shader input";
+                    << style::Attribute << "@builtin" << style::Code << "(" << style::Enum
+                    << builtin << style::Code << ")" << style::Plain
+                    << " is only valid as a compute shader input";
                 return false;
             }
             break;
@@ -988,8 +1012,10 @@
     }
 
     if (is_stage_mismatch) {
-        AddError(attr->source) << "@builtin(" << builtin << ") cannot be used for "
-                               << stage_name.str() << " shader " << (is_input ? "input" : "output");
+        AddError(attr->source) << style::Attribute << "@builtin" << style::Code << "("
+                               << style::Enum << builtin << style::Code << ")" << style::Plain
+                               << " cannot be used for " << stage_name.str() << " shader "
+                               << (is_input ? "input" : "output");
         return false;
     }
 
@@ -1000,7 +1026,8 @@
                                      const core::type::Type* storage_ty,
                                      const ast::PipelineStage stage) const {
     if (stage == ast::PipelineStage::kCompute) {
-        AddError(attr->source) << AttrToStr(attr) << " cannot be used by compute shaders";
+        AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+                               << " cannot be used by compute shaders";
         return false;
     }
 
@@ -1012,8 +1039,8 @@
     }
 
     if (type->is_integer_scalar_or_vector() && i_type->Value() != core::InterpolationType::kFlat) {
-        AddError(attr->source)
-            << "interpolation type must be 'flat' for integral user-defined IO types";
+        AddError(attr->source) << "interpolation type must be " << style::Enum << "flat"
+                               << style::Plain << " for integral user-defined IO types";
         return false;
     }
 
@@ -1028,7 +1055,8 @@
 bool Validator::InvariantAttribute(const ast::InvariantAttribute* attr,
                                    const ast::PipelineStage stage) const {
     if (stage == ast::PipelineStage::kCompute) {
-        AddError(attr->source) << AttrToStr(attr) << " cannot be used by compute shaders";
+        AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+                               << " cannot be used by compute shaders";
         return false;
     }
     return true;
@@ -1042,7 +1070,8 @@
             attr,  //
             [&](const ast::WorkgroupAttribute*) {
                 if (decl->PipelineStage() != ast::PipelineStage::kCompute) {
-                    AddError(attr->source) << "@workgroup_size is only valid for compute stages";
+                    AddError(attr->source) << style::Attribute << "@workgroup_size" << style::Plain
+                                           << " is only valid for compute stages";
                     return false;
                 }
                 return true;
@@ -1050,7 +1079,8 @@
             [&](const ast::MustUseAttribute*) {
                 if (func->ReturnType()->Is<core::type::Void>()) {
                     AddError(attr->source)
-                        << "@must_use can only be applied to functions that return a value";
+                        << style::Attribute << "@must_use" << style::Plain
+                        << " can only be applied to functions that return a value";
                     return false;
                 }
                 return true;
@@ -1085,7 +1115,7 @@
             }
         } else if (TINT_UNLIKELY(IsValidationEnabled(
                        decl->attributes, ast::DisabledValidation::kFunctionHasNoBody))) {
-            TINT_ICE() << "Function " << decl->name->symbol.Name() << " has no body";
+            TINT_ICE() << "function " << decl->name->symbol.Name() << " has no body";
         }
     }
 
@@ -1150,14 +1180,17 @@
                     if (pipeline_io_attribute) {
                         AddError(attr->source) << "multiple entry point IO attributes";
                         AddNote(pipeline_io_attribute->source)
-                            << "previously consumed " << AttrToStr(pipeline_io_attribute);
+                            << "previously consumed " << style::Attribute << "@"
+                            << pipeline_io_attribute->Name();
                         return false;
                     }
                     pipeline_io_attribute = attr;
 
                     if (builtins.Contains(builtin)) {
                         AddError(decl->source)
-                            << "@builtin(" << builtin << ") appears multiple times as pipeline "
+                            << style::Attribute << "@builtin" << style::Code << "(" << style::Enum
+                            << builtin << style::Code << ")" << style::Plain
+                            << " appears multiple times as pipeline "
                             << (param_or_ret == ParamOrRetType::kParameter ? "input" : "output");
                         return false;
                     }
@@ -1175,7 +1208,8 @@
                     if (pipeline_io_attribute) {
                         AddError(attr->source) << "multiple entry point IO attributes";
                         AddNote(pipeline_io_attribute->source)
-                            << "previously consumed " << AttrToStr(pipeline_io_attribute);
+                            << "previously consumed " << style::Attribute << "@"
+                            << pipeline_io_attribute->Name();
                         return false;
                     }
                     pipeline_io_attribute = attr;
@@ -1202,7 +1236,8 @@
                     if (pipeline_io_attribute) {
                         AddError(attr->source) << "multiple entry point IO attributes";
                         AddNote(pipeline_io_attribute->source)
-                            << "previously consumed " << AttrToStr(pipeline_io_attribute);
+                            << "previously consumed " << style::Attribute << "@"
+                            << pipeline_io_attribute->Name();
                         return false;
                     }
                     pipeline_io_attribute = attr;
@@ -1251,15 +1286,17 @@
                     if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
                         param_or_ret == ParamOrRetType::kReturnType) {
                         AddError(source) << "integral user-defined vertex outputs must have a "
-                                            "flat interpolation "
-                                            "attribute";
+                                         << style::Attribute << "@interpolate" << style::Code << "("
+                                         << style::Enum << "flat" << style::Code << ")"
+                                         << style::Plain << " attribute";
                         return false;
                     }
                     if (decl->PipelineStage() == ast::PipelineStage::kFragment &&
                         param_or_ret == ParamOrRetType::kParameter) {
-                        AddError(source) << "integral user-defined fragment inputs must have "
-                                            "a flat interpolation "
-                                            "attribute";
+                        AddError(source) << "integral user-defined fragment inputs must have a "
+                                         << style::Attribute << "@interpolate" << style::Code << "("
+                                         << style::Enum << "flat" << style::Code << ")"
+                                         << style::Plain << " attribute";
                         return false;
                     }
                 }
@@ -1271,7 +1308,9 @@
                 // in the backend writers.
                 if (location.value_or(1) != 0) {
                     AddError(blend_src_attribute->source)
-                        << "@blend_src can only be used with @location(0)";
+                        << style::Attribute << "@blend_src" << style::Plain
+                        << " can only be used with " << style::Attribute << "@location"
+                        << style::Code << "(" << style::Literal << "0" << style::Code << ")";
                     return false;
                 }
             }
@@ -1284,10 +1323,12 @@
 
             if (first_blend_src && first_location_without_blend_src) {
                 AddError(first_location_without_blend_src->source)
-                    << "use of @blend_src requires all the output @location "
-                       "attributes of the entry "
-                       "point to be paired with a @blend_src attribute";
-                AddNote(first_blend_src->source) << "use of @blend_src here";
+                    << "use of " << style::Attribute << "@blend_src" << style::Plain
+                    << " requires all the output " << style::Attribute << "@location"
+                    << style::Plain << " attributes of the entry point to be paired with a "
+                    << style::Attribute << "@blend_src" << style::Plain << " attribute";
+                AddNote(first_blend_src->source)
+                    << "use of " << style::Attribute << "@blend_src" << style::Plain << " here";
                 return false;
             }
 
@@ -1297,8 +1338,11 @@
                 }
                 if (first_nonzero_location && first_blend_src) {
                     AddError(first_blend_src->source)
-                        << "pipeline cannot use both a @blend_src and non-zero @location";
-                    AddNote(first_nonzero_location->source) << "non-zero @location declared here";
+                        << "pipeline cannot use both a " << style::Attribute << "@blend_src"
+                        << style::Plain << " and non-zero " << style::Attribute << "@location";
+                    AddNote(first_nonzero_location->source)
+                        << "non-zero " << style::Attribute << "@location" << style::Plain
+                        << " declared here";
                     return false;
                 }
 
@@ -1306,18 +1350,22 @@
                                                                      blend_src.value_or(0));
                 if (!locations_and_blend_srcs.Add(location_and_blend_src)) {
                     auto& err = AddError(location_attribute->source)
-                                << "@location(" << location.value() << ") ";
+                                << style::Attribute << "@location" << style::Code << "("
+                                << style::Literal << location.value() << style::Code << ")";
                     if (blend_src_attribute) {
-                        err << "@blend_src(" << blend_src.value() << ") ";
+                        err << style::Attribute << " @blend_src" << style::Code << "("
+                            << style::Literal << blend_src.value() << style::Code << ")";
                     }
-                    err << "appears multiple times";
+                    err << style::Plain << " appears multiple times";
                     return false;
                 }
             }
 
             if (color_attribute && !colors.Add(color.value())) {
                 AddError(color_attribute->source)
-                    << "@color(" << color.value() << ") appears multiple times";
+                    << style::Attribute << "@color" << style::Code << "(" << style::Literal
+                    << color.value() << style::Code << ")" << style::Plain
+                    << " appears multiple times";
                 return false;
             }
 
@@ -1325,7 +1373,8 @@
                 if (!pipeline_io_attribute ||
                     !pipeline_io_attribute->Is<ast::LocationAttribute>()) {
                     AddError(interpolate_attribute->source)
-                        << "@interpolate can only be used with @location";
+                        << style::Attribute << "@interpolate" << style::Plain
+                        << " can only be used with " << style::Attribute << "@location";
                     return false;
                 }
             }
@@ -1340,7 +1389,9 @@
                 }
                 if (!has_position) {
                     AddError(invariant_attribute->source)
-                        << "@invariant must be applied to a position builtin";
+                        << style::Attribute << "@invariant" << style::Plain
+                        << " must be applied to a " << style::Attribute << "@builtin" << style::Code
+                        << "(" << style::Enum << "position" << style::Code << ")";
                     return false;
                 }
             }
@@ -1366,8 +1417,8 @@
                             member->Declaration()->source, param_or_ret,
                             /*is_struct_member*/ true, member->Attributes().location,
                             member->Attributes().blend_src, member->Attributes().color)) {
-                        AddNote(decl->source)
-                            << "while analyzing entry point '" << decl->name->symbol.Name() << "'";
+                        AddNote(decl->source) << "while analyzing entry point " << style::Function
+                                              << decl->name->symbol.Name();
                         return false;
                     }
                 }
@@ -1418,16 +1469,16 @@
             }
         }
         if (!found) {
-            AddError(decl->source)
-                << "a vertex shader must include the 'position' builtin in its return type";
+            AddError(decl->source) << "a vertex shader must include the " << style::Enum
+                                   << "position" << style::Plain << " builtin in its return type";
             return false;
         }
     }
 
     if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
         if (!ast::HasAttribute<ast::WorkgroupAttribute>(decl->attributes)) {
-            AddError(decl->source)
-                << "a compute shader must include 'workgroup_size' in its attributes";
+            AddError(decl->source) << "a compute shader must include " << style::Attribute
+                                   << "@workgroup_size" << style::Plain << " in its attributes";
             return false;
         }
     }
@@ -1454,10 +1505,12 @@
             // resource interface of a given shader must not have the same group and binding values,
             // when considered as a pair of values.
             auto func_name = decl->name->symbol.Name();
-            AddError(var_decl->source) << "entry point '" << func_name
-                                       << "' references multiple variables that use the same "
-                                          "resource binding @group("
-                                       << bp->group << "), @binding(" << bp->binding << ")";
+            AddError(var_decl->source)
+                << "entry point " << style::Function << func_name << style::Plain
+                << " references multiple variables that use the same resource binding "
+                << style::Attribute << "@group" << style::Code << "(" << style::Literal << bp->group
+                << style::Code << ")" << style::Plain << ", " << style::Attribute << "@binding"
+                << style::Code << "(" << style::Literal << bp->binding << style::Code << ")";
             AddNote(added.value->source) << "first resource binding usage declared here";
             return false;
         }
@@ -1494,7 +1547,8 @@
         if (auto* stmt = expr->Stmt()) {
             if (auto* decl = As<ast::VariableDeclStatement>(stmt->Declaration())) {
                 if (decl->variable->Is<ast::Const>()) {
-                    AddNote(decl->source) << "consider changing 'const' to 'let'";
+                    AddNote(decl->source) << "consider changing " << style::Keyword << "const"
+                                          << style::Plain << " to " << style::Keyword << "let";
                 }
             }
         }
@@ -1570,13 +1624,14 @@
             call->Target(),  //
             [&](const sem::Function* fn) {
                 AddError(call->Declaration()->source)
-                    << "ignoring return value of function '"
-                    << fn->Declaration()->name->symbol.Name() + "' annotated with @must_use";
+                    << "ignoring return value of function " << style::Function
+                    << fn->Declaration()->name->symbol.Name() << style::Plain << " annotated with "
+                    << style::Attribute << "@must_use";
                 sem_.NoteDeclarationSource(fn->Declaration());
             },
             [&](const sem::BuiltinFn* b) {
                 AddError(call->Declaration()->source)
-                    << "ignoring return value of builtin '" << b->Fn() << "'";
+                    << "ignoring return value of builtin " << style::Function << b->Fn();
             },
             [&](const sem::ValueConversion*) {
                 AddError(call->Declaration()->source) << "value conversion evaluated but not used";
@@ -1690,7 +1745,8 @@
             // used instead.
             auto* builtin = call->Target()->As<sem::BuiltinFn>();
             AddError(call->Declaration()->source)
-                << "builtin function '" << builtin->Fn() << "' does not return a value";
+                << "builtin function " << style::Function << builtin->Fn() << style::Plain
+                << " does not return a value";
             return false;
         }
     }
@@ -1795,8 +1851,8 @@
     if (extension != wgsl::Extension::kUndefined) {
         if (!enabled_extensions_.Contains(extension)) {
             AddError(call->Declaration()->source)
-                << "cannot call built-in function '" << builtin->Fn() << "' without extension "
-                << extension;
+                << "cannot call built-in function " << style::Function << builtin->Fn()
+                << style::Plain << " without extension " << extension;
             return false;
         }
     }
@@ -1805,8 +1861,8 @@
     if (feature != wgsl::LanguageFeature::kUndefined) {
         if (!allowed_features_.features.count(feature)) {
             AddError(call->Declaration()->source)
-                << "built-in function '" << builtin->Fn() << "' requires the "
-                << wgsl::ToString(feature)
+                << "built-in function " << style::Function << builtin->Fn() << style::Plain
+                << " requires the " << style::Code << wgsl::ToString(feature) << style::Plain
                 << " language feature, which is not allowed in the current environment";
             return false;
         }
@@ -1818,7 +1874,8 @@
 bool Validator::CheckF16Enabled(const Source& source) const {
     // Validate if f16 type is allowed.
     if (!enabled_extensions_.Contains(wgsl::Extension::kF16)) {
-        AddError(source) << "f16 type used without 'f16' extension enabled";
+        AddError(source) << style::Type << "f16" << style::Plain << " type used without "
+                         << style::Code << "f16" << style::Plain << " extension enabled";
         return false;
     }
     return true;
@@ -1846,9 +1903,10 @@
         bool more = decl->args.Length() > target->Parameters().Length();
         AddError(decl->source) << "too "
                                << (more ? std::string("many") : std::string("few")) +
-                                      " arguments in call to '"
-                               << name << "', expected " << target->Parameters().Length()
-                               << ", got " << call->Arguments().Length();
+                                      " arguments in call to "
+                               << style::Function << name << style::Plain << ", expected "
+                               << target->Parameters().Length() << ", got "
+                               << call->Arguments().Length();
         return false;
     }
 
@@ -1859,10 +1917,10 @@
         auto* arg_type = sem_.TypeOf(arg_expr)->UnwrapRef();
 
         if (param_type != arg_type) {
-            AddError(arg_expr->source)
-                << "type mismatch for argument " << (i + 1) << " in call to '" << name
-                << "', expected '" << sem_.TypeNameOf(param_type) << "', got '"
-                << sem_.TypeNameOf(arg_type) << "'";
+            AddError(arg_expr->source) << "type mismatch for argument " << (i + 1) << " in call to "
+                                       << style::Function << name << style::Plain << ", expected "
+                                       << style::Type << sem_.TypeNameOf(param_type) << style::Plain
+                                       << ", got " << style::Type << sem_.TypeNameOf(arg_type);
             return false;
         }
 
@@ -1906,7 +1964,8 @@
             // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
             // If the called function does not return a value, a function call
             // statement should be used instead.
-            AddError(decl->source) << "function '" << name << "' does not return a value";
+            AddError(decl->source) << "function " << style::Function << name << style::Plain
+                                   << " does not return a value";
             return false;
         }
     }
@@ -1934,9 +1993,9 @@
             auto* value_ty = sem_.TypeOf(value);
             if (member->Type() != value_ty->UnwrapRef()) {
                 AddError(value->source)
-                    << "type in structure constructor does not match struct member type: expected '"
-                    << sem_.TypeNameOf(member->Type()) << "', found '" << sem_.TypeNameOf(value_ty)
-                    << "'";
+                    << "type in structure constructor does not match struct member type: expected "
+                    << style::Type << sem_.TypeNameOf(member->Type()) << style::Plain << ", found "
+                    << style::Type << sem_.TypeNameOf(value_ty);
                 return false;
             }
         }
@@ -1952,9 +2011,9 @@
         auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
         if (core::type::Type::ConversionRank(value_ty, elem_ty) ==
             core::type::Type::kNoConversion) {
-            AddError(value->source)
-                << "'" << sem_.TypeNameOf(value_ty) + "' cannot be used to construct an array of '"
-                << sem_.TypeNameOf(elem_ty) << "'";
+            AddError(value->source) << style::Type << sem_.TypeNameOf(value_ty) << style::Plain
+                                    << " cannot be used to construct an array of " << style::Type
+                                    << sem_.TypeNameOf(elem_ty);
             return false;
         }
     }
@@ -1992,7 +2051,10 @@
 
 bool Validator::Vector(const core::type::Type* el_ty, const Source& source) const {
     if (!el_ty->Is<core::type::Scalar>()) {
-        AddError(source) << "vector element type must be 'bool', 'f32', 'f16', 'i32' or 'u32'";
+        AddError(source) << "vector element type must be " << style::Type << "bool" << style::Plain
+                         << ", " << style::Type << "f32" << style::Plain << ", " << style::Type
+                         << "f16" << style::Plain << ", " << style::Type << "i32" << style::Plain
+                         << " or " << style::Type << "u32";
         return false;
     }
     return true;
@@ -2000,7 +2062,8 @@
 
 bool Validator::Matrix(const core::type::Type* el_ty, const Source& source) const {
     if (!el_ty->is_float_scalar()) {
-        AddError(source) << "matrix element type must be 'f32' or 'f16'";
+        AddError(source) << "matrix element type must be " << style::Type << "f32" << style::Plain
+                         << " or " << style::Type << "f16";
         return false;
     }
     return true;
@@ -2010,12 +2073,12 @@
     auto backtrace = [&](const sem::Function* func, const sem::Function* entry_point) {
         if (func != entry_point) {
             TraverseCallChain(entry_point, func, [&](const sem::Function* f) {
-                AddNote(f->Declaration()->source)
-                    << "called by function '" << f->Declaration()->name->symbol.Name() << "'";
+                AddNote(f->Declaration()->source) << "called by function " << style::Function
+                                                  << f->Declaration()->name->symbol.Name();
             });
             AddNote(entry_point->Declaration()->source)
-                << "called by entry point '" << entry_point->Declaration()->name->symbol.Name()
-                << "'";
+                << "called by entry point " << style::Function
+                << entry_point->Declaration()->name->symbol.Name();
         }
     };
 
@@ -2028,8 +2091,8 @@
                     break;
                 }
             }
-            AddError(source) << "var with '" << var->AddressSpace()
-                             << "' address space cannot be used by " << stage << " pipeline stage";
+            AddError(source) << "var with " << style::Enum << var->AddressSpace() << style::Plain
+                             << " address space cannot be used by " << stage << " pipeline stage";
             AddNote(var->Declaration()->source) << "variable is declared here";
             backtrace(func, entry_point);
             return false;
@@ -2236,8 +2299,9 @@
                 [&](const ast::StructMemberSizeAttribute*) {
                     if (!member->Type()->HasCreationFixedFootprint()) {
                         AddError(attr->source)
-                            << "@size can only be applied to members where the member's type size "
-                               "can be fully determined at shader creation time";
+                            << style::Attribute << "@size" << style::Plain
+                            << " can only be applied to members where the member's type size can "
+                               "be fully determined at shader creation time";
                         return false;
                     }
                     return true;
@@ -2250,7 +2314,8 @@
 
         if (invariant_attribute && !has_position) {
             AddError(invariant_attribute->source)
-                << "@invariant must be applied to a position builtin";
+                << style::Attribute << "@invariant" << style::Plain
+                << " must be applied to a position builtin";
             return false;
         }
 
@@ -2260,14 +2325,17 @@
             // backend writers.
             if (member->Attributes().location.value_or(1) != 0) {
                 AddError(blend_src_attribute->source)
-                    << "@blend_src can only be used with @location(0)";
+                    << style::Attribute << "@blend_src" << style::Plain << " can only be used with "
+                    << style::Attribute << "@location" << style::Code << "(" << style::Literal
+                    << "0" << style::Code << ")";
                 return false;
             }
         }
 
         if (interpolate_attribute && !location_attribute) {
             AddError(interpolate_attribute->source)
-                << "@interpolate can only be used with @location";
+                << style::Attribute << "@interpolate" << style::Plain << " can only be used with "
+                << style::Attribute << "@location";
             return false;
         }
 
@@ -2278,11 +2346,13 @@
 
             if (!locations_and_blend_srcs.Add(std::make_pair(location, blend_src))) {
                 auto& err = AddError(location_attribute->source)
-                            << "@location(" << location << ") ";
+                            << style::Attribute << "@location" << style::Code << "("
+                            << style::Literal << location << style::Code << ")";
                 if (blend_src) {
-                    err << "@blend_src(" << blend_src.value() << ") ";
+                    err << style::Attribute << " @blend_src" << style::Code << "(" << style::Literal
+                        << blend_src.value() << style::Code << ")";
                 }
-                err << "appears multiple times";
+                err << style::Plain << " appears multiple times";
                 return false;
             }
         }
@@ -2291,7 +2361,8 @@
             uint32_t color = member->Attributes().color.value();
             if (!colors.Add(color)) {
                 AddError(color_attribute->source)
-                    << "@color(" << color << ") appears multiple times";
+                    << style::Attribute << "@color" << style::Code << "(" << style::Literal << color
+                    << style::Code << ")" << style::Plain << " appears multiple times";
                 return false;
             }
         }
@@ -2305,16 +2376,18 @@
                                   ast::PipelineStage stage,
                                   const Source& source) const {
     if (stage == ast::PipelineStage::kCompute) {
-        AddError(attr->source) << AttrToStr(attr) << " cannot be used by compute shaders";
+        AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+                               << " cannot be used by compute shaders";
         return false;
     }
 
     if (!type->is_numeric_scalar_or_vector()) {
         std::string invalid_type = sem_.TypeNameOf(type);
-        AddError(source) << "cannot apply @location to declaration of type '" << invalid_type
-                         << "'";
-        AddNote(attr->source) << "@location must only be applied to declarations of numeric scalar "
-                                 "or numeric vector type";
+        AddError(source) << "cannot apply " << style::Attribute << "@location" << style::Plain
+                         << " to declaration of type " << style::Type << invalid_type;
+        AddNote(attr->source)
+            << style::Attribute << "@location" << style::Plain
+            << " must only be applied to declarations of numeric scalar or numeric vector type";
         return false;
     }
 
@@ -2327,8 +2400,9 @@
                                const Source& source,
                                const std::optional<bool> is_input) const {
     if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumExperimentalFramebufferFetch)) {
-        AddError(attr->source) << "use of @color requires enabling extension "
-                                  "'chromium_experimental_framebuffer_fetch'";
+        AddError(attr->source) << "use of " << style::Attribute << "@color" << style::Plain
+                               << " requires enabling extension " << style::Code
+                               << "chromium_experimental_framebuffer_fetch";
         return false;
     }
 
@@ -2336,15 +2410,18 @@
         stage != ast::PipelineStage::kNone && stage != ast::PipelineStage::kFragment;
     bool is_output = !is_input.value_or(true);
     if (is_stage_non_fragment || is_output) {
-        AddError(attr->source) << "@color can only be used for fragment shader input";
+        AddError(attr->source) << style::Attribute << "@color" << style::Plain
+                               << " can only be used for fragment shader input";
         return false;
     }
 
     if (!type->is_numeric_scalar_or_vector()) {
         std::string invalid_type = sem_.TypeNameOf(type);
-        AddError(source) << "cannot apply @color to declaration of type '" << invalid_type << "'";
-        AddNote(attr->source) << "@color must only be applied to declarations of numeric scalar or "
-                                 "numeric vector type";
+        AddError(source) << "cannot apply " << style::Attribute << "@color" << style::Plain
+                         << " to declaration of type " << style::Type << invalid_type;
+        AddNote(attr->source)
+            << style::Attribute << "@color" << style::Plain
+            << " must only be applied to declarations of numeric scalar or numeric vector type";
         return false;
     }
 
@@ -2355,8 +2432,9 @@
                                   ast::PipelineStage stage,
                                   const std::optional<bool> is_input) const {
     if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumInternalDualSourceBlending)) {
-        AddError(attr->source) << "use of @blend_src requires enabling extension "
-                                  "'chromium_internal_dual_source_blending'";
+        AddError(attr->source) << "use of " << style::Attribute << "@blend_src" << style::Plain
+                               << " requires enabling extension " << style::Code
+                               << "chromium_internal_dual_source_blending";
         return false;
     }
 
@@ -2364,7 +2442,8 @@
         stage != ast::PipelineStage::kNone && stage != ast::PipelineStage::kFragment;
     bool is_output = is_input.value_or(false);
     if (is_stage_non_fragment || is_output) {
-        AddError(attr->source) << AttrToStr(attr) << " can only be used for fragment shader output";
+        AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+                               << " can only be used for fragment shader output";
         return false;
     }
 
@@ -2377,8 +2456,9 @@
                        sem::Statement* current_statement) const {
     if (func_type->UnwrapRef() != ret_type) {
         AddError(ret->source)
-            << "return statement type must match its function return type, returned '"
-            << sem_.TypeNameOf(ret_type) << "', expected '" << sem_.TypeNameOf(func_type) << "'";
+            << "return statement type must match its function return type, returned " << style::Type
+            << sem_.TypeNameOf(ret_type) << style::Plain << ", expected " << style::Type
+            << sem_.TypeNameOf(func_type);
         return false;
     }
 
@@ -2480,9 +2560,11 @@
         if (!ty->IsConstructible() &&
             !ty->IsAnyOf<core::type::Pointer, core::type::Texture, core::type::Sampler,
                          core::type::AbstractNumeric>()) {
-            AddError(rhs->source) << "cannot assign '" << sem_.TypeNameOf(rhs_ty)
-                                  << "' to '_'. '_' can only be assigned a constructible, pointer, "
-                                     "texture or sampler type";
+            AddError(rhs->source)
+                << "cannot assign " << style::Type << sem_.TypeNameOf(rhs_ty) << style::Plain
+                << " to " << style::Code << "_" << style::Plain << ". " << style::Code << "_"
+                << style::Plain
+                << " can only be assigned a constructible, pointer, texture or sampler type";
             return false;
         }
         return true;  // RHS can be anything.
@@ -2551,7 +2633,7 @@
     }
     if (lhs_ref->Access() == core::Access::kRead) {
         AddError(a->source) << "cannot store into a read-only type " << style::Type
-                            << sem_.RawTypeNameOf(lhs_ty) << style::Plain;
+                            << sem_.RawTypeNameOf(lhs_ty);
         return false;
     }
     return true;
@@ -2564,14 +2646,22 @@
 
     if (auto* var_user = sem_.Get<sem::VariableUser>(lhs)) {
         auto* v = var_user->Variable()->Declaration();
-        const char* err = Switch(
+        bool errored = Switch(
             v,  //
-            [&](const ast::Parameter*) { return "cannot modify function parameter"; },
-            [&](const ast::Let*) { return "cannot modify 'let'"; },
-            [&](const ast::Override*) { return "cannot modify 'override'"; });
-        if (err) {
-            AddError(lhs->source) << err;
-            AddNote(v->source) << "'" << v->name->symbol.Name() << "' is declared here:";
+            [&](const ast::Parameter*) {
+                AddError(lhs->source) << "cannot modify function parameter";
+                return true;
+            },
+            [&](const ast::Let*) {
+                AddError(lhs->source) << "cannot modify " << style::Keyword << "let";
+                return true;
+            },
+            [&](const ast::Override*) {
+                AddError(lhs->source) << "cannot modify " << style::Keyword << "override";
+                return true;
+            });
+        if (errored) {
+            sem_.NoteDeclarationSource(v);
             return false;
         }
     }
@@ -2580,7 +2670,8 @@
     auto* lhs_ref = lhs_ty->As<core::type::Reference>();
     if (!lhs_ref) {
         // LHS is not a reference, so it has no storage.
-        AddError(lhs->source) << "cannot modify value of type '" << sem_.TypeNameOf(lhs_ty) << "'";
+        AddError(lhs->source) << "cannot modify value of type " << style::Type
+                              << sem_.TypeNameOf(lhs_ty);
         return false;
     }
 
@@ -2591,8 +2682,8 @@
     }
 
     if (lhs_ref->Access() == core::Access::kRead) {
-        AddError(inc->source) << "cannot modify read-only type '" << sem_.RawTypeNameOf(lhs_ty)
-                              << "'";
+        AddError(inc->source) << "cannot modify read-only type " << style::Type
+                              << sem_.RawTypeNameOf(lhs_ty);
         return false;
     }
     return true;
@@ -2630,8 +2721,8 @@
         if (!diag_added && diag_added.value->severity != dc->severity) {
             AddError(dc->rule_name->source) << "conflicting diagnostic " << use;
             AddNote(diag_added.value->rule_name->source)
-                << "severity of '" << dc->rule_name->String() << "' set to '" << dc->severity
-                << "' here";
+                << "severity of " << style::Code << dc->rule_name->String() << style::Plain
+                << " set to " << style::Code << dc->severity << style::Plain << " here";
             return false;
         }
     }
@@ -2665,9 +2756,11 @@
 }
 
 void Validator::RaiseArrayWithOverrideCountError(const Source& source) const {
-    AddError(source)
-        << "array with an 'override' element count can only be used as the store type of a "
-           "'var<workgroup>'";
+    AddError(source) << style::Type << "array" << style::Plain << " with an " << style::Keyword
+                     << "override" << style::Plain
+                     << " element count can only be used as the store type of a " << style::Keyword
+                     << "var" << style::Code << "<" << style::Enum << "workgroup" << style::Code
+                     << ">";
 }
 
 std::string Validator::VectorPretty(uint32_t size, const core::type::Type* element_type) const {
@@ -2691,15 +2784,21 @@
                     using Allowed = std::tuple<core::type::I32, core::type::U32, core::type::F32>;
                     if (TINT_UNLIKELY(!member->Type()->TypeInfo().IsAnyOfTuple<Allowed>())) {
                         AddError(member->Declaration()->source)
-                            << "struct members used in the 'pixel_local' address "
-                               "space can only be of the type 'i32', 'u32' or 'f32'";
-                        AddNote(source) << "struct '" << str->Name().Name()
-                                        << "' used in the 'pixel_local' address space here";
+                            << style::Keyword << "struct" << style::Plain << " members used in the "
+                            << style::Enum << "pixel_local" << style::Plain
+                            << " address space can only be of the type " << style::Type << "i32"
+                            << style::Plain << ", " << style::Type << "u32" << style::Plain
+                            << " or " << style::Type << "f32";
+                        AddNote(source)
+                            << style::Keyword << "struct " << style::Type << str->Name().Name()
+                            << style::Plain << " used in the " << style::Enum << "pixel_local"
+                            << style::Plain << " address space here";
                         return false;
                     }
                 }
             } else if (TINT_UNLIKELY(!store_ty->TypeInfo().Is<core::type::Struct>())) {
-                AddError(source) << "'pixel_local' variable only support struct storage types";
+                AddError(source) << style::Enum << "pixel_local" << style::Plain
+                                 << " variable only support struct storage types";
                 return false;
             }
             break;
@@ -2708,16 +2807,19 @@
                                   wgsl::Extension::kChromiumExperimentalPushConstant) &&
                               IsValidationEnabled(attributes,
                                                   ast::DisabledValidation::kIgnoreAddressSpace))) {
-                AddError(source) << "use of variable address space 'push_constant' requires "
-                                    "enabling extension 'chromium_experimental_push_constant'";
+                AddError(source) << "use of variable address space " << style::Enum
+                                 << "push_constant" << style::Plain
+                                 << " requires enabling extension " << style::Code
+                                 << "chromium_experimental_push_constant";
                 return false;
             }
             break;
         case core::AddressSpace::kStorage:
             if (TINT_UNLIKELY(access == core::Access::kWrite)) {
                 // The access mode for the storage address space can only be 'read' or 'read_write'.
-                AddError(source)
-                    << "access mode 'write' is not valid for the 'storage' address space";
+                AddError(source) << "access mode " << style::Enum << "write" << style::Plain
+                                 << " is not valid for the " << style::Enum << "storage"
+                                 << style::Plain << " address space";
                 return false;
             }
             break;
@@ -2725,24 +2827,30 @@
             break;
     }
 
-    auto atomic_error = [&]() -> const char* {
+    auto atomic_error = [&] {
         StyledText err;
         if (address_space != core::AddressSpace::kStorage &&
             address_space != core::AddressSpace::kWorkgroup) {
-            return "atomic variables must have <storage> or <workgroup> address space";
+            AddError(source) << style::Type << "atomic" << style::Plain << " variables must have "
+                             << style::Enum << "storage" << style::Plain << " or " << style::Enum
+                             << "workgroup" << style::Plain << " address space";
+            return true;
         }
         if (address_space == core::AddressSpace::kStorage && access != core::Access::kReadWrite) {
-            return "atomic variables in <storage> address space must have read_write access mode";
+            AddError(source) << "atomic variables in " << style::Enum << "storage" << style::Plain
+                             << " address space must have " << style::Enum << "read_write"
+                             << style::Plain << " access mode";
+            return true;
         }
-        return nullptr;
+        return false;
     };
 
     auto check_sub_atomics = [&] {
         if (auto atomic_use = atomic_composite_info_.Get(store_ty)) {
-            if (auto* err = atomic_error()) {
-                AddError(source) << err;
+            if (TINT_UNLIKELY(atomic_error())) {
                 AddNote(**atomic_use)
-                    << "atomic sub-type of '" << sem_.TypeNameOf(store_ty) << "' is declared here";
+                    << "atomic sub-type of " << style::Type << sem_.TypeNameOf(store_ty)
+                    << style::Plain << " is declared here";
                 return false;
             }
         }
@@ -2752,8 +2860,7 @@
     return Switch(
         store_ty,  //
         [&](const core::type::Atomic*) {
-            if (auto* err = atomic_error()) {
-                AddError(source) << err;
+            if (TINT_UNLIKELY(atomic_error())) {
                 return false;
             }
             return true;
@@ -2783,27 +2890,29 @@
             }
 
             AddError(ep->Declaration()->source)
-                << "entry point '" << ep->Declaration()->name->symbol.Name()
-                << "' uses two different '" << space << "' variables.";
-            AddNote(var->Declaration()->source)
-                << "first '" << space << "' variable declaration is here";
+                << "entry point " << style::Function << ep->Declaration()->name->symbol.Name()
+                << style::Plain << " uses two different " << style::Enum << space << style::Plain
+                << " variables.";
+            AddNote(var->Declaration()->source) << "first " << style::Enum << space << style::Plain
+                                                << " variable declaration is here";
             if (func != ep) {
                 TraverseCallChain(ep, func, [&](const sem::Function* f) {
-                    AddNote(f->Declaration()->source)
-                        << "called by function '" << f->Declaration()->name->symbol.Name() << "'";
+                    AddNote(f->Declaration()->source) << "called by function " << style::Function
+                                                      << f->Declaration()->name->symbol.Name();
                 });
-                AddNote(ep->Declaration()->source)
-                    << "called by entry point '" << ep->Declaration()->name->symbol.Name() << "'";
+                AddNote(ep->Declaration()->source) << "called by entry point " << style::Function
+                                                   << ep->Declaration()->name->symbol.Name();
             }
             AddNote(seen_var->Declaration()->source)
-                << "second '" << space << "' variable declaration is here";
+                << "second " << style::Enum << space << style::Plain
+                << " variable declaration is here";
             if (seen_func != ep) {
                 TraverseCallChain(ep, seen_func, [&](const sem::Function* f) {
-                    AddNote(f->Declaration()->source)
-                        << "called by function '" << f->Declaration()->name->symbol.Name() << "'";
+                    AddNote(f->Declaration()->source) << "called by function " << style::Function
+                                                      << f->Declaration()->name->symbol.Name();
                 });
-                AddNote(ep->Declaration()->source)
-                    << "called by entry point '" << ep->Declaration()->name->symbol.Name() << "'";
+                AddNote(ep->Declaration()->source) << "called by entry point " << style::Function
+                                                   << ep->Declaration()->name->symbol.Name();
             }
             return false;
         }
diff --git a/src/tint/lang/wgsl/resolver/variable_validation_test.cc b/src/tint/lang/wgsl/resolver/variable_validation_test.cc
index 10bc7ec..89179ce 100644
--- a/src/tint/lang/wgsl/resolver/variable_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/variable_validation_test.cc
@@ -190,7 +190,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(3:3 error: cannot initialize const of type 'i32' with value of type 'u32')");
+              R"(3:3 error: cannot initialize 'const' of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVariableValidationTest, LetInitializerWrongType) {
@@ -199,7 +199,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+              R"(3:3 error: cannot initialize 'let' of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVariableValidationTest, VarInitializerWrongType) {
@@ -208,7 +208,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+              R"(3:3 error: cannot initialize 'var' of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVariableValidationTest, ConstInitializerWrongTypeViaAlias) {
@@ -217,7 +217,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(3:3 error: cannot initialize const of type 'i32' with value of type 'u32')");
+              R"(3:3 error: cannot initialize 'const' of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVariableValidationTest, LetInitializerWrongTypeViaAlias) {
@@ -226,7 +226,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+              R"(3:3 error: cannot initialize 'let' of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVariableValidationTest, VarInitializerWrongTypeViaAlias) {
@@ -235,7 +235,7 @@
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+              R"(3:3 error: cannot initialize 'var' of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVariableValidationTest, LetOfPtrConstructedWithRef) {
@@ -250,7 +250,7 @@
 
     EXPECT_EQ(
         r()->error(),
-        R"(12:34 error: cannot initialize let of type 'ptr<function, f32, read_write>' with value of type 'f32')");
+        R"(12:34 error: cannot initialize 'let' of type 'ptr<function, f32, read_write>' with value of type 'f32')");
 }
 
 TEST_F(ResolverVariableValidationTest, LocalLetRedeclared) {
@@ -338,10 +338,9 @@
     WrapInFunction(ptr);
 
     EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: cannot initialize let of type "
-              "'ptr<storage, i32, read_write>' with value of type "
-              "'ptr<storage, i32, read>'");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: cannot initialize 'let' of type 'ptr<storage, i32, read_write>' with value of type 'ptr<storage, i32, read>')");
 }
 
 TEST_F(ResolverVariableValidationTest, NonConstructibleType_Atomic) {