Import Tint changes from Dawn
Changes:
- 710b62fdf1227d0da9c890b4d43f3f1c447f7fc9 [tint][wgsl] Migrate more resolver diagnostics over to St... by Ben Clayton <bclayton@google.com>
- c27315a48c5cd49e525c14d3bdee3f18bf1dc28e [tint] Use StyledText for all diagnostics by Ben Clayton <bclayton@google.com>
- 89549b14a2200f128a3025b317efff3efae194cb [tint] Add new StyledText utilities by Ben Clayton <bclayton@google.com>
- e4d210d69171910312fedb84f836653b4a9869a2 [tint][wgsl] Add 'chromium_internal_graphite' extension by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 710b62fdf1227d0da9c890b4d43f3f1c447f7fc9
Change-Id: Ib3929ed9cabc3f6b3069ce4c1c7b2bbec96aa4e0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/176760
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/include/tint/tint.h b/include/tint/tint.h
index 492f11b..23d1d3e 100644
--- a/include/tint/tint.h
+++ b/include/tint/tint.h
@@ -51,7 +51,7 @@
#include "src/tint/lang/wgsl/helpers/flatten_bindings.h"
#include "src/tint/lang/wgsl/inspector/inspector.h"
#include "src/tint/utils/diagnostic/formatter.h"
-#include "src/tint/utils/diagnostic/printer.h"
+#include "src/tint/utils/text/styled_text.h"
#if TINT_BUILD_SPV_READER
#include "src/tint/lang/spirv/reader/reader.h"
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index 4dd0ea1..c043588 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -46,8 +46,10 @@
#endif
#include "src/tint/utils/diagnostic/formatter.h"
-#include "src/tint/utils/diagnostic/printer.h"
#include "src/tint/utils/text/string.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/text_style.h"
#include "src/tint/utils/traits/traits.h"
namespace tint::cmd {
@@ -145,10 +147,10 @@
} // namespace
[[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err) {
- auto printer = diag::Printer::Create(stderr, true);
- diag::Style bold_red{diag::Color::kRed, true};
- printer->Write(err.Error(), bold_red);
- constexpr const char* please_file_bug = R"(
+ auto printer = StyledTextPrinter::Create(stderr);
+ StyledText msg;
+ msg << (style::Error + style::Bold) << err.Error();
+ msg << R"(
********************************************************************
* The tint shader compiler has encountered an unexpected error. *
* *
@@ -156,7 +158,7 @@
* crbug.com/tint with the source program that triggered the bug. *
********************************************************************
)";
- printer->Write(please_file_bug, bold_red);
+ printer->Print(msg);
exit(1);
}
@@ -267,9 +269,9 @@
PrintWGSL(std::cout, info.program);
}
- auto diag_printer = tint::diag::Printer::Create(stderr, true);
- tint::diag::Formatter diag_formatter;
- diag_formatter.Format(info.program.Diagnostics(), diag_printer.get());
+ auto printer = tint::StyledTextPrinter::Create(stderr);
+ tint::diag::Formatter formatter;
+ printer->Print(formatter.Format(info.program.Diagnostics()));
}
if (!info.program.IsValid()) {
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 8db9a64..947355e 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -56,10 +56,11 @@
#include "src/tint/utils/command/command.h"
#include "src/tint/utils/containers/transform.h"
#include "src/tint/utils/diagnostic/formatter.h"
-#include "src/tint/utils/diagnostic/printer.h"
#include "src/tint/utils/macros/defer.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/styled_text_printer.h"
#if TINT_BUILD_WGSL_READER
#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
@@ -789,9 +790,9 @@
auto source = std::make_unique<tint::Source::File>(options.input_filename, result->wgsl);
auto reparsed_program = tint::wgsl::reader::Parse(source.get(), parser_options);
if (!reparsed_program.IsValid()) {
- auto diag_printer = tint::diag::Printer::Create(stderr, true);
+ auto printer = tint::StyledTextPrinter::Create(stderr);
tint::diag::Formatter diag_formatter;
- diag_formatter.Format(reparsed_program.Diagnostics(), diag_printer.get());
+ printer->Print(diag_formatter.Format(reparsed_program.Diagnostics()));
return false;
}
}
diff --git a/src/tint/fuzzers/BUILD.gn b/src/tint/fuzzers/BUILD.gn
index bf83f01..3809954 100644
--- a/src/tint/fuzzers/BUILD.gn
+++ b/src/tint/fuzzers/BUILD.gn
@@ -101,6 +101,7 @@
"${tint_src_dir}/lang/wgsl/writer",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/text",
]
sources = [
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index a50ca8e..be3a673 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -51,8 +51,10 @@
#include "src/tint/lang/wgsl/program/program.h"
#include "src/tint/lang/wgsl/sem/variable.h"
#include "src/tint/utils/diagnostic/formatter.h"
-#include "src/tint/utils/diagnostic/printer.h"
#include "src/tint/utils/math/hash.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/text_style.h"
#if TINT_BUILD_SPV_WRITER
#include "src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h"
@@ -74,15 +76,14 @@
// to better de-duplication of bug reports, because ClusterFuzz only uses the
// top few stack frames for de-duplication, and a FATAL_ERROR stack frame
// provides no useful information.
-#define FATAL_ERROR(diags, msg_string) \
- do { \
- std::string msg = msg_string; \
- auto printer = tint::diag::Printer::Create(stderr, true); \
- if (!msg.empty()) { \
- printer->Write(msg + "\n", {diag::Color::kRed, true}); \
- } \
- tint::diag::Formatter().Format(diags, printer.get()); \
- __builtin_trap(); \
+#define FATAL_ERROR(diags, msg_string) \
+ do { \
+ StyledText msg; \
+ msg << (style::Error + style::Bold) << msg_string; \
+ auto printer = tint::StyledTextPrinter::Create(stderr); \
+ printer->Print(msg); \
+ printer->Print(tint::diag::Formatter().Format(diags)); \
+ __builtin_trap(); \
} while (false)
[[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err) {
@@ -117,13 +118,13 @@
const tint::diag::List& diags = program.Diagnostics();
tools.SetMessageConsumer(
[diags](spv_message_level_t, const char*, const spv_position_t& pos, const char* msg) {
- std::stringstream out;
+ StyledText out;
out << "Unexpected spirv-val error:\n"
- << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << std::endl;
+ << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg;
- auto printer = tint::diag::Printer::Create(stderr, true);
- printer->Write(out.str(), {diag::Color::kYellow, false});
- tint::diag::Formatter().Format(diags, printer.get());
+ auto printer = tint::StyledTextPrinter::Create(stderr);
+ printer->Print(out);
+ printer->Print(tint::diag::Formatter().Format(diags));
});
return tools.Validate(spirv.data(), spirv.size(), spvtools::ValidatorOptions());
diff --git a/src/tint/lang/core/constant/eval.cc b/src/tint/lang/core/constant/eval.cc
index 74b9022..0b78386 100644
--- a/src/tint/lang/core/constant/eval.cc
+++ b/src/tint/lang/core/constant/eval.cc
@@ -281,7 +281,7 @@
// [abstract-numeric -> x] - materialization failure
auto msg = OverflowErrorMessage(scalar->value, target_ty->FriendlyName());
if (ctx.use_runtime_semantics) {
- ctx.diags.AddWarning(tint::diag::System::Resolver, msg, ctx.source);
+ ctx.diags.AddWarning(tint::diag::System::Resolver, ctx.source) << msg;
switch (conv.Failure()) {
case ConversionFailure::kExceedsNegativeLimit:
return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Lowest());
@@ -289,7 +289,7 @@
return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Highest());
}
} else {
- ctx.diags.AddError(tint::diag::System::Resolver, msg, ctx.source);
+ ctx.diags.AddError(tint::diag::System::Resolver, ctx.source) << msg;
return nullptr;
}
} else if constexpr (IsFloatingPoint<TO>) {
@@ -297,7 +297,7 @@
// https://www.w3.org/TR/WGSL/#floating-point-conversion
auto msg = OverflowErrorMessage(scalar->value, target_ty->FriendlyName());
if (ctx.use_runtime_semantics) {
- ctx.diags.AddWarning(tint::diag::System::Resolver, msg, ctx.source);
+ ctx.diags.AddWarning(tint::diag::System::Resolver, ctx.source) << msg;
switch (conv.Failure()) {
case ConversionFailure::kExceedsNegativeLimit:
return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Lowest());
@@ -305,7 +305,7 @@
return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Highest());
}
} else {
- ctx.diags.AddError(tint::diag::System::Resolver, msg, ctx.source);
+ ctx.diags.AddError(tint::diag::System::Resolver, ctx.source) << msg;
return nullptr;
}
} else if constexpr (IsFloatingPoint<FROM>) {
@@ -648,7 +648,7 @@
if constexpr (IsFloatingPoint<T>) {
if (!std::isfinite(v.value)) {
- AddError(OverflowErrorMessage(v, t->FriendlyName()), source);
+ AddError(source) << OverflowErrorMessage(v, t->FriendlyName());
if (use_runtime_semantics_) {
return mgr.Zero(t);
} else {
@@ -666,7 +666,7 @@
if (auto r = CheckedAdd(a, b)) {
result = r->value;
} else {
- AddError(OverflowErrorMessage(a, "+", b), source);
+ AddError(source) << OverflowErrorMessage(a, "+", b);
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -696,7 +696,7 @@
if (auto r = CheckedSub(a, b)) {
result = r->value;
} else {
- AddError(OverflowErrorMessage(a, "-", b), source);
+ AddError(source) << OverflowErrorMessage(a, "-", b);
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -727,7 +727,7 @@
if (auto r = CheckedMul(a, b)) {
result = r->value;
} else {
- AddError(OverflowErrorMessage(a, "*", b), source);
+ AddError(source) << OverflowErrorMessage(a, "*", b);
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -756,7 +756,7 @@
if (auto r = CheckedDiv(a, b)) {
result = r->value;
} else {
- AddError(OverflowErrorMessage(a, "/", b), source);
+ AddError(source) << OverflowErrorMessage(a, "/", b);
if (use_runtime_semantics_) {
return a;
} else {
@@ -769,7 +769,7 @@
auto rhs = b.value;
if (rhs == 0) {
// For integers (as for floats), lhs / 0 is an error
- AddError(OverflowErrorMessage(a, "/", b), source);
+ AddError(source) << OverflowErrorMessage(a, "/", b);
if (use_runtime_semantics_) {
return a;
} else {
@@ -780,7 +780,7 @@
// For signed integers, lhs / -1 where lhs is the
// most negative value is an error
if (rhs == -1 && lhs == std::numeric_limits<T>::min()) {
- AddError(OverflowErrorMessage(a, "/", b), source);
+ AddError(source) << OverflowErrorMessage(a, "/", b);
if (use_runtime_semantics_) {
return a;
} else {
@@ -800,7 +800,7 @@
if (auto r = CheckedMod(a, b)) {
result = r->value;
} else {
- AddError(OverflowErrorMessage(a, "%", b), source);
+ AddError(source) << OverflowErrorMessage(a, "%", b);
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -813,7 +813,7 @@
auto rhs = b.value;
if (rhs == 0) {
// lhs % 0 is an error
- AddError(OverflowErrorMessage(a, "%", b), source);
+ AddError(source) << OverflowErrorMessage(a, "%", b);
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -824,7 +824,7 @@
// For signed integers, lhs % -1 where lhs is the
// most negative value is an error
if (rhs == -1 && lhs == std::numeric_limits<T>::min()) {
- AddError(OverflowErrorMessage(a, "%", b), source);
+ AddError(source) << OverflowErrorMessage(a, "%", b);
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -1084,7 +1084,7 @@
template <typename NumberT>
tint::Result<NumberT, Eval::Error> Eval::Sqrt(const Source& source, NumberT v) {
if (v < NumberT(0)) {
- AddError("sqrt must be called with a value >= 0", source);
+ AddError(source) << "sqrt must be called with a value >= 0";
if (use_runtime_semantics_) {
return NumberT{0};
} else {
@@ -1109,9 +1109,8 @@
NumberT low,
NumberT high) {
if (low > high) {
- StringStream ss;
- ss << "clamp called with 'low' (" << low << ") greater than 'high' (" << high << ")";
- AddError(ss.str(), source);
+ AddError(source) << "clamp called with 'low' (" << low << ") greater than 'high' (" << high
+ << ")";
if (!use_runtime_semantics_) {
return error;
}
@@ -1403,11 +1402,11 @@
AInt idx = idx_val->ValueAs<AInt>();
if (idx < 0 || (el.count > 0 && idx >= el.count)) {
- std::string range;
+ auto& err = AddError(idx_source) << "index " << idx << " out of bounds";
if (el.count > 0) {
- range = " [0.." + std::to_string(el.count - 1) + "]";
+ err << " [0.." + std::to_string(el.count - 1) + "]";
}
- AddError("index " + std::to_string(idx) + " out of bounds" + range, idx_source);
+
if (use_runtime_semantics_) {
return mgr.Zero(el.type);
} else {
@@ -1998,7 +1997,7 @@
UT must_match_msb = e2u + 1;
UT mask = ~UT{0} << (bit_width - must_match_msb);
if ((e1u & mask) != 0 && (e1u & mask) != mask) {
- AddError("shift left operation results in sign change", source);
+ AddError(source) << "shift left operation results in sign change";
if (!use_runtime_semantics_) {
return error;
}
@@ -2006,7 +2005,7 @@
} else {
// If shift value >= bit_width, then any non-zero value would overflow
if (e1 != 0) {
- AddError(OverflowErrorMessage(e1, "<<", e2), source);
+ AddError(source) << OverflowErrorMessage(e1, "<<", e2);
if (!use_runtime_semantics_) {
return error;
}
@@ -2021,10 +2020,9 @@
// At shader/pipeline-creation time, it is an error to shift by the bit width of
// the lhs or greater.
// NOTE: At runtime, we shift by e2 % (bit width of e1).
- AddError(
- "shift left value must be less than the bit width of the lhs, which is " +
- std::to_string(bit_width),
- source);
+ AddError(source)
+ << "shift left value must be less than the bit width of the lhs, which is "
+ << bit_width;
if (use_runtime_semantics_) {
e2u = e2u % bit_width;
} else {
@@ -2038,7 +2036,7 @@
size_t must_match_msb = e2u + 1;
UT mask = ~UT{0} << (bit_width - must_match_msb);
if ((e1u & mask) != 0 && (e1u & mask) != mask) {
- AddError("shift left operation results in sign change", source);
+ AddError(source) << "shift left operation results in sign change";
if (!use_runtime_semantics_) {
return error;
}
@@ -2050,7 +2048,7 @@
size_t must_be_zero_msb = e2u;
UT mask = ~UT{0} << (bit_width - must_be_zero_msb);
if ((e1u & mask) != 0) {
- AddError(OverflowErrorMessage(e1, "<<", e2), source);
+ AddError(source) << OverflowErrorMessage(e1, "<<", e2);
if (!use_runtime_semantics_) {
return error;
}
@@ -2111,10 +2109,9 @@
if (static_cast<size_t>(e2) >= bit_width) {
// At shader/pipeline-creation time, it is an error to shift by the bit width of
// the lhs or greater. NOTE: At runtime, we shift by e2 % (bit width of e1).
- AddError(
- "shift right value must be less than the bit width of the lhs, which is " +
- std::to_string(bit_width),
- source);
+ AddError(source)
+ << "shift right value must be less than the bit width of the lhs, which is "
+ << bit_width;
if (use_runtime_semantics_) {
e2u = e2u % bit_width;
} else {
@@ -2169,22 +2166,23 @@
Eval::Result Eval::acos(const core::type::Type* ty,
VectorRef<const Value*> args,
const Source& source) {
- auto transform = [&](const Value* c0) {
- auto create = [&](auto i) -> Eval::Result {
- using NumberT = decltype(i);
- if (i < NumberT(-1.0) || i > NumberT(1.0)) {
- AddError("acos must be called with a value in the range [-1 .. 1] (inclusive)",
- source);
- if (use_runtime_semantics_) {
- return mgr.Zero(c0->Type());
- } else {
- return error;
+ auto transform =
+ [&](const Value* c0) {
+ auto create = [&](auto i) -> Eval::Result {
+ using NumberT = decltype(i);
+ if (i < NumberT(-1.0) || i > NumberT(1.0)) {
+ AddError(source)
+ << "acos must be called with a value in the range [-1 .. 1] (inclusive)";
+ if (use_runtime_semantics_) {
+ return mgr.Zero(c0->Type());
+ } else {
+ return error;
+ }
}
- }
- return CreateScalar(source, c0->Type(), NumberT(std::acos(i.value)));
+ return CreateScalar(source, c0->Type(), NumberT(std::acos(i.value)));
+ };
+ return Dispatch_fa_f32_f16(create, c0);
};
- return Dispatch_fa_f32_f16(create, c0);
- };
return TransformUnaryElements(mgr, ty, transform, args[0]);
}
@@ -2195,7 +2193,7 @@
auto create = [&](auto i) -> Eval::Result {
using NumberT = decltype(i);
if (i < NumberT(1.0)) {
- AddError("acosh must be called with a value >= 1.0", source);
+ AddError(source) << "acosh must be called with a value >= 1.0";
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -2225,22 +2223,23 @@
Eval::Result Eval::asin(const core::type::Type* ty,
VectorRef<const Value*> args,
const Source& source) {
- auto transform = [&](const Value* c0) {
- auto create = [&](auto i) -> Eval::Result {
- using NumberT = decltype(i);
- if (i < NumberT(-1.0) || i > NumberT(1.0)) {
- AddError("asin must be called with a value in the range [-1 .. 1] (inclusive)",
- source);
- if (use_runtime_semantics_) {
- return mgr.Zero(c0->Type());
- } else {
- return error;
+ auto transform =
+ [&](const Value* c0) {
+ auto create = [&](auto i) -> Eval::Result {
+ using NumberT = decltype(i);
+ if (i < NumberT(-1.0) || i > NumberT(1.0)) {
+ AddError(source)
+ << "asin must be called with a value in the range [-1 .. 1] (inclusive)";
+ if (use_runtime_semantics_) {
+ return mgr.Zero(c0->Type());
+ } else {
+ return error;
+ }
}
- }
- return CreateScalar(source, c0->Type(), NumberT(std::asin(i.value)));
+ return CreateScalar(source, c0->Type(), NumberT(std::asin(i.value)));
+ };
+ return Dispatch_fa_f32_f16(create, c0);
};
- return Dispatch_fa_f32_f16(create, c0);
- };
return TransformUnaryElements(mgr, ty, transform, args[0]);
}
@@ -2272,22 +2271,23 @@
Eval::Result Eval::atanh(const core::type::Type* ty,
VectorRef<const Value*> args,
const Source& source) {
- auto transform = [&](const Value* c0) {
- auto create = [&](auto i) -> Eval::Result {
- using NumberT = decltype(i);
- if (i <= NumberT(-1.0) || i >= NumberT(1.0)) {
- AddError("atanh must be called with a value in the range (-1 .. 1) (exclusive)",
- source);
- if (use_runtime_semantics_) {
- return mgr.Zero(c0->Type());
- } else {
- return error;
+ auto transform =
+ [&](const Value* c0) {
+ auto create = [&](auto i) -> Eval::Result {
+ using NumberT = decltype(i);
+ if (i <= NumberT(-1.0) || i >= NumberT(1.0)) {
+ AddError(source)
+ << "atanh must be called with a value in the range (-1 .. 1) (exclusive)";
+ if (use_runtime_semantics_) {
+ return mgr.Zero(c0->Type());
+ } else {
+ return error;
+ }
}
- }
- return CreateScalar(source, c0->Type(), NumberT(std::atanh(i.value)));
+ return CreateScalar(source, c0->Type(), NumberT(std::atanh(i.value)));
+ };
+ return Dispatch_fa_f32_f16(create, c0);
};
- return Dispatch_fa_f32_f16(create, c0);
- };
return TransformUnaryElements(mgr, ty, transform, args[0]);
}
@@ -2458,12 +2458,12 @@
auto pi = kPi<T>;
auto scale = Div(source, NumberT(180), NumberT(pi));
if (scale != Success) {
- AddNote("when calculating degrees", source);
+ AddNote(source) << "when calculating degrees";
return error;
}
auto result = Mul(source, e, scale.Get());
if (result != Success) {
- AddNote("when calculating degrees", source);
+ AddNote(source) << "when calculating degrees";
return error;
}
return CreateScalar(source, c0->Type(), result.Get());
@@ -2504,7 +2504,7 @@
};
auto r = calculate();
if (r != Success) {
- AddNote("when calculating determinant", source);
+ AddNote(source) << "when calculating determinant";
}
return r;
}
@@ -2513,7 +2513,7 @@
VectorRef<const Value*> args,
const Source& source) {
auto err = [&]() -> Eval::Result {
- AddNote("when calculating distance", source);
+ AddNote(source) << "when calculating distance";
return error;
};
@@ -2534,7 +2534,7 @@
const Source& source) {
auto r = Dot(source, args[0], args[1]);
if (r != Success) {
- AddNote("when calculating dot", source);
+ AddNote(source) << "when calculating dot";
}
return r;
}
@@ -2577,7 +2577,7 @@
using NumberT = decltype(e0);
auto val = NumberT(std::exp(e0));
if (!std::isfinite(val.value)) {
- AddError(OverflowExpErrorMessage("e", e0), source);
+ AddError(source) << OverflowExpErrorMessage("e", e0);
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -2599,7 +2599,7 @@
using NumberT = decltype(e0);
auto val = NumberT(std::exp2(e0));
if (!std::isfinite(val.value)) {
- AddError(OverflowExpErrorMessage("2", e0), source);
+ AddError(source) << OverflowExpErrorMessage("2", e0);
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -2616,60 +2616,62 @@
Eval::Result Eval::extractBits(const core::type::Type* ty,
VectorRef<const Value*> args,
const Source& source) {
- auto transform = [&](const Value* c0) {
- auto create = [&](auto in_e) -> Eval::Result {
- using NumberT = decltype(in_e);
- using T = UnwrapNumber<NumberT>;
- using UT = std::make_unsigned_t<T>;
- using NumberUT = Number<UT>;
+ auto transform =
+ [&](const Value* c0) {
+ auto create = [&](auto in_e) -> Eval::Result {
+ using NumberT = decltype(in_e);
+ using T = UnwrapNumber<NumberT>;
+ using UT = std::make_unsigned_t<T>;
+ using NumberUT = Number<UT>;
- // Read args that are always scalar
- NumberUT in_offset = args[1]->ValueAs<NumberUT>();
- NumberUT in_count = args[2]->ValueAs<NumberUT>();
+ // Read args that are always scalar
+ NumberUT in_offset = args[1]->ValueAs<NumberUT>();
+ NumberUT in_count = args[2]->ValueAs<NumberUT>();
- // Cast all to unsigned
- UT e = static_cast<UT>(in_e);
- UT o = static_cast<UT>(in_offset);
- UT c = static_cast<UT>(in_count);
+ // Cast all to unsigned
+ UT e = static_cast<UT>(in_e);
+ UT o = static_cast<UT>(in_offset);
+ UT c = static_cast<UT>(in_count);
- constexpr UT w = sizeof(UT) * 8;
- if (o > w || c > w || (o + c) > w) {
- AddError("'offset + 'count' must be less than or equal to the bit width of 'e'",
- source);
- if (use_runtime_semantics_) {
- o = std::min(o, w);
- c = std::min(c, w - o);
- } else {
- return error;
- }
- }
-
- NumberT result;
- if (c == UT{0}) {
- // The result is 0 if c is 0
- result = NumberT{0};
- } else if (c == w) {
- // The result is e if c is w
- result = NumberT{e};
- } else {
- // Otherwise, bits 0..c - 1 of the result are copied from bits o..o + c - 1 of e.
- UT src_mask = ((UT{1} << c) - UT{1}) << o;
- UT r = (e & src_mask) >> o;
- if constexpr (IsSignedIntegral<NumberT>) {
- // Other bits of the result are the same as bit c - 1 of the result.
- // Only need to set other bits if bit at c - 1 of result is 1
- if ((r & (UT{1} << (c - UT{1}))) != UT{0}) {
- UT dst_mask = src_mask >> o;
- r |= (~UT{0} & ~dst_mask);
+ constexpr UT w = sizeof(UT) * 8;
+ if (o > w || c > w || (o + c) > w) {
+ AddError(source)
+ << "'offset + 'count' must be less than or equal to the bit width of 'e'";
+ if (use_runtime_semantics_) {
+ o = std::min(o, w);
+ c = std::min(c, w - o);
+ } else {
+ return error;
}
}
- result = NumberT{r};
- }
- return CreateScalar(source, c0->Type(), result);
+ NumberT result;
+ if (c == UT{0}) {
+ // The result is 0 if c is 0
+ result = NumberT{0};
+ } else if (c == w) {
+ // The result is e if c is w
+ result = NumberT{e};
+ } else {
+ // Otherwise, bits 0..c - 1 of the result are copied from bits o..o + c - 1 of
+ // e.
+ UT src_mask = ((UT{1} << c) - UT{1}) << o;
+ UT r = (e & src_mask) >> o;
+ if constexpr (IsSignedIntegral<NumberT>) {
+ // Other bits of the result are the same as bit c - 1 of the result.
+ // Only need to set other bits if bit at c - 1 of result is 1
+ if ((r & (UT{1} << (c - UT{1}))) != UT{0}) {
+ UT dst_mask = src_mask >> o;
+ r |= (~UT{0} & ~dst_mask);
+ }
+ }
+
+ result = NumberT{r};
+ }
+ return CreateScalar(source, c0->Type(), result);
+ };
+ return Dispatch_iu32(create, c0);
};
- return Dispatch_iu32(create, c0);
- };
return TransformUnaryElements(mgr, ty, transform, args[0]);
}
@@ -2682,7 +2684,7 @@
auto* e3 = args[2];
auto r = Dot(source, e2, e3);
if (r != Success) {
- AddNote("when calculating faceForward", source);
+ AddNote(source) << "when calculating faceForward";
return error;
}
auto is_negative = [](auto v) { return v < 0; };
@@ -2780,7 +2782,7 @@
auto transform = [&](const Value* c1, const Value* c2, const Value* c3) {
auto create = [&](auto e1, auto e2, auto e3) -> Eval::Result {
auto err_msg = [&] {
- AddNote("when calculating fma", source);
+ AddNote(source) << "when calculating fma";
return error;
};
@@ -2882,57 +2884,58 @@
Eval::Result Eval::insertBits(const core::type::Type* ty,
VectorRef<const Value*> args,
const Source& source) {
- auto transform = [&](const Value* c0, const Value* c1) {
- auto create = [&](auto in_e, auto in_newbits) -> Eval::Result {
- using NumberT = decltype(in_e);
- using T = UnwrapNumber<NumberT>;
- using UT = std::make_unsigned_t<T>;
- using NumberUT = Number<UT>;
+ auto transform =
+ [&](const Value* c0, const Value* c1) {
+ auto create = [&](auto in_e, auto in_newbits) -> Eval::Result {
+ using NumberT = decltype(in_e);
+ using T = UnwrapNumber<NumberT>;
+ using UT = std::make_unsigned_t<T>;
+ using NumberUT = Number<UT>;
- // Read args that are always scalar
- NumberUT in_offset = args[2]->ValueAs<NumberUT>();
- NumberUT in_count = args[3]->ValueAs<NumberUT>();
+ // Read args that are always scalar
+ NumberUT in_offset = args[2]->ValueAs<NumberUT>();
+ NumberUT in_count = args[3]->ValueAs<NumberUT>();
- // Cast all to unsigned
- UT e = static_cast<UT>(in_e);
- UT newbits = static_cast<UT>(in_newbits);
- UT o = static_cast<UT>(in_offset);
- UT c = static_cast<UT>(in_count);
+ // Cast all to unsigned
+ UT e = static_cast<UT>(in_e);
+ UT newbits = static_cast<UT>(in_newbits);
+ UT o = static_cast<UT>(in_offset);
+ UT c = static_cast<UT>(in_count);
- constexpr UT w = sizeof(UT) * 8;
- if (o > w || c > w || (o + c) > w) {
- AddError("'offset + 'count' must be less than or equal to the bit width of 'e'",
- source);
- if (use_runtime_semantics_) {
- o = std::min(o, w);
- c = std::min(c, w - o);
- } else {
- return error;
+ constexpr UT w = sizeof(UT) * 8;
+ if (o > w || c > w || (o + c) > w) {
+ AddError(source)
+ << "'offset + 'count' must be less than or equal to the bit width of 'e'";
+ if (use_runtime_semantics_) {
+ o = std::min(o, w);
+ c = std::min(c, w - o);
+ } else {
+ return error;
+ }
}
- }
- NumberT result;
- if (c == UT{0}) {
- // The result is e if c is 0
- result = NumberT{e};
- } else if (c == w) {
- // The result is newbits if c is w
- result = NumberT{newbits};
- } else {
- // Otherwise, bits o..o + c - 1 of the result are copied from bits 0..c - 1 of
- // newbits. Other bits of the result are copied from e.
- UT from = newbits << o;
- UT mask = ((UT{1} << c) - UT{1}) << UT{o};
- auto r = e; // Start with 'e' as the result
- r &= ~mask; // Zero the bits in 'e' we're overwriting
- r |= (from & mask); // Overwrite from 'newbits' (shifted into position)
- result = NumberT{r};
- }
+ NumberT result;
+ if (c == UT{0}) {
+ // The result is e if c is 0
+ result = NumberT{e};
+ } else if (c == w) {
+ // The result is newbits if c is w
+ result = NumberT{newbits};
+ } else {
+ // Otherwise, bits o..o + c - 1 of the result are copied from bits 0..c - 1 of
+ // newbits. Other bits of the result are copied from e.
+ UT from = newbits << o;
+ UT mask = ((UT{1} << c) - UT{1}) << UT{o};
+ auto r = e; // Start with 'e' as the result
+ r &= ~mask; // Zero the bits in 'e' we're overwriting
+ r |= (from & mask); // Overwrite from 'newbits' (shifted into position)
+ result = NumberT{r};
+ }
- return CreateScalar(source, c0->Type(), result);
+ return CreateScalar(source, c0->Type(), result);
+ };
+ return Dispatch_iu32(create, c0, c1);
};
- return Dispatch_iu32(create, c0, c1);
- };
return TransformBinaryElements(mgr, ty, transform, args[0], args[1]);
}
@@ -2944,7 +2947,7 @@
using NumberT = decltype(e);
if (e <= NumberT(0)) {
- AddError("inverseSqrt must be called with a value > 0", source);
+ AddError(source) << "inverseSqrt must be called with a value > 0";
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -2953,7 +2956,7 @@
}
auto err = [&] {
- AddNote("when calculating inverseSqrt", source);
+ AddNote(source) << "when calculating inverseSqrt";
return error;
};
@@ -3001,7 +3004,7 @@
}
if (e2 > bias + 1) {
- AddError("e2 must be less than or equal to " + std::to_string(bias + 1), source);
+ AddError(source) << "e2 must be less than or equal to " << (bias + 1);
if (use_runtime_semantics_) {
return mgr.Zero(c1->Type());
} else {
@@ -3025,7 +3028,7 @@
const Source& source) {
auto r = Length(source, ty, args[0]);
if (r != Success) {
- AddNote("when calculating length", source);
+ AddNote(source) << "when calculating length";
}
return r;
}
@@ -3037,7 +3040,7 @@
auto create = [&](auto v) -> Eval::Result {
using NumberT = decltype(v);
if (v <= NumberT(0)) {
- AddError("log must be called with a value > 0", source);
+ AddError(source) << "log must be called with a value > 0";
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -3058,7 +3061,7 @@
auto create = [&](auto v) -> Eval::Result {
using NumberT = decltype(v);
if (v <= NumberT(0)) {
- AddError("log2 must be called with a value > 0", source);
+ AddError(source) << "log2 must be called with a value > 0";
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -3134,7 +3137,7 @@
};
auto r = TransformElements(mgr, ty, transform, 0, args[0], args[1]);
if (r != Success) {
- AddNote("when calculating mix", source);
+ AddNote(source) << "when calculating mix";
}
return r;
}
@@ -3180,12 +3183,12 @@
auto* len_ty = ty->DeepestElement();
auto len = Length(source, len_ty, args[0]);
if (len != Success) {
- AddNote("when calculating normalize", source);
+ AddNote(source) << "when calculating normalize";
return error;
}
auto* v = len.Get();
if (v->AllZero()) {
- AddError("zero length vector can not be normalized", source);
+ AddError(source) << "zero length vector can not be normalized";
if (use_runtime_semantics_) {
return mgr.Zero(ty);
} else {
@@ -3201,7 +3204,7 @@
auto convert = [&](f32 val) -> tint::Result<uint32_t, Error> {
auto conv = CheckedConvert<f16>(val);
if (conv != Success) {
- AddError(OverflowErrorMessage(val, "f16"), source);
+ AddError(source) << OverflowErrorMessage(val, "f16");
if (use_runtime_semantics_) {
return 0;
} else {
@@ -3365,7 +3368,7 @@
auto create = [&](auto e1, auto e2) -> Eval::Result {
auto r = CheckedPow(e1, e2);
if (!r) {
- AddError(OverflowErrorMessage(e1, "^", e2), source);
+ AddError(source) << OverflowErrorMessage(e1, "^", e2);
if (use_runtime_semantics_) {
return mgr.Zero(c0->Type());
} else {
@@ -3390,12 +3393,12 @@
auto pi = kPi<T>;
auto scale = Div(source, NumberT(pi), NumberT(180));
if (scale != Success) {
- AddNote("when calculating radians", source);
+ AddNote(source) << "when calculating radians";
return error;
}
auto result = Mul(source, e, scale.Get());
if (result != Success) {
- AddNote("when calculating radians", source);
+ AddNote(source) << "when calculating radians";
return error;
}
return CreateScalar(source, c0->Type(), result.Get());
@@ -3443,7 +3446,7 @@
};
auto r = calculate();
if (r != Success) {
- AddNote("when calculating reflect", source);
+ AddNote(source) << "when calculating reflect";
}
return r;
}
@@ -3541,7 +3544,7 @@
};
auto r = calculate();
if (r != Success) {
- AddNote("when calculating refract", source);
+ AddNote(source) << "when calculating refract";
}
return r;
}
@@ -3708,7 +3711,7 @@
using NumberT = decltype(low);
auto err = [&] {
- AddNote("when calculating smoothstep", source);
+ AddNote(source) << "when calculating smoothstep";
return error;
};
@@ -3844,7 +3847,7 @@
auto in = f16::FromBits(uint16_t((e >> (16 * i)) & 0x0000'ffff));
auto val = CheckedConvert<f32>(in);
if (val != Success) {
- AddError(OverflowErrorMessage(in, "f32"), source);
+ AddError(source) << OverflowErrorMessage(in, "f32");
if (use_runtime_semantics_) {
val = f32(0.f);
} else {
@@ -3986,7 +3989,7 @@
auto value = c->ValueAs<f32>();
auto conv = CheckedConvert<f32>(f16(value));
if (conv != Success) {
- AddError(OverflowErrorMessage(value, "f16"), source);
+ AddError(source) << OverflowErrorMessage(value, "f16");
if (use_runtime_semantics_) {
return mgr.Zero(c->Type());
} else {
@@ -4009,20 +4012,20 @@
return converted ? Result(converted) : Result(error);
}
-void Eval::AddError(const std::string& msg, const Source& source) const {
+diag::Diagnostic& Eval::AddError(const Source& source) const {
if (use_runtime_semantics_) {
- diags.AddWarning(diag::System::Constant, msg, source);
+ return diags.AddWarning(diag::System::Constant, source);
} else {
- diags.AddError(diag::System::Constant, msg, source);
+ return diags.AddError(diag::System::Constant, source);
}
}
-void Eval::AddWarning(const std::string& msg, const Source& source) const {
- diags.AddWarning(diag::System::Constant, msg, source);
+diag::Diagnostic& Eval::AddWarning(const Source& source) const {
+ return diags.AddWarning(diag::System::Constant, source);
}
-void Eval::AddNote(const std::string& msg, const Source& source) const {
- diags.AddNote(diag::System::Constant, msg, source);
+diag::Diagnostic& Eval::AddNote(const Source& source) const {
+ return diags.AddNote(diag::System::Constant, source);
}
} // namespace tint::core::constant
diff --git a/src/tint/lang/core/constant/eval.h b/src/tint/lang/core/constant/eval.h
index de6624a..f3c4e6e 100644
--- a/src/tint/lang/core/constant/eval.h
+++ b/src/tint/lang/core/constant/eval.h
@@ -1025,14 +1025,14 @@
const Source& source);
private:
- /// Adds the given error message to the diagnostics
- void AddError(const std::string& msg, const Source& source) const;
+ /// @returns a new error diagnostic
+ diag::Diagnostic& AddError(const Source& source) const;
- /// Adds the given warning message to the diagnostics
- void AddWarning(const std::string& msg, const Source& source) const;
+ /// @returns a new warning diagnostic
+ diag::Diagnostic& AddWarning(const Source& source) const;
- /// Adds the given note message to the diagnostics
- void AddNote(const std::string& msg, const Source& source) const;
+ /// @returns a new note diagnostic
+ diag::Diagnostic& AddNote(const Source& source) const;
/// CreateScalar constructs and returns a constant::Scalar<T>.
/// @param source the source location
diff --git a/src/tint/lang/core/constant/eval_binary_op_test.cc b/src/tint/lang/core/constant/eval_binary_op_test.cc
index 1a1fbe2..7859908 100644
--- a/src/tint/lang/core/constant/eval_binary_op_test.cc
+++ b/src/tint/lang/core/constant/eval_binary_op_test.cc
@@ -1508,11 +1508,11 @@
GlobalConst("result", LogicalAnd(lhs, rhs));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for operator ! (abstract-int)
+ EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for 'operator ! (abstract-int)'
2 candidate operators:
- operator ! (bool) -> bool
- operator ! (vecN<bool>) -> vecN<bool>
+ 'operator ! (bool) -> bool'
+ 'operator ! (vecN<bool>) -> vecN<bool>'
)");
}
@@ -1525,11 +1525,11 @@
GlobalConst("result", LogicalOr(lhs, rhs));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for operator ! (abstract-int)
+ EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for 'operator ! (abstract-int)'
2 candidate operators:
- operator ! (bool) -> bool
- operator ! (vecN<bool>) -> vecN<bool>
+ 'operator ! (bool) -> bool'
+ 'operator ! (vecN<bool>) -> vecN<bool>'
)");
}
@@ -1574,10 +1574,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator && (bool, abstract-int)
+ R"(12:34 error: no matching overload for 'operator && (bool, abstract-int)'
1 candidate operator:
- operator && (bool, bool) -> bool
+ 'operator && (bool, bool) -> bool'
)");
}
@@ -1618,10 +1618,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator || (bool, abstract-int)
+ R"(12:34 error: no matching overload for 'operator || (bool, abstract-int)'
1 candidate operator:
- operator || (bool, bool) -> bool
+ 'operator || (bool, bool) -> bool'
)");
}
@@ -1672,11 +1672,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator == (abstract-float, i32)
+ R"(12:34 error: no matching overload for 'operator == (abstract-float, i32)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -1723,11 +1723,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator == (abstract-float, i32)
+ R"(12:34 error: no matching overload for 'operator == (abstract-float, i32)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -1784,11 +1784,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator == (i32, f32)
+ R"(12:34 error: no matching overload for 'operator == (i32, f32)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -1841,11 +1841,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator == (i32, f32)
+ R"(12:34 error: no matching overload for 'operator == (i32, f32)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -1895,11 +1895,11 @@
GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for operator == (f32, i32)
+ EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for 'operator == (f32, i32)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -1945,11 +1945,11 @@
GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for operator == (f32, i32)
+ EXPECT_EQ(r()->error(), R"(12:34 error: no matching overload for 'operator == (f32, i32)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -1971,24 +1971,24 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching constructor for vec2<f32>(abstract-float, bool)
+ R"(12:34 error: no matching constructor for 'vec2<f32>(abstract-float, bool)'
8 candidate constructors:
- vec2<T>(x: T, y: T) -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2<T>(T) -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2(T) -> vec2<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec2<T>(vec2<T>) -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2(vec2<T>) -> vec2<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec2() -> vec2<abstract-int>
- vec2<T>() -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2(x: T, y: T) -> vec2<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'vec2<T>(x: T, y: T) -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2<T>(T) -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2(T) -> vec2<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2<T>(vec2<T>) -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2(vec2<T>) -> vec2<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2() -> vec2<abstract-int>'
+ 'vec2<T>() -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2(x: T, y: T) -> vec2<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec2<T>(vec2<U>) -> vec2<T> where: T is f32, U is abstract-int, abstract-float, i32, f16, u32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is f16, U is abstract-int, abstract-float, f32, i32, u32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is i32, U is abstract-int, abstract-float, f32, f16, u32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is u32, U is abstract-int, abstract-float, f32, f16, i32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is bool, U is abstract-int, abstract-float, f32, f16, i32 or u32
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'f32', 'U' is 'abstract-int', 'abstract-float', 'i32', 'f16', 'u32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'f16', 'U' is 'abstract-int', 'abstract-float', 'f32', 'i32', 'u32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'i32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'u32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'u32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'bool', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -2003,24 +2003,24 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching constructor for vec2<f32>(abstract-float, bool)
+ R"(12:34 error: no matching constructor for 'vec2<f32>(abstract-float, bool)'
8 candidate constructors:
- vec2<T>(x: T, y: T) -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2<T>(T) -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2(T) -> vec2<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec2<T>(vec2<T>) -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2(vec2<T>) -> vec2<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec2() -> vec2<abstract-int>
- vec2<T>() -> vec2<T> where: T is f32, f16, i32, u32 or bool
- vec2(x: T, y: T) -> vec2<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'vec2<T>(x: T, y: T) -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2<T>(T) -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2(T) -> vec2<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2<T>(vec2<T>) -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2(vec2<T>) -> vec2<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2() -> vec2<abstract-int>'
+ 'vec2<T>() -> vec2<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec2(x: T, y: T) -> vec2<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec2<T>(vec2<U>) -> vec2<T> where: T is f32, U is abstract-int, abstract-float, i32, f16, u32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is f16, U is abstract-int, abstract-float, f32, i32, u32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is i32, U is abstract-int, abstract-float, f32, f16, u32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is u32, U is abstract-int, abstract-float, f32, f16, i32 or bool
- vec2<T>(vec2<U>) -> vec2<T> where: T is bool, U is abstract-int, abstract-float, f32, f16, i32 or u32
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'f32', 'U' is 'abstract-int', 'abstract-float', 'i32', 'f16', 'u32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'f16', 'U' is 'abstract-int', 'abstract-float', 'f32', 'i32', 'u32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'i32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'u32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'u32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'bool'
+ 'vec2<T>(vec2<U>) -> vec2<T>' where: 'T' is 'bool', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -2078,12 +2078,13 @@
GlobalConst("result", LogicalAnd(lhs, rhs));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(error: no matching overload for operator == (array<abstract-int, 1>, abstract-int)
+ EXPECT_EQ(
+ r()->error(),
+ R"(error: no matching overload for 'operator == (array<abstract-int, 1>, abstract-int)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -2096,12 +2097,13 @@
GlobalConst("result", LogicalOr(lhs, rhs));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(error: no matching overload for operator == (array<abstract-int, 1>, abstract-int)
+ EXPECT_EQ(
+ r()->error(),
+ R"(error: no matching overload for 'operator == (array<abstract-int, 1>, abstract-int)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -2147,11 +2149,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator == (i32, abstract-float)
+ R"(12:34 error: no matching overload for 'operator == (i32, abstract-float)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -2193,11 +2195,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching overload for operator == (i32, abstract-float)
+ R"(12:34 error: no matching overload for 'operator == (i32, abstract-float)'
2 candidate operators:
- operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'operator == (T, T) -> bool' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'operator == (vecN<T>, vecN<T>) -> vecN<bool>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
diff --git a/src/tint/lang/core/intrinsic/data.cc b/src/tint/lang/core/intrinsic/data.cc
index d5db81e..46637b1 100644
--- a/src/tint/lang/core/intrinsic/data.cc
+++ b/src/tint/lang/core/intrinsic/data.cc
@@ -80,8 +80,8 @@
}
return BuildBool(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "bool";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "bool";
}
};
@@ -94,8 +94,8 @@
}
return BuildI32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "i32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "i32";
}
};
@@ -108,8 +108,8 @@
}
return BuildU32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "u32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "u32";
}
};
@@ -122,8 +122,8 @@
}
return BuildF32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "f32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "f32";
}
};
@@ -136,8 +136,8 @@
}
return BuildF16(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "f16";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "f16";
}
};
@@ -155,9 +155,9 @@
}
return BuildVec2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -175,9 +175,9 @@
}
return BuildVec3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -195,9 +195,9 @@
}
return BuildVec4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -215,9 +215,9 @@
}
return BuildMat2X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -235,9 +235,9 @@
}
return BuildMat2X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -255,9 +255,9 @@
}
return BuildMat2X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -275,9 +275,9 @@
}
return BuildMat3X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -295,9 +295,9 @@
}
return BuildMat3X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -315,9 +315,9 @@
}
return BuildMat3X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -335,9 +335,9 @@
}
return BuildMat4X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -355,9 +355,9 @@
}
return BuildMat4X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -375,9 +375,9 @@
}
return BuildMat4X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -400,12 +400,10 @@
}
return BuildVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "vec" << N << "<" << T << ">";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec" << style::Type << N << style::Type << "<" << style::Type << T << style::Type << ">";
}
};
@@ -433,13 +431,11 @@
}
return BuildMat(state, ty, N, M, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string M = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "mat" << N << "x" << M << "<" << T << ">";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText M;
+ state->PrintNum(M);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat" << style::Type << N << style::Type << "x" << style::Type << M << style::Type << "<" << style::Type << T << style::Type << ">";
}
};
@@ -467,11 +463,11 @@
}
return BuildPtr(state, ty, S, T, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string S = state->NumName();
- const std::string T = state->TypeName();
- const std::string A = state->NumName();
- return "ptr<" + S + ", " + T + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText S;
+ state->PrintNum(S);StyledText T;
+ state->PrintType(T);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "ptr" << style::Code << "<" << style::Type << S << style::Code << ", " << style::Type << T << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -489,9 +485,9 @@
}
return BuildAtomic(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "atomic<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "atomic" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -509,9 +505,9 @@
}
return BuildArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -524,8 +520,8 @@
}
return BuildSampler(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "sampler";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "sampler";
}
};
@@ -538,8 +534,8 @@
}
return BuildSamplerComparison(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "sampler_comparison";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "sampler_comparison";
}
};
@@ -557,9 +553,9 @@
}
return BuildTexture1D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_1d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_1d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -577,9 +573,9 @@
}
return BuildTexture2D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_2d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_2d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -597,9 +593,9 @@
}
return BuildTexture2DArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_2d_array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_2d_array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -617,9 +613,9 @@
}
return BuildTexture3D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_3d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_3d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -637,9 +633,9 @@
}
return BuildTextureCube(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_cube<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_cube" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -657,9 +653,9 @@
}
return BuildTextureCubeArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_cube_array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_cube_array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -677,9 +673,9 @@
}
return BuildTextureMultisampled2D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_multisampled_2d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_multisampled_2d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -692,8 +688,8 @@
}
return BuildTextureDepth2D(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_2d";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_2d";
}
};
@@ -706,8 +702,8 @@
}
return BuildTextureDepth2DArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_2d_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_2d_array";
}
};
@@ -720,8 +716,8 @@
}
return BuildTextureDepthCube(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_cube";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_cube";
}
};
@@ -734,8 +730,8 @@
}
return BuildTextureDepthCubeArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_cube_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_cube_array";
}
};
@@ -748,8 +744,8 @@
}
return BuildTextureDepthMultisampled2D(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_multisampled_2d";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_multisampled_2d";
}
};
@@ -772,10 +768,10 @@
}
return BuildTextureStorage1D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_1d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_1d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -798,10 +794,10 @@
}
return BuildTextureStorage2D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_2d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_2d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -824,10 +820,10 @@
}
return BuildTextureStorage2DArray(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_2d_array<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_2d_array" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -850,10 +846,10 @@
}
return BuildTextureStorage3D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_3d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_3d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -866,8 +862,8 @@
}
return BuildTextureExternal(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_external";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_external";
}
};
@@ -885,11 +881,9 @@
}
return BuildModfResult(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__modf_result_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__modf_result_" << style::Type << T;
}
};
@@ -912,12 +906,10 @@
}
return BuildModfResultVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__modf_result_vec" << N << "_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__modf_result_vec" << style::Type << N << style::Type << "_" << style::Type << T;
}
};
@@ -935,11 +927,9 @@
}
return BuildFrexpResult(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__frexp_result_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__frexp_result_" << style::Type << T;
}
};
@@ -962,12 +952,10 @@
}
return BuildFrexpResultVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__frexp_result_vec" << N << "_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__frexp_result_vec" << style::Type << N << style::Type << "_" << style::Type << T;
}
};
@@ -985,9 +973,9 @@
}
return BuildAtomicCompareExchangeResult(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "__atomic_compare_exchange_result<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__atomic_compare_exchange_result" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -1012,13 +1000,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_f32'
@@ -1038,13 +1023,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kI32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_f16'
@@ -1064,13 +1046,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_i32'
@@ -1090,13 +1069,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_u32'
@@ -1116,13 +1092,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_bool'
@@ -1142,13 +1115,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fiu32_f16'
@@ -1168,13 +1138,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fiu32'
@@ -1191,13 +1158,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fi32_f16'
@@ -1214,13 +1178,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fi32'
@@ -1234,13 +1195,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << " or " << kI32Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kI32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match f32_f16'
@@ -1254,13 +1212,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match iu32'
@@ -1274,13 +1229,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// EnumMatcher for 'match f32_texel_format'
@@ -1299,8 +1251,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "bgra8unorm, rgba8unorm, rgba8snorm, rgba16float, r32float, rg32float or rgba32float";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "bgra8unorm"<< TextStyle{} << ", " << style::Enum << "rgba8unorm"<< TextStyle{} << ", " << style::Enum << "rgba8snorm"<< TextStyle{} << ", " << style::Enum << "rgba16float"<< TextStyle{} << ", " << style::Enum << "r32float"<< TextStyle{} << ", " << style::Enum << "rg32float"<< TextStyle{} << " or " << style::Enum << "rgba32float";
}
};
@@ -1318,8 +1270,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "rgba8sint, rgba16sint, r32sint, rg32sint or rgba32sint";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "rgba8sint"<< TextStyle{} << ", " << style::Enum << "rgba16sint"<< TextStyle{} << ", " << style::Enum << "r32sint"<< TextStyle{} << ", " << style::Enum << "rg32sint"<< TextStyle{} << " or " << style::Enum << "rgba32sint";
}
};
@@ -1337,8 +1289,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "rgba8uint, rgba16uint, r32uint, rg32uint or rgba32uint";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "rgba8uint"<< TextStyle{} << ", " << style::Enum << "rgba16uint"<< TextStyle{} << ", " << style::Enum << "r32uint"<< TextStyle{} << ", " << style::Enum << "rg32uint"<< TextStyle{} << " or " << style::Enum << "rgba32uint";
}
};
@@ -1350,8 +1302,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "write";
}
};
@@ -1363,8 +1315,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "read_write";
}
};
@@ -1379,8 +1331,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "read or read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "read"<< TextStyle{} << " or " << style::Enum << "read_write";
}
};
@@ -1395,8 +1347,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "write or read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "write"<< TextStyle{} << " or " << style::Enum << "read_write";
}
};
@@ -1412,8 +1364,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "function, private or workgroup";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "function"<< TextStyle{} << ", " << style::Enum << "private"<< TextStyle{} << " or " << style::Enum << "workgroup";
}
};
@@ -1428,8 +1380,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "workgroup or storage";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "workgroup"<< TextStyle{} << " or " << style::Enum << "storage";
}
};
@@ -1441,8 +1393,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "storage";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "storage";
}
};
@@ -1454,8 +1406,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "workgroup";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "workgroup";
}
};
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index d7c080e..b888362 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -37,7 +37,10 @@
#include "src/tint/lang/core/type/manager.h"
#include "src/tint/lang/core/type/void.h"
#include "src/tint/utils/ice/ice.h"
+#include "src/tint/utils/macros/defer.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"
namespace tint::core::intrinsic {
@@ -86,7 +89,7 @@
using Candidates = Vector<Candidate, kNumFixedCandidates>;
/// Callback function when no overloads match.
-using OnNoMatch = std::function<std::string(VectorRef<Candidate>)>;
+using OnNoMatch = std::function<StyledText(VectorRef<Candidate>)>;
/// Sorts the candidates based on their score, with the lowest (best-ranking) scores first.
static inline void SortCandidates(Candidates& candidates) {
@@ -94,15 +97,17 @@
[&](const Candidate& a, const Candidate& b) { return a.score < b.score; });
}
-static void PrintTypeList(StringStream& ss, VectorRef<const core::type::Type*> types) {
+/// Prints a list of types. Ends with the style of @p ss set to style::Code.
+static void PrintTypeList(StyledText& ss, VectorRef<const core::type::Type*> types) {
bool first = true;
for (auto* arg : types) {
if (!first) {
- ss << ", ";
+ ss << style::Code << ", ";
}
first = false;
- ss << arg->FriendlyName();
+ ss << style::Type << arg->FriendlyName();
}
+ ss << style::Code;
}
/// Attempts to find a single intrinsic overload that matches the provided argument types.
@@ -114,13 +119,13 @@
/// @param on_no_match an error callback when no intrinsic overloads matched the provided
/// arguments.
/// @returns the matched intrinsic
-Result<Overload, std::string> MatchIntrinsic(Context& context,
- const IntrinsicInfo& intrinsic,
- std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const OnNoMatch& on_no_match);
+Result<Overload, StyledText> MatchIntrinsic(Context& context,
+ const IntrinsicInfo& intrinsic,
+ std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const OnNoMatch& on_no_match);
/// The scoring mode for ScoreOverload()
enum class ScoreMode {
@@ -156,11 +161,11 @@
/// @param args the argument types
/// @see https://www.w3.org/TR/WGSL/#overload-resolution-section
/// @returns the resolved Candidate.
-Result<Candidate, std::string> ResolveCandidate(Context& context,
- Candidates&& candidates,
- std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args);
+Result<Candidate, StyledText> ResolveCandidate(Context& context,
+ Candidates&& candidates,
+ std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args);
/// Match constructs a new MatchState
/// @param context the intrinsic context
@@ -174,43 +179,44 @@
EvaluationStage earliest_eval_stage);
// Prints the list of candidates for emitting diagnostics
-void PrintCandidates(StringStream& ss,
+void PrintCandidates(StyledText& err,
Context& context,
VectorRef<Candidate> candidates,
std::string_view intrinsic_name);
/// Raises an ICE when no overload is a clear winner of overload resolution
-std::string ErrAmbiguousOverload(Context& context,
- std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- VectorRef<Candidate> candidates);
+StyledText ErrAmbiguousOverload(Context& context,
+ std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ VectorRef<Candidate> candidates);
/// @return a string representing a call to a builtin with the given argument
/// types.
-std::string CallSignature(std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args) {
- StringStream ss;
- ss << intrinsic_name;
+StyledText CallSignature(std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args) {
+ StyledText out;
+ out << style::Function << intrinsic_name << style::Code;
if (!template_args.IsEmpty()) {
- ss << "<";
- PrintTypeList(ss, template_args);
- ss << ">";
+ out << "<";
+ PrintTypeList(out, template_args);
+ out << ">";
}
- ss << "(";
- PrintTypeList(ss, args);
- ss << ")";
- return ss.str();
+ out << "(";
+ PrintTypeList(out, args);
+ out << ")";
+
+ return out << style::Plain;
}
-Result<Overload, std::string> MatchIntrinsic(Context& context,
- const IntrinsicInfo& intrinsic,
- std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const OnNoMatch& on_no_match) {
+Result<Overload, StyledText> MatchIntrinsic(Context& context,
+ const IntrinsicInfo& intrinsic,
+ std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const OnNoMatch& on_no_match) {
const size_t num_overloads = static_cast<size_t>(intrinsic.num_overloads);
size_t num_matched = 0;
size_t match_idx = 0;
@@ -261,8 +267,9 @@
Match(context, match.templates, *match.overload, matcher_indices, earliest_eval_stage)
.Type(&any);
if (TINT_UNLIKELY(!return_type)) {
- std::string err = "MatchState.Match() returned null";
- TINT_ICE() << err;
+ StyledText err;
+ err << "MatchState.Match() returned null";
+ TINT_ICE() << err.Plain();
return err;
}
} else {
@@ -423,11 +430,11 @@
#undef MATCH_FAILURE
}
-Result<Candidate, std::string> ResolveCandidate(Context& context,
- Candidates&& candidates,
- std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args) {
+Result<Candidate, StyledText> ResolveCandidate(Context& context,
+ Candidates&& candidates,
+ std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args) {
Vector<uint32_t, kNumFixedParams> best_ranks;
best_ranks.Resize(args.Length(), 0xffffffff);
size_t num_matched = 0;
@@ -497,57 +504,59 @@
overload, matcher_indices, earliest_eval_stage};
}
-void PrintCandidates(StringStream& ss,
+void PrintCandidates(StyledText& ss,
Context& context,
VectorRef<Candidate> candidates,
std::string_view intrinsic_name) {
for (auto& candidate : candidates) {
ss << " ";
PrintOverload(ss, context, *candidate.overload, intrinsic_name);
- ss << std::endl;
+ ss << "\n";
}
}
-std::string ErrAmbiguousOverload(Context& context,
- std::string_view intrinsic_name,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- VectorRef<Candidate> candidates) {
- StringStream ss;
- ss << "ambiguous overload while attempting to match "
- << CallSignature(intrinsic_name, template_args, args) << "\n";
+StyledText ErrAmbiguousOverload(Context& context,
+ std::string_view intrinsic_name,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ VectorRef<Candidate> candidates) {
+ StyledText err;
+ err << "ambiguous overload while attempting to match "
+ << CallSignature(intrinsic_name, template_args, args) << "\n";
for (auto& candidate : candidates) {
if (candidate.score == 0) {
- ss << " ";
- PrintOverload(ss, context, *candidate.overload, intrinsic_name);
- ss << "\n";
+ err << " ";
+ PrintOverload(err, context, *candidate.overload, intrinsic_name);
+ err << "\n";
}
}
- TINT_ICE() << ss.str();
- return ss.str();
+ TINT_ICE() << err.Plain();
+ return err;
}
} // namespace
-void PrintOverload(StringStream& ss,
+void PrintOverload(StyledText& ss,
Context& context,
const OverloadInfo& overload,
std::string_view intrinsic_name) {
+ TINT_DEFER(ss << style::Plain);
+
TemplateState templates;
// TODO(crbug.com/tint/1730): Use input evaluation stage to output only relevant overloads.
auto earliest_eval_stage = EvaluationStage::kConstant;
- ss << intrinsic_name;
+ ss << style::Function << intrinsic_name << style::Code;
if (overload.num_explicit_templates > 0) {
ss << "<";
for (size_t i = 0; i < overload.num_explicit_templates; i++) {
if (i > 0) {
- ss << ", ";
+ ss << style::Code << ", ";
}
- ss << context.data[overload.templates + i].name;
+ ss << style::Type << context.data[overload.templates + i].name;
}
ss << ">";
}
@@ -555,24 +564,24 @@
for (size_t p = 0; p < overload.num_parameters; p++) {
auto& parameter = context.data[overload.parameters + p];
if (p > 0) {
- ss << ", ";
+ ss << style::Code << ", ";
}
if (parameter.usage != ParameterUsage::kNone) {
- ss << ToString(parameter.usage) << ": ";
+ ss << style::Variable << ToString(parameter.usage) << style::Code << ": ";
}
auto* matcher_indices = context.data[parameter.matcher_indices];
- ss << Match(context, templates, overload, matcher_indices, earliest_eval_stage).TypeName();
+ Match(context, templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
}
- ss << ")";
+ ss << style::Code << ")";
if (overload.return_matcher_indices.IsValid()) {
ss << " -> ";
auto* matcher_indices = context.data[overload.return_matcher_indices];
- ss << Match(context, templates, overload, matcher_indices, earliest_eval_stage).TypeName();
+ Match(context, templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
}
bool first = true;
auto separator = [&] {
- ss << (first ? " where: " : ", ");
+ ss << style::Plain << (first ? " where: " : ", ");
first = false;
};
@@ -583,35 +592,33 @@
Match(context, templates, overload, matcher_indices, earliest_eval_stage);
separator();
- ss << tmpl.name;
- ss << " is ";
+ ss << style::Type << tmpl.name << style::Plain << " is ";
if (tmpl.kind == TemplateInfo::Kind::kType) {
- ss << matcher.TypeName();
+ matcher.PrintType(ss);
} else {
- ss << matcher.NumName();
+ matcher.PrintNum(ss);
}
}
}
}
-Result<Overload, std::string> LookupFn(Context& context,
- std::string_view intrinsic_name,
- size_t function_id,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage) {
+Result<Overload, StyledText> LookupFn(Context& context,
+ std::string_view intrinsic_name,
+ size_t function_id,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage) {
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](VectorRef<Candidate> candidates) {
- StringStream ss;
- ss << "no matching call to " << CallSignature(intrinsic_name, template_args, args)
- << std::endl;
+ StyledText err;
+ err << "no matching call to " << CallSignature(intrinsic_name, template_args, args) << "\n";
if (!candidates.IsEmpty()) {
- ss << std::endl
- << candidates.Length() << " candidate function"
- << (candidates.Length() > 1 ? "s:" : ":") << std::endl;
- PrintCandidates(ss, context, candidates, intrinsic_name);
+ err << "\n"
+ << candidates.Length() << " candidate function"
+ << (candidates.Length() > 1 ? "s:" : ":") << "\n";
+ PrintCandidates(err, context, candidates, intrinsic_name);
}
- return ss.str();
+ return err;
};
// Resolve the intrinsic overload
@@ -619,10 +626,10 @@
template_args, args, earliest_eval_stage, on_no_match);
}
-Result<Overload, std::string> LookupUnary(Context& context,
- core::UnaryOp op,
- const core::type::Type* arg,
- EvaluationStage earliest_eval_stage) {
+Result<Overload, StyledText> LookupUnary(Context& context,
+ core::UnaryOp op,
+ const core::type::Type* arg,
+ EvaluationStage earliest_eval_stage) {
const IntrinsicInfo* intrinsic_info = nullptr;
std::string_view intrinsic_name;
switch (op) {
@@ -652,15 +659,15 @@
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](VectorRef<Candidate> candidates) {
- StringStream ss;
- ss << "no matching overload for " << CallSignature(name, Empty, args) << std::endl;
+ StyledText err;
+ err << "no matching overload for " << CallSignature(name, Empty, args) << "\n";
if (!candidates.IsEmpty()) {
- ss << std::endl
- << candidates.Length() << " candidate operator"
- << (candidates.Length() > 1 ? "s:" : ":") << std::endl;
- PrintCandidates(ss, context, candidates, name);
+ err << "\n"
+ << candidates.Length() << " candidate operator"
+ << (candidates.Length() > 1 ? "s:" : ":") << "\n";
+ PrintCandidates(err, context, candidates, name);
}
- return ss.str();
+ return err;
};
// Resolve the intrinsic overload
@@ -668,12 +675,12 @@
earliest_eval_stage, on_no_match);
}
-Result<Overload, std::string> LookupBinary(Context& context,
- core::BinaryOp op,
- const core::type::Type* lhs,
- const core::type::Type* rhs,
- EvaluationStage earliest_eval_stage,
- bool is_compound) {
+Result<Overload, StyledText> LookupBinary(Context& context,
+ core::BinaryOp op,
+ const core::type::Type* lhs,
+ const core::type::Type* rhs,
+ EvaluationStage earliest_eval_stage,
+ bool is_compound) {
const IntrinsicInfo* intrinsic_info = nullptr;
std::string_view intrinsic_name;
switch (op) {
@@ -755,15 +762,15 @@
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](VectorRef<Candidate> candidates) {
- StringStream ss;
- ss << "no matching overload for " << CallSignature(name, Empty, args) << std::endl;
+ StyledText err;
+ err << "no matching overload for " << CallSignature(name, Empty, args) << "\n";
if (!candidates.IsEmpty()) {
- ss << std::endl
- << candidates.Length() << " candidate operator"
- << (candidates.Length() > 1 ? "s:" : ":") << std::endl;
- PrintCandidates(ss, context, candidates, name);
+ err << "\n"
+ << candidates.Length() << " candidate operator"
+ << (candidates.Length() > 1 ? "s:" : ":") << "\n";
+ PrintCandidates(err, context, candidates, name);
}
- return ss.str();
+ return err;
};
// Resolve the intrinsic overload
@@ -771,17 +778,17 @@
earliest_eval_stage, on_no_match);
}
-Result<Overload, std::string> LookupCtorConv(Context& context,
- std::string_view type_name,
- size_t type_id,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage) {
+Result<Overload, StyledText> LookupCtorConv(Context& context,
+ std::string_view type_name,
+ size_t type_id,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage) {
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](VectorRef<Candidate> candidates) {
- StringStream ss;
- ss << "no matching constructor for " << CallSignature(type_name, template_args, args)
- << std::endl;
+ StyledText err;
+ err << "no matching constructor for " << CallSignature(type_name, template_args, args)
+ << "\n";
Candidates ctor, conv;
for (auto candidate : candidates) {
if (candidate.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
@@ -791,18 +798,18 @@
}
}
if (!ctor.IsEmpty()) {
- ss << std::endl
- << ctor.Length() << " candidate constructor" << (ctor.Length() > 1 ? "s:" : ":")
- << std::endl;
- PrintCandidates(ss, context, ctor, type_name);
+ err << "\n"
+ << ctor.Length() << " candidate constructor" << (ctor.Length() > 1 ? "s:" : ":")
+ << "\n";
+ PrintCandidates(err, context, ctor, type_name);
}
if (!conv.IsEmpty()) {
- ss << std::endl
- << conv.Length() << " candidate conversion" << (conv.Length() > 1 ? "s:" : ":")
- << std::endl;
- PrintCandidates(ss, context, conv, type_name);
+ err << "\n"
+ << conv.Length() << " candidate conversion" << (conv.Length() > 1 ? "s:" : ":")
+ << "\n";
+ PrintCandidates(err, context, conv, type_name);
}
- return ss.str();
+ return err;
};
// Resolve the intrinsic overload
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index c77e61b..56f590a 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -39,7 +39,9 @@
#include "src/tint/lang/core/parameter_usage.h"
#include "src/tint/lang/core/unary_op.h"
#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/text/string.h"
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/text/styled_text.h"
// Forward declarations
namespace tint::diag {
@@ -107,7 +109,7 @@
};
// Prints the overload for emitting diagnostics
-void PrintOverload(StringStream& ss,
+void PrintOverload(StyledText& ss,
Context& context,
const OverloadInfo& overload,
std::string_view intrinsic_name);
@@ -126,12 +128,12 @@
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
/// @return the resolved builtin function overload
-Result<Overload, std::string> LookupFn(Context& context,
- std::string_view function_name,
- size_t function_id,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage);
+Result<Overload, StyledText> LookupFn(Context& context,
+ std::string_view function_name,
+ size_t function_id,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage);
/// Lookup looks for the unary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
@@ -145,10 +147,10 @@
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved unary operator overload
-Result<Overload, std::string> LookupUnary(Context& context,
- core::UnaryOp op,
- const core::type::Type* arg,
- EvaluationStage earliest_eval_stage);
+Result<Overload, StyledText> LookupUnary(Context& context,
+ core::UnaryOp op,
+ const core::type::Type* arg,
+ EvaluationStage earliest_eval_stage);
/// Lookup looks for the binary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
@@ -164,12 +166,12 @@
/// after shader creation time (EvaluationStage::kConstant).
/// @param is_compound true if the binary operator is being used as a compound assignment
/// @return the resolved binary operator overload
-Result<Overload, std::string> LookupBinary(Context& context,
- core::BinaryOp op,
- const core::type::Type* lhs,
- const core::type::Type* rhs,
- EvaluationStage earliest_eval_stage,
- bool is_compound);
+Result<Overload, StyledText> LookupBinary(Context& context,
+ core::BinaryOp op,
+ const core::type::Type* lhs,
+ const core::type::Type* rhs,
+ EvaluationStage earliest_eval_stage,
+ bool is_compound);
/// Lookup looks for the value constructor or conversion overload for the given CtorConv.
/// @param context the intrinsic context
@@ -184,12 +186,12 @@
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved type constructor or conversion function overload
-Result<Overload, std::string> LookupCtorConv(Context& context,
- std::string_view type_name,
- size_t type_id,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage);
+Result<Overload, StyledText> LookupCtorConv(Context& context,
+ std::string_view type_name,
+ size_t type_id,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage);
/// Table is a wrapper around a dialect to provide type-safe interface to the intrinsic table.
template <typename DIALECT>
@@ -219,12 +221,11 @@
/// only overloads with concrete argument types will be considered, as all
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
-
/// @return the resolved builtin function overload
- Result<Overload, std::string> Lookup(BuiltinFn builtin_fn,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage) {
+ Result<Overload, StyledText> Lookup(BuiltinFn builtin_fn,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage) {
std::string_view name = DIALECT::ToString(builtin_fn);
size_t id = static_cast<size_t>(builtin_fn);
return LookupFn(context, name, id, std::move(template_args), std::move(args),
@@ -243,9 +244,9 @@
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved unary operator overload
- Result<Overload, std::string> Lookup(core::UnaryOp op,
- const core::type::Type* arg,
- EvaluationStage earliest_eval_stage) {
+ Result<Overload, StyledText> Lookup(core::UnaryOp op,
+ const core::type::Type* arg,
+ EvaluationStage earliest_eval_stage) {
return LookupUnary(context, op, arg, earliest_eval_stage);
}
@@ -263,11 +264,11 @@
/// @param is_compound true if the binary operator is being used as a compound assignment
/// @return the resolved binary operator overload
- Result<Overload, std::string> Lookup(core::BinaryOp op,
- const core::type::Type* lhs,
- const core::type::Type* rhs,
- EvaluationStage earliest_eval_stage,
- bool is_compound) {
+ Result<Overload, StyledText> Lookup(core::BinaryOp op,
+ const core::type::Type* lhs,
+ const core::type::Type* rhs,
+ EvaluationStage earliest_eval_stage,
+ bool is_compound) {
return LookupBinary(context, op, lhs, rhs, earliest_eval_stage, is_compound);
}
@@ -281,12 +282,11 @@
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
-
/// @return the resolved type constructor or conversion function overload
- Result<Overload, std::string> Lookup(CtorConv type,
- VectorRef<const core::type::Type*> template_args,
- VectorRef<const core::type::Type*> args,
- EvaluationStage earliest_eval_stage) {
+ Result<Overload, StyledText> Lookup(CtorConv type,
+ VectorRef<const core::type::Type*> template_args,
+ VectorRef<const core::type::Type*> args,
+ EvaluationStage earliest_eval_stage) {
std::string_view name = DIALECT::ToString(type);
size_t id = static_cast<size_t>(type);
return LookupCtorConv(context, name, id, std::move(template_args), std::move(args),
diff --git a/src/tint/lang/core/intrinsic/table_data.h b/src/tint/lang/core/intrinsic/table_data.h
index b2d86c0..1ed619d 100644
--- a/src/tint/lang/core/intrinsic/table_data.h
+++ b/src/tint/lang/core/intrinsic/table_data.h
@@ -37,6 +37,8 @@
#include "src/tint/lang/core/parameter_usage.h"
#include "src/tint/utils/containers/enum_set.h"
#include "src/tint/utils/containers/slice.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/text_style.h"
/// Forward declaration
namespace tint::core::intrinsic {
@@ -414,13 +416,13 @@
/// @note: The matcher indices are progressed on calling.
inline Number Num(Number number);
- /// @returns a string representation of the next TypeMatcher from the matcher indices.
+ /// Prints the type matcher representation to @p out
/// @note: The matcher indices are progressed on calling.
- inline std::string TypeName();
+ inline void PrintType(StyledText& out);
- /// @returns a string representation of the next NumberMatcher from the matcher indices.
+ /// Prints the number matcher representation to @p out
/// @note: The matcher indices are progressed on calling.
- inline std::string NumName();
+ inline void PrintNum(StyledText& out);
private:
const MatcherIndex* matcher_indices_ = nullptr;
@@ -439,12 +441,12 @@
/// @see #MatchFn
MatchFn* const match;
- /// Returns a string representation of the matcher.
+ /// Prints the representation of the matcher.
/// Used for printing error messages when no overload is found.
- using StringFn = std::string(MatchState* state);
+ using PrintFn = void(MatchState* state, StyledText& out);
- /// @see #StringFn
- StringFn* const string;
+ /// @see #PrintFn
+ PrintFn* const print;
};
/// A NumberMatcher is the interface used to match a number or enumerator used
@@ -459,12 +461,12 @@
/// @see #MatchFn
MatchFn* const match;
- /// Returns a string representation of the matcher.
+ /// Prints the representation of the matcher.
/// Used for printing error messages when no overload is found.
- using StringFn = std::string(MatchState* state);
+ using PrintFn = void(MatchState* state, StyledText& out);
- /// @see #StringFn
- StringFn* const string;
+ /// @see #PrintFn
+ PrintFn* const print;
};
/// TableData holds the immutable data that holds the intrinsic data for a language.
@@ -600,16 +602,16 @@
return matcher.match(*this, number);
}
-std::string MatchState::TypeName() {
+void MatchState::PrintType(StyledText& out) {
TypeMatcherIndex matcher_index{(*matcher_indices_++).value};
auto& matcher = data[matcher_index];
- return matcher.string(this);
+ matcher.print(this, out);
}
-std::string MatchState::NumName() {
+void MatchState::PrintNum(StyledText& out) {
NumberMatcherIndex matcher_index{(*matcher_indices_++).value};
auto& matcher = data[matcher_index];
- return matcher.string(this);
+ matcher.print(this, out);
}
/// TemplateTypeMatcher is a Matcher for a template type.
@@ -630,9 +632,9 @@
}
return nullptr;
},
- /* string */
- [](MatchState* state) -> std::string {
- return state->data[state->overload.templates + INDEX].name;
+ /* print */
+ [](MatchState* state, StyledText& out) {
+ out << style::Type << state->data[state->overload.templates + INDEX].name;
},
};
};
@@ -651,9 +653,9 @@
}
return state.templates.Num(INDEX, number) ? number : Number::invalid;
},
- /* string */
- [](MatchState* state) -> std::string {
- return state->data[state->overload.templates + INDEX].name;
+ /* print */
+ [](MatchState* state, StyledText& out) {
+ out << style::Variable << state->data[state->overload.templates + INDEX].name;
},
};
};
diff --git a/src/tint/lang/core/intrinsic/table_test.cc b/src/tint/lang/core/intrinsic/table_test.cc
index ddf205f..52b25f4 100644
--- a/src/tint/lang/core/intrinsic/table_test.cc
+++ b/src/tint/lang/core/intrinsic/table_test.cc
@@ -65,7 +65,7 @@
auto* i32 = create<type::I32>();
auto result = table.Lookup(BuiltinFn::kCos, Empty, Vector{i32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchU32) {
@@ -85,7 +85,7 @@
auto result =
table.Lookup(BuiltinFn::kUnpack2X16Float, Empty, Vector{f32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchI32) {
@@ -112,7 +112,7 @@
auto result =
table.Lookup(BuiltinFn::kTextureLoad, Empty, Vector{tex, f32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchIU32AsI32) {
@@ -140,7 +140,7 @@
auto result =
table.Lookup(BuiltinFn::kCountOneBits, Empty, Vector{f32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchFIU32AsI32) {
@@ -184,7 +184,7 @@
auto result = table.Lookup(BuiltinFn::kClamp, Empty, Vector{bool_, bool_, bool_},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchBool) {
@@ -205,7 +205,7 @@
auto result =
table.Lookup(BuiltinFn::kSelect, Empty, Vector{f32, f32, f32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchPointer) {
@@ -226,7 +226,7 @@
auto result =
table.Lookup(BuiltinFn::kAtomicLoad, Empty, Vector{atomic_i32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchArray) {
@@ -248,7 +248,7 @@
auto result =
table.Lookup(BuiltinFn::kArrayLength, Empty, Vector{f32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchSampler) {
@@ -277,7 +277,7 @@
auto result = table.Lookup(BuiltinFn::kTextureSample, Empty, Vector{tex, f32, vec2f},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchSampledTexture) {
@@ -400,7 +400,7 @@
auto result = table.Lookup(BuiltinFn::kTextureLoad, Empty, Vector{f32, vec2i},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchTemplateType) {
@@ -420,7 +420,7 @@
auto result =
table.Lookup(BuiltinFn::kClamp, Empty, Vector{f32, u32, f32}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchOpenSizeVector) {
@@ -443,7 +443,7 @@
auto result = table.Lookup(BuiltinFn::kClamp, Empty, Vector{vec2f, u32, vec2f},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchOpenSizeMatrix) {
@@ -465,7 +465,7 @@
auto result =
table.Lookup(BuiltinFn::kDeterminant, Empty, Vector{mat3x2f}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(CoreIntrinsicTableTest, MatchDifferentArgsElementType_Builtin_ConstantEval) {
@@ -524,37 +524,37 @@
auto result = table.Lookup(BuiltinFn::kTextureDimensions, Empty, Vector{bool_, bool_},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_EQ(result.Failure(),
- R"(no matching call to textureDimensions(bool, bool)
+ ASSERT_EQ(result.Failure().Plain(),
+ R"(no matching call to 'textureDimensions(bool, bool)'
27 candidate functions:
- textureDimensions(texture: texture_1d<T>, level: L) -> u32 where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_1d<T>) -> u32 where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_3d<T>) -> vec3<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_depth_2d) -> vec2<u32>
- textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
- textureDimensions(texture: texture_storage_1d<F, A>) -> u32
- textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>
- textureDimensions(texture: texture_external) -> vec2<u32>
+ 'textureDimensions(texture: texture_1d<T>, level: L) -> u32' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_1d<T>) -> u32' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_1d<F, A>) -> u32'
+ 'textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>'
+ 'textureDimensions(texture: texture_external) -> vec2<u32>'
)");
}
@@ -564,37 +564,37 @@
auto result = table.Lookup(BuiltinFn::kTextureDimensions, Empty, Vector{tex, bool_},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_EQ(result.Failure(),
- R"(no matching call to textureDimensions(texture_depth_2d, bool)
+ ASSERT_EQ(result.Failure().Plain(),
+ R"(no matching call to 'textureDimensions(texture_depth_2d, bool)'
27 candidate functions:
- textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_1d<T>, level: L) -> u32 where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_2d) -> vec2<u32>
- textureDimensions(texture: texture_1d<T>) -> u32 where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_3d<T>) -> vec3<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
- textureDimensions(texture: texture_storage_1d<F, A>) -> u32
- textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>
- textureDimensions(texture: texture_external) -> vec2<u32>
+ 'textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_1d<T>, level: L) -> u32' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_1d<T>) -> u32' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_1d<F, A>) -> u32'
+ 'textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>'
+ 'textureDimensions(texture: texture_external) -> vec2<u32>'
)");
}
@@ -610,11 +610,11 @@
auto* bool_ = create<type::Bool>();
auto result = table.Lookup(UnaryOp::kNegation, bool_, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(), R"(no matching overload for operator - (bool)
+ EXPECT_EQ(result.Failure().Plain(), R"(no matching overload for 'operator - (bool)'
2 candidate operators:
- operator - (T) -> T where: T is f32, i32 or f16
- operator - (vecN<T>) -> vecN<T> where: T is f32, i32 or f16
+ 'operator - (T) -> T' where: 'T' is 'f32', 'i32' or 'f16'
+ 'operator - (vecN<T>) -> vecN<T>' where: 'T' is 'f32', 'i32' or 'f16'
)");
}
@@ -649,18 +649,18 @@
auto result = table.Lookup(BinaryOp::kMultiply, f32, bool_, EvaluationStage::kConstant,
/* is_compound */ false);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(), R"(no matching overload for operator * (f32, bool)
+ EXPECT_EQ(result.Failure().Plain(), R"(no matching overload for 'operator * (f32, bool)'
9 candidate operators:
- operator * (T, T) -> T where: T is f32, i32, u32 or f16
- operator * (vecN<T>, T) -> vecN<T> where: T is f32, i32, u32 or f16
- operator * (T, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
- operator * (T, matNxM<T>) -> matNxM<T> where: T is f32 or f16
- operator * (matNxM<T>, T) -> matNxM<T> where: T is f32 or f16
- operator * (vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
- operator * (matCxR<T>, vecC<T>) -> vecR<T> where: T is f32 or f16
- operator * (vecR<T>, matCxR<T>) -> vecC<T> where: T is f32 or f16
- operator * (matKxR<T>, matCxK<T>) -> matCxR<T> where: T is f32 or f16
+ 'operator * (T, T) -> T' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (vecN<T>, T) -> vecN<T>' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (T, vecN<T>) -> vecN<T>' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (T, matNxM<T>) -> matNxM<T>' where: 'T' is 'f32' or 'f16'
+ 'operator * (matNxM<T>, T) -> matNxM<T>' where: 'T' is 'f32' or 'f16'
+ 'operator * (vecN<T>, vecN<T>) -> vecN<T>' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (matCxR<T>, vecC<T>) -> vecR<T>' where: 'T' is 'f32' or 'f16'
+ 'operator * (vecR<T>, matCxR<T>) -> vecC<T>' where: 'T' is 'f32' or 'f16'
+ 'operator * (matKxR<T>, matCxK<T>) -> matCxR<T>' where: 'T' is 'f32' or 'f16'
)");
}
@@ -681,18 +681,18 @@
auto result = table.Lookup(BinaryOp::kMultiply, f32, bool_, EvaluationStage::kConstant,
/* is_compound */ true);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(), R"(no matching overload for operator *= (f32, bool)
+ EXPECT_EQ(result.Failure().Plain(), R"(no matching overload for 'operator *= (f32, bool)'
9 candidate operators:
- operator *= (T, T) -> T where: T is f32, i32, u32 or f16
- operator *= (vecN<T>, T) -> vecN<T> where: T is f32, i32, u32 or f16
- operator *= (T, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
- operator *= (T, matNxM<T>) -> matNxM<T> where: T is f32 or f16
- operator *= (matNxM<T>, T) -> matNxM<T> where: T is f32 or f16
- operator *= (vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32, u32 or f16
- operator *= (matCxR<T>, vecC<T>) -> vecR<T> where: T is f32 or f16
- operator *= (vecR<T>, matCxR<T>) -> vecC<T> where: T is f32 or f16
- operator *= (matKxR<T>, matCxK<T>) -> matCxR<T> where: T is f32 or f16
+ 'operator *= (T, T) -> T' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (vecN<T>, T) -> vecN<T>' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (T, vecN<T>) -> vecN<T>' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (T, matNxM<T>) -> matNxM<T>' where: 'T' is 'f32' or 'f16'
+ 'operator *= (matNxM<T>, T) -> matNxM<T>' where: 'T' is 'f32' or 'f16'
+ 'operator *= (vecN<T>, vecN<T>) -> vecN<T>' where: 'T' is 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (matCxR<T>, vecC<T>) -> vecR<T>' where: 'T' is 'f32' or 'f16'
+ 'operator *= (vecR<T>, matCxR<T>) -> vecC<T>' where: 'T' is 'f32' or 'f16'
+ 'operator *= (matKxR<T>, matCxK<T>) -> matCxR<T>' where: 'T' is 'f32' or 'f16'
)");
}
@@ -717,23 +717,23 @@
auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, f32, i32},
EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(),
- R"(no matching constructor for vec3<i32>(i32, f32, i32)
+ EXPECT_EQ(result.Failure().Plain(),
+ R"(no matching constructor for 'vec3<i32>(i32, f32, i32)'
6 candidate constructors:
- vec3<T>(x: T, y: T, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(xy: vec2<T>, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(x: T, yz: vec2<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>() -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ 'vec3<T>(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>() -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec3<T>(vec3<U>) -> vec3<T> where: T is f32, U is i32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is f16, U is f32, i32, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is i32, U is f32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is u32, U is f32, f16, i32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is bool, U is f32, f16, i32 or u32
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f32', 'U' is 'i32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f16', 'U' is 'f32', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'i32', 'U' is 'f32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'u32', 'U' is 'f32', 'f16', 'i32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'bool', 'U' is 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -790,23 +790,23 @@
auto result =
table.Lookup(CtorConv::kVec3, Vector{f32}, Vector{arr}, EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(),
- R"(no matching constructor for vec3<f32>(array<u32>)
+ EXPECT_EQ(result.Failure().Plain(),
+ R"(no matching constructor for 'vec3<f32>(array<u32>)'
6 candidate constructors:
- vec3<T>(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>() -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(x: T, yz: vec2<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(xy: vec2<T>, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(x: T, y: T, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ 'vec3<T>(vec3<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>() -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec3<T>(vec3<U>) -> vec3<T> where: T is f32, U is i32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is f16, U is f32, i32, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is i32, U is f32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is u32, U is f32, f16, i32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is bool, U is f32, f16, i32 or u32
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f32', 'U' is 'i32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f16', 'U' is 'f32', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'i32', 'U' is 'f32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'u32', 'U' is 'f32', 'f16', 'i32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'bool', 'U' is 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -848,7 +848,7 @@
auto result =
table.Lookup(BuiltinFn::kAbs, Empty, std::move(arg_tys), EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
} // namespace
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index afc234f..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
@@ -101,60 +102,51 @@
Result<SuccessType> Run();
protected:
- /// @param inst the instruction
- /// @param err the error message
- /// @returns a string with the instruction name name and error message formatted
- std::string InstError(const Instruction* inst, std::string err);
-
/// Adds an error for the @p inst and highlights the instruction in the disassembly
/// @param inst the instruction
- /// @param err the error string
- void AddError(const Instruction* inst, std::string err);
+ /// @returns the diagnostic
+ diag::Diagnostic& AddError(const Instruction* inst);
/// Adds an error for the @p inst operand at @p idx and highlights the operand in the
/// disassembly
/// @param inst the instaruction
/// @param idx the operand index
- /// @param err the error string
- void AddError(const Instruction* inst, size_t idx, std::string err);
+ /// @returns the diagnostic
+ diag::Diagnostic& AddError(const Instruction* inst, size_t idx);
/// Adds an error for the @p inst result at @p idx and highlgihts the result in the disassembly
/// @param inst the instruction
/// @param idx the result index
- /// @param err the error string
- void AddResultError(const Instruction* inst, size_t idx, std::string err);
+ /// @returns the diagnostic
+ diag::Diagnostic& AddResultError(const Instruction* inst, size_t idx);
/// Adds an error the @p block and highlights the block header in the disassembly
/// @param blk the block
- /// @param err the error string
- void AddError(const Block* blk, std::string err);
+ /// @returns the diagnostic
+ diag::Diagnostic& AddError(const Block* blk);
+
+ /// Adds an error the @p block and highlights the block header in the disassembly
+ /// @param src the source lines to highlight
+ /// @returns the diagnostic
+ diag::Diagnostic& AddError(Source src);
/// Adds a note to @p inst and highlights the instruction in the disassembly
/// @param inst the instruction
- /// @param err the message to emit
- void AddNote(const Instruction* inst, std::string err);
+ diag::Diagnostic& AddNote(const Instruction* inst);
/// Adds a note to @p inst for operand @p idx and highlights the operand in the
/// disassembly
/// @param inst the instruction
/// @param idx the operand index
- /// @param err the message string
- void AddNote(const Instruction* inst, size_t idx, std::string err);
+ diag::Diagnostic& AddNote(const Instruction* inst, size_t idx);
/// Adds a note to @p blk and highlights the block in the disassembly
/// @param blk the block
- /// @param err the message to emit
- void AddNote(const Block* blk, std::string err);
-
- /// Adds an error to the diagnostics
- /// @param err the message to emit
- /// @param src the source lines to highlight
- void AddError(std::string err, Source src = {});
+ diag::Diagnostic& AddNote(const Block* blk);
/// Adds a note to the diagnostics
- /// @param note the note to emit
/// @param src the source lines to highlight
- void AddNote(std::string note, Source src = {});
+ diag::Diagnostic& AddNote(Source src = {});
/// @param v the value to get the name for
/// @returns the name for the given value
@@ -316,7 +308,8 @@
for (auto& func : mod_.functions) {
if (!all_functions_.Add(func.Get())) {
- AddError("function '" + Name(func.Get()) + "' added to module multiple times");
+ AddError(Source{}) << "function " << style::Function << Name(func.Get()) << style::Plain
+ << " added to module multiple times";
}
}
@@ -328,92 +321,94 @@
// Check for orphaned instructions.
for (auto* inst : mod_.instructions.Objects()) {
if (inst->Alive() && !visited_instructions_.Contains(inst)) {
- AddError("orphaned instruction: " + inst->FriendlyName());
+ AddError(inst) << "orphaned instruction: " << inst->FriendlyName();
}
}
}
if (diagnostics_.ContainsErrors()) {
DisassembleIfNeeded();
- diagnostics_.AddNote(tint::diag::System::IR,
- "# Disassembly\n" + disassembly_file->content.data, {});
+ diagnostics_.AddNote(tint::diag::System::IR, Source{}) << "# Disassembly\n"
+ << disassembly_file->content.data;
return Failure{std::move(diagnostics_)};
}
return Success;
}
-std::string Validator::InstError(const Instruction* inst, std::string err) {
- return std::string(inst->FriendlyName()) + ": " + err;
-}
-
-void Validator::AddError(const Instruction* inst, std::string err) {
+diag::Diagnostic& Validator::AddError(const Instruction* inst) {
DisassembleIfNeeded();
auto src = dis_.InstructionSource(inst);
- AddError(std::move(err), src);
+ auto& diag = AddError(src) << inst->FriendlyName() << ": ";
if (current_block_) {
- AddNote(current_block_, "In block");
+ AddNote(current_block_) << "In block";
}
+ return diag;
}
-void Validator::AddError(const Instruction* inst, size_t idx, std::string err) {
+diag::Diagnostic& Validator::AddError(const Instruction* inst, size_t idx) {
DisassembleIfNeeded();
auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
- AddError(std::move(err), src);
+ auto& diag = AddError(src) << inst->FriendlyName() << ": ";
if (current_block_) {
- AddNote(current_block_, "In block");
+ AddNote(current_block_) << "In block";
}
+
+ return diag;
}
-void Validator::AddResultError(const Instruction* inst, size_t idx, std::string err) {
+diag::Diagnostic& Validator::AddResultError(const Instruction* inst, size_t idx) {
DisassembleIfNeeded();
auto src = dis_.ResultSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
- AddError(std::move(err), src);
+ auto& diag = AddError(src) << inst->FriendlyName() << ": ";
if (current_block_) {
- AddNote(current_block_, "In block");
+ AddNote(current_block_) << "In block";
}
+ return diag;
}
-void Validator::AddError(const Block* blk, std::string err) {
+diag::Diagnostic& Validator::AddError(const Block* blk) {
DisassembleIfNeeded();
auto src = dis_.BlockSource(blk);
- AddError(std::move(err), src);
+ return AddError(src);
}
-void Validator::AddNote(const Instruction* inst, std::string err) {
+diag::Diagnostic& Validator::AddNote(const Instruction* inst) {
DisassembleIfNeeded();
auto src = dis_.InstructionSource(inst);
- AddNote(std::move(err), src);
+ return AddNote(src);
}
-void Validator::AddNote(const Instruction* inst, size_t idx, std::string err) {
+diag::Diagnostic& Validator::AddNote(const Instruction* inst, size_t idx) {
DisassembleIfNeeded();
auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
- AddNote(std::move(err), src);
+ return AddNote(src);
}
-void Validator::AddNote(const Block* blk, std::string err) {
+diag::Diagnostic& Validator::AddNote(const Block* blk) {
DisassembleIfNeeded();
auto src = dis_.BlockSource(blk);
- AddNote(std::move(err), src);
+ return AddNote(src);
}
-void Validator::AddError(std::string err, Source src) {
- auto& diag = diagnostics_.AddError(tint::diag::System::IR, std::move(err), src);
+diag::Diagnostic& Validator::AddError(Source src) {
+ auto& diag = diagnostics_.AddError(tint::diag::System::IR, src);
if (src.range != Source::Range{{}}) {
diag.source.file = disassembly_file.get();
diag.owned_file = disassembly_file;
}
+ return diag;
}
-void Validator::AddNote(std::string note, Source src) {
- auto& diag = diagnostics_.AddNote(tint::diag::System::IR, std::move(note), src);
+diag::Diagnostic& Validator::AddNote(Source src) {
+ auto& diag = diagnostics_.AddNote(tint::diag::System::IR, src);
if (src.range != Source::Range{{}}) {
diag.source.file = disassembly_file.get();
diag.owned_file = disassembly_file;
}
+ return diag;
}
std::string Validator::Name(const Value* v) {
@@ -422,7 +417,7 @@
void Validator::CheckOperandNotNull(const Instruction* inst, const ir::Value* operand, size_t idx) {
if (operand == nullptr) {
- AddError(inst, idx, InstError(inst, "operand is undefined"));
+ AddError(inst, idx) << "operand is undefined";
}
}
@@ -440,15 +435,12 @@
for (auto* inst : *blk) {
if (inst->Block() != blk) {
- AddError(
- inst,
- InstError(inst, "instruction in root block does not have root block as parent"));
+ AddError(inst) << "instruction in root block does not have root block as parent";
continue;
}
auto* var = inst->As<ir::Var>();
if (!var) {
- AddError(inst,
- std::string("root block: invalid instruction: ") + inst->TypeInfo().name);
+ AddError(inst) << "root block: invalid instruction: " << inst->TypeInfo().name;
continue;
}
CheckInstruction(var);
@@ -463,17 +455,17 @@
TINT_SCOPED_ASSIGNMENT(current_block_, blk);
if (!blk->Terminator()) {
- AddError(blk, "block: does not end in a terminator instruction");
+ AddError(blk) << "block: does not end in a terminator instruction";
}
for (auto* inst : *blk) {
if (inst->Block() != blk) {
- AddError(inst, InstError(inst, "block instruction does not have same block as parent"));
- AddNote(current_block_, "In block");
+ AddError(inst) << "block instruction does not have same block as parent";
+ AddNote(current_block_) << "In block";
continue;
}
if (inst->Is<ir::Terminator>() && inst != blk->Terminator()) {
- AddError(inst, "block: terminator which isn't the final instruction");
+ AddError(inst) << "block: terminator which isn't the final instruction";
continue;
}
@@ -484,22 +476,21 @@
void Validator::CheckInstruction(const Instruction* inst) {
visited_instructions_.Add(inst);
if (!inst->Alive()) {
- AddError(inst, InstError(inst, "destroyed instruction found in instruction list"));
+ AddError(inst) << "destroyed instruction found in instruction list";
return;
}
auto results = inst->Results();
for (size_t i = 0; i < results.Length(); ++i) {
auto* res = results[i];
if (!res) {
- AddResultError(inst, i, InstError(inst, "result is undefined"));
+ AddResultError(inst, i) << "result is undefined";
continue;
}
if (res->Instruction() == nullptr) {
- AddResultError(inst, i, InstError(inst, "instruction of result is undefined"));
+ AddResultError(inst, i) << "instruction of result is undefined";
} else if (res->Instruction() != inst) {
- AddResultError(inst, i,
- InstError(inst, "instruction of result is a different instruction"));
+ AddResultError(inst, i) << "instruction of result is a different instruction";
}
}
@@ -513,11 +504,11 @@
// Note, a `nullptr` is a valid operand in some cases, like `var` so we can't just check
// for `nullptr` here.
if (!op->Alive()) {
- AddError(inst, i, InstError(inst, "operand is not alive"));
+ AddError(inst, i) << "operand is not alive";
}
if (!op->HasUsage(inst, i)) {
- AddError(inst, i, InstError(inst, "operand missing usage"));
+ AddError(inst, i) << "operand missing usage";
}
}
@@ -538,13 +529,13 @@
[&](const Terminator* b) { CheckTerminator(b); }, //
[&](const Unary* u) { CheckUnary(u); }, //
[&](const Var* var) { CheckVar(var); }, //
- [&](const Default) { AddError(inst, InstError(inst, "missing validation")); });
+ [&](const Default) { AddError(inst) << "missing validation"; });
}
void Validator::CheckVar(const Var* var) {
if (var->Result(0) && var->Initializer()) {
if (var->Initializer()->Type() != var->Result(0)->Type()->UnwrapPtr()) {
- AddError(var, InstError(var, "initializer has incorrect type"));
+ AddError(var) << "initializer has incorrect type";
}
}
}
@@ -554,7 +545,7 @@
if (let->Result(0) && let->Value()) {
if (let->Result(0)->Type() != let->Value()->Type()) {
- AddError(let, InstError(let, "result type does not match value type"));
+ AddError(let) << "result type does not match value type";
}
}
}
@@ -587,42 +578,39 @@
auto result = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
Empty, args, core::EvaluationStage::kRuntime);
if (result != Success) {
- AddError(call, InstError(call, result.Failure()));
+ AddError(call) << result.Failure();
return;
}
if (result->return_type != call->Result(0)->Type()) {
- AddError(call, InstError(call, "call result type does not match builtin return type"));
+ AddError(call) << "call result type does not match builtin return type";
}
}
void Validator::CheckUserCall(const UserCall* call) {
if (!all_functions_.Contains(call->Target())) {
- AddError(call, UserCall::kFunctionOperandOffset,
- InstError(call, "call target is not part of the module"));
+ AddError(call, UserCall::kFunctionOperandOffset) << "call target is not part of the module";
}
if (call->Target()->Stage() != Function::PipelineStage::kUndefined) {
- AddError(call, UserCall::kFunctionOperandOffset,
- InstError(call, "call target must not have a pipeline stage"));
+ AddError(call, UserCall::kFunctionOperandOffset)
+ << "call target must not have a pipeline stage";
}
auto args = call->Args();
auto params = call->Target()->Params();
if (args.Length() != params.Length()) {
- StringStream err;
- err << "function has " << params.Length() << " parameters, but call provides "
+ AddError(call, UserCall::kFunctionOperandOffset)
+ << "function has " << params.Length() << " parameters, but call provides "
<< args.Length() << " arguments";
- AddError(call, UserCall::kFunctionOperandOffset, InstError(call, err.str()));
return;
}
for (size_t i = 0; i < args.Length(); i++) {
if (args[i]->Type() != params[i]->Type()) {
- StringStream err;
- err << "function parameter " << i << " is of type " << params[i]->Type()->FriendlyName()
+ AddError(call, UserCall::kArgsOperandOffset + i)
+ << "function parameter " << i << " is of type " << params[i]->Type()->FriendlyName()
<< ", but argument is of type " << args[i]->Type()->FriendlyName();
- AddError(call, UserCall::kArgsOperandOffset + i, InstError(call, err.str()));
}
}
}
@@ -643,10 +631,8 @@
};
for (size_t i = 0; i < a->Indices().Length(); i++) {
- auto err = [&](std::string msg) {
- AddError(a, i + Access::kIndicesOperandOffset, InstError(a, msg));
- };
- auto note = [&](std::string msg) { AddNote(a, i + Access::kIndicesOperandOffset, msg); };
+ auto err = [&](std::string msg) { AddError(a, i + Access::kIndicesOperandOffset) << msg; };
+ auto note = [&](std::string msg) { AddNote(a, i + Access::kIndicesOperandOffset) << msg; };
auto* index = a->Indices()[i];
if (TINT_UNLIKELY(!index->Type()->is_integer_scalar())) {
@@ -705,8 +691,8 @@
}
if (TINT_UNLIKELY(!ok)) {
- AddError(a, InstError(a, "result of access chain is type " + current() +
- " but instruction type is " + want->FriendlyName()));
+ AddError(a) << "result of access chain is type " << current() << " but instruction type is "
+ << want->FriendlyName();
}
}
@@ -725,7 +711,7 @@
core::intrinsic::LookupBinary(context, b->Op(), b->LHS()->Type(), b->RHS()->Type(),
core::EvaluationStage::kRuntime, /* is_compound */ false);
if (overload != Success) {
- AddError(b, InstError(b, overload.Failure()));
+ AddError(b) << overload.Failure();
return;
}
@@ -735,7 +721,7 @@
err << "binary instruction result type (" << result->Type()->FriendlyName()
<< ") does not match overload result type ("
<< overload->return_type->FriendlyName() << ")";
- AddError(b, InstError(b, err.str()));
+ AddError(b) << err.str();
}
}
}
@@ -755,7 +741,7 @@
auto overload = core::intrinsic::LookupUnary(context, u->Op(), u->Val()->Type(),
core::EvaluationStage::kRuntime);
if (overload != Success) {
- AddError(u, InstError(u, overload.Failure()));
+ AddError(u) << overload.Failure();
return;
}
@@ -765,7 +751,7 @@
err << "unary instruction result type (" << result->Type()->FriendlyName()
<< ") does not match overload result type ("
<< overload->return_type->FriendlyName() << ")";
- AddError(u, InstError(u, err.str()));
+ AddError(u) << err.str();
}
}
}
@@ -775,8 +761,7 @@
CheckOperandNotNull(if_, if_->Condition(), If::kConditionOperandOffset);
if (if_->Condition() && !if_->Condition()->Type()->Is<core::type::Bool>()) {
- AddError(if_, If::kConditionOperandOffset,
- InstError(if_, "condition must be a `bool` type"));
+ AddError(if_, If::kConditionOperandOffset) << "condition must be a `bool` type";
}
control_stack_.Push(if_);
@@ -824,38 +809,36 @@
[&](const ir::Return* ret) { CheckReturn(ret); }, //
[&](const ir::TerminateInvocation*) {}, //
[&](const ir::Unreachable*) {}, //
- [&](Default) { AddError(b, InstError(b, "missing validation")); });
+ [&](Default) { AddError(b) << "missing validation"; });
}
void Validator::CheckExit(const Exit* e) {
if (e->ControlInstruction() == nullptr) {
- AddError(e, InstError(e, "has no parent control instruction"));
+ AddError(e) << "has no parent control instruction";
return;
}
if (control_stack_.IsEmpty()) {
- AddError(e, InstError(e, "found outside all control instructions"));
+ AddError(e) << "found outside all control instructions";
return;
}
auto results = e->ControlInstruction()->Results();
auto args = e->Args();
if (results.Length() != args.Length()) {
- AddError(e, InstError(e, std::string("args count (") + std::to_string(args.Length()) +
- ") does not match control instruction result count (" +
- std::to_string(results.Length()) + ")"));
- AddNote(e->ControlInstruction(), "control instruction");
+ AddError(e) << ("args count (") << args.Length()
+ << ") does not match control instruction result count (" << results.Length()
+ << ")";
+ AddNote(e->ControlInstruction()) << "control instruction";
return;
}
for (size_t i = 0; i < results.Length(); ++i) {
if (results[i] && args[i] && results[i]->Type() != args[i]->Type()) {
- AddError(
- e, i,
- InstError(e, std::string("argument type (") + results[i]->Type()->FriendlyName() +
- ") does not match control instruction type (" +
- args[i]->Type()->FriendlyName() + ")"));
- AddNote(e->ControlInstruction(), "control instruction");
+ AddError(e, i) << "argument type (" << results[i]->Type()->FriendlyName()
+ << ") does not match control instruction type ("
+ << args[i]->Type()->FriendlyName() << ")";
+ AddNote(e->ControlInstruction()) << "control instruction";
}
}
@@ -864,31 +847,31 @@
[&](const ir::ExitIf* i) { CheckExitIf(i); }, //
[&](const ir::ExitLoop* l) { CheckExitLoop(l); }, //
[&](const ir::ExitSwitch* s) { CheckExitSwitch(s); }, //
- [&](Default) { AddError(e, InstError(e, "missing validation")); });
+ [&](Default) { AddError(e) << "missing validation"; });
}
void Validator::CheckExitIf(const ExitIf* e) {
if (control_stack_.Back() != e->If()) {
- AddError(e, InstError(e, "if target jumps over other control instructions"));
- AddNote(control_stack_.Back(), "first control instruction jumped");
+ AddError(e) << "if target jumps over other control instructions";
+ AddNote(control_stack_.Back()) << "first control instruction jumped";
}
}
void Validator::CheckReturn(const Return* ret) {
auto* func = ret->Func();
if (func == nullptr) {
- AddError(ret, InstError(ret, "undefined function"));
+ AddError(ret) << "undefined function";
return;
}
if (func->ReturnType()->Is<core::type::Void>()) {
if (ret->Value()) {
- AddError(ret, InstError(ret, "unexpected return value"));
+ AddError(ret) << "unexpected return value";
}
} else {
if (!ret->Value()) {
- AddError(ret, InstError(ret, "expected return value"));
+ AddError(ret) << "expected return value";
} else if (ret->Value()->Type() != func->ReturnType()) {
- AddError(ret, InstError(ret, "return value type does not match function return type"));
+ AddError(ret) << "return value type does not match function return type";
}
}
}
@@ -902,15 +885,14 @@
}
// A exit switch can step over if instructions, but no others.
if (!ctrl->Is<ir::If>()) {
- AddError(exit, InstError(exit, std::string(control->FriendlyName()) +
- " target jumps over other control instructions"));
- AddNote(ctrl, "first control instruction jumped");
+ AddError(exit) << control->FriendlyName()
+ << " target jumps over other control instructions";
+ AddNote(ctrl) << "first control instruction jumped";
return;
}
}
if (!found) {
- AddError(exit, InstError(exit, std::string(control->FriendlyName()) +
- " not found in parent control instructions"));
+ AddError(exit) << control->FriendlyName() << " not found in parent control instructions";
}
}
@@ -927,14 +909,14 @@
// Found parent loop
if (inst->Block()->Parent() == control) {
if (inst->Block() == control->Continuing()) {
- AddError(l, InstError(l, "loop exit jumps out of continuing block"));
+ AddError(l) << "loop exit jumps out of continuing block";
if (control->Continuing() != l->Block()) {
- AddNote(control->Continuing(), "in continuing block");
+ AddNote(control->Continuing()) << "in continuing block";
}
} else if (inst->Block() == control->Initializer()) {
- AddError(l, InstError(l, "loop exit not permitted in loop initializer"));
+ AddError(l) << "loop exit not permitted in loop initializer";
if (control->Initializer() != l->Block()) {
- AddNote(control->Initializer(), "in initializer block");
+ AddNote(control->Initializer()) << "in initializer block";
}
}
break;
@@ -949,11 +931,11 @@
if (auto* from = l->From()) {
auto* mv = from->Type()->As<core::type::MemoryView>();
if (!mv) {
- AddError(l, Load::kFromOperandOffset, "load source operand is not a memory view");
+ AddError(l, Load::kFromOperandOffset) << "load source operand is not a memory view";
return;
}
if (l->Result(0)->Type() != mv->StoreType()) {
- AddError(l, Load::kFromOperandOffset, "result type does not match source store type");
+ AddError(l, Load::kFromOperandOffset) << "result type does not match source store type";
}
}
}
@@ -965,11 +947,12 @@
if (auto* to = s->To()) {
auto* mv = to->Type()->As<core::type::MemoryView>();
if (!mv) {
- AddError(s, Store::kFromOperandOffset, "store target operand is not a memory view");
+ AddError(s, Store::kFromOperandOffset)
+ << "store target operand is not a memory view";
return;
}
if (from->Type() != mv->StoreType()) {
- AddError(s, Store::kFromOperandOffset, "value type does not match store type");
+ AddError(s, Store::kFromOperandOffset) << "value type does not match store type";
}
}
}
@@ -983,7 +966,7 @@
if (auto* res = l->Result(0)) {
if (auto* el_ty = GetVectorPtrElementType(l, LoadVectorElement::kFromOperandOffset)) {
if (res->Type() != el_ty) {
- AddResultError(l, 0, "result type does not match vector pointer element type");
+ AddResultError(l, 0) << "result type does not match vector pointer element type";
}
}
}
@@ -997,8 +980,8 @@
if (auto* value = s->Value()) {
if (auto* el_ty = GetVectorPtrElementType(s, StoreVectorElement::kToOperandOffset)) {
if (value->Type() != el_ty) {
- AddError(s, StoreVectorElement::kValueOperandOffset,
- "value type does not match vector pointer element type");
+ AddError(s, StoreVectorElement::kValueOperandOffset)
+ << "value type does not match vector pointer element type";
}
}
}
@@ -1023,7 +1006,7 @@
}
}
- AddError(inst, idx, "operand must be a pointer to vector, got " + type->FriendlyName());
+ AddError(inst, idx) << "operand must be a pointer to vector, got " << type->FriendlyName();
return nullptr;
}
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index cd5faeb..256cf8f 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -60,7 +60,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:2:3 error: root block: invalid instruction: tint::core::ir::Loop
+ R"(:2:3 error: loop: root block: invalid instruction: tint::core::ir::Loop
loop [b: %b2] { # loop_1
^^^^^^^^^^^^^
@@ -922,7 +922,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:3:5 error: block: terminator which isn't the final instruction
+ R"(:3:5 error: return: block: terminator which isn't the final instruction
ret
^^^
@@ -1447,7 +1447,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
- EXPECT_EQ(res.Failure().reason.Str(), R"(error: orphaned instruction: load
+ EXPECT_EQ(res.Failure().reason.Str(), R"(error: load: orphaned instruction: load
note: # Disassembly
%my_func = func():void -> %b1 {
%b1 = block {
@@ -3157,7 +3157,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:4:19 error: load source operand is not a memory view
+ R"(:4:19 error: load: load source operand is not a memory view
%3:f32 = load %l
^^
@@ -3188,7 +3188,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:4:19 error: result type does not match source store type
+ R"(:4:19 error: load: result type does not match source store type
%3:f32 = load %2
^^
@@ -3277,7 +3277,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:4:15 error: store target operand is not a memory view
+ R"(:4:15 error: store: store target operand is not a memory view
store %l, 42u
^^^
@@ -3308,7 +3308,7 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:4:15 error: value type does not match store type
+ R"(:4:15 error: store: value type does not match store type
store %2, 42u
^^^
@@ -3468,7 +3468,7 @@
%b1 = block {
^^^^^^^^^^^
-:4:37 error: value type does not match vector pointer element type
+:4:37 error: store_vector_element: value type does not match vector pointer element type
store_vector_element %2, undef, 2i
^^
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index c40bcbb..6ecc839 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -393,8 +393,8 @@
auto* dst_type = TypeOf(call);
if (!dst_type->is_integer_scalar_or_vector() && !dst_type->is_float_scalar_or_vector()) {
- diagnostics_.AddError(diag::System::Writer,
- "Unable to do bitcast to type " + dst_type->FriendlyName());
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Unable to do bitcast to type " << dst_type->FriendlyName();
return;
}
@@ -1517,9 +1517,7 @@
out << "imageStore";
break;
default:
- diagnostics_.AddError(diag::System::Writer,
- "Internal compiler error: Unhandled texture builtin '" +
- std::string(builtin->str()) + "'");
+ TINT_ICE() << "Unhandled texture builtin '" << std::string(builtin->str()) << "'";
return;
}
@@ -1742,8 +1740,8 @@
case wgsl::BuiltinFn::kUnpack4X8Unorm:
return "unpackUnorm4x8";
default:
- diagnostics_.AddError(diag::System::Writer,
- "Unknown builtin method: " + std::string(builtin->str()));
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Unknown builtin method: " << builtin;
}
return "";
@@ -1921,9 +1919,9 @@
[&](const ast::Let* let) { EmitProgramConstVariable(let); },
[&](const ast::Override*) {
// Override is removed with SubstituteOverride
- diagnostics_.AddError(diag::System::Writer,
- "override-expressions should have been removed with the "
- "SubstituteOverride transform");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "override-expressions should have been removed with the "
+ "SubstituteOverride transform";
},
[&](const ast::Const*) {
// Constants are embedded at their use
@@ -2187,10 +2185,9 @@
out << "local_size_" << (i == 0 ? "x" : i == 1 ? "y" : "z") << " = ";
if (!wgsize[i].has_value()) {
- diagnostics_.AddError(
- diag::System::Writer,
- "override-expressions should have been removed with the SubstituteOverride "
- "transform");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "override-expressions should have been removed with the SubstituteOverride "
+ "transform";
return;
}
out << std::to_string(wgsize[i].value());
@@ -2291,8 +2288,8 @@
auto count = a->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return;
}
@@ -2343,7 +2340,8 @@
return;
}
}
- diagnostics_.AddError(diag::System::Writer, "unknown integer literal suffix type");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unknown integer literal suffix type";
}, //
TINT_ICE_ON_NO_MATCH);
}
@@ -2395,8 +2393,8 @@
auto count = arr->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return;
}
@@ -2407,8 +2405,8 @@
EmitZeroValue(out, arr->ElemType());
}
} else {
- diagnostics_.AddError(diag::System::Writer,
- "Invalid type for zero emission: " + type->FriendlyName());
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Invalid type for zero emission: " << type->FriendlyName();
}
}
@@ -2683,8 +2681,8 @@
} else {
auto count = arr->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return;
}
sizes.push_back(count.value());
@@ -2839,7 +2837,7 @@
} else if (type->Is<core::type::Void>()) {
out << "void";
} else {
- diagnostics_.AddError(diag::System::Writer, "unknown type in EmitType");
+ diagnostics_.AddError(diag::System::Writer, Source{}) << "unknown type in EmitType";
}
}
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc
index 475f00a..4c8c40c 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc
@@ -35,7 +35,7 @@
using GlslASTPrinterTest = TestHelper;
TEST_F(GlslASTPrinterTest, InvalidProgram) {
- Diagnostics().AddError(diag::System::Writer, "make the program invalid");
+ Diagnostics().AddError(diag::System::Writer, Source{}) << "make the program invalid";
ASSERT_FALSE(IsValid());
auto program = resolver::Resolve(*this);
ASSERT_FALSE(program.IsValid());
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
index 25cc723..9b09f57 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
@@ -441,8 +441,8 @@
auto* binding_info = inputs.Get<BindingInfo>();
if (!binding_info) {
ProgramBuilder b;
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
index 7d3a4ab..89cebe1 100644
--- a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
@@ -74,10 +74,9 @@
ApplyResult Run() {
auto* cfg = inputs.Get<Config>();
if (cfg == nullptr) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "missing transform data for " +
- std::string(tint::TypeInfo::Of<TextureBuiltinsFromUniform>().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for "
+ << tint::TypeInfo::Of<TextureBuiltinsFromUniform>().name;
return resolver::Resolve(b);
}
ubo_bindingpoint_ordering = cfg->ubo_bindingpoint_ordering;
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index ab2551a..658beeb 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -702,8 +702,8 @@
auto* dst_el_type = dst_type->DeepestElement();
if (!dst_el_type->is_integer_scalar() && !dst_el_type->is_float_scalar()) {
- diagnostics_.AddError(diag::System::Writer,
- "Unable to do bitcast to type " + dst_el_type->FriendlyName());
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Unable to do bitcast to type " << dst_el_type->FriendlyName();
return false;
}
@@ -2450,8 +2450,7 @@
break;
}
default:
- diagnostics_.AddError(diag::System::Writer,
- "Internal error: unhandled data packing builtin");
+ TINT_ICE() << " unhandled data packing builtin";
return false;
}
@@ -2517,8 +2516,7 @@
Line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
break;
default:
- diagnostics_.AddError(diag::System::Writer,
- "Internal error: unhandled data packing builtin");
+ TINT_ICE() << "unhandled data packing builtin";
return false;
}
@@ -2579,28 +2577,27 @@
return false;
}
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- std::string functionName;
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kDot4I8Packed:
- Line(b) << "int accumulator = 0;";
- functionName = "dot4add_i8packed";
- break;
- case wgsl::BuiltinFn::kDot4U8Packed:
- Line(b) << "uint accumulator = 0u;";
- functionName = "dot4add_u8packed";
- break;
- default:
- diagnostics_.AddError(diag::System::Writer,
- "Internal error: unhandled DP4a builtin");
- return false;
- }
- Line(b) << "return " << functionName << "(" << params[0] << ", " << params[1]
- << ", accumulator);";
+ return CallBuiltinHelper(out, expr, builtin,
+ [&](TextBuffer* b, const std::vector<std::string>& params) {
+ std::string functionName;
+ switch (builtin->Fn()) {
+ case wgsl::BuiltinFn::kDot4I8Packed:
+ Line(b) << "int accumulator = 0;";
+ functionName = "dot4add_i8packed";
+ break;
+ case wgsl::BuiltinFn::kDot4U8Packed:
+ Line(b) << "uint accumulator = 0u;";
+ functionName = "dot4add_u8packed";
+ break;
+ default:
+ TINT_ICE() << "Internal error: unhandled DP4a builtin";
+ return false;
+ }
+ Line(b) << "return " << functionName << "(" << params[0] << ", "
+ << params[1] << ", accumulator);";
- return true;
- });
+ return true;
+ });
}
bool ASTPrinter::EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin) {
@@ -2932,9 +2929,7 @@
out << "[";
break;
default:
- diagnostics_.AddError(diag::System::Writer,
- "Internal compiler error: Unhandled texture builtin '" +
- std::string(builtin->str()) + "'");
+ TINT_ICE() << "Unhandled texture builtin '" << builtin << "'";
return false;
}
@@ -3120,8 +3115,8 @@
case wgsl::BuiltinFn::kSubgroupBroadcast:
return "WaveReadLaneAt";
default:
- diagnostics_.AddError(diag::System::Writer,
- "Unknown builtin method: " + std::string(builtin->str()));
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Unknown builtin method: " << builtin->str();
}
return "";
@@ -3392,9 +3387,8 @@
case core::AddressSpace::kWorkgroup:
return EmitWorkgroupVariable(sem);
case core::AddressSpace::kPushConstant:
- diagnostics_.AddError(
- diag::System::Writer,
- "unhandled address space " + tint::ToString(sem->AddressSpace()));
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unhandled address space " << sem->AddressSpace();
return false;
default: {
TINT_ICE() << "unhandled address space " << sem->AddressSpace();
@@ -3404,9 +3398,9 @@
},
[&](const ast::Override*) {
// Override is removed with SubstituteOverride
- diagnostics_.AddError(diag::System::Writer,
- "override-expressions should have been removed with the "
- "SubstituteOverride transform");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "override-expressions should have been removed with the SubstituteOverride "
+ "transform";
return false;
},
[&](const ast::Const*) {
@@ -3629,10 +3623,9 @@
out << ", ";
}
if (!wgsize[i].has_value()) {
- diagnostics_.AddError(
- diag::System::Writer,
- "override-expressions should have been removed with the SubstituteOverride "
- "transform");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "override-expressions should have been removed with the "
+ "SubstituteOverride transform";
return false;
}
out << std::to_string(wgsize[i].value());
@@ -3784,8 +3777,8 @@
auto count = a->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return false;
}
@@ -3880,7 +3873,8 @@
out << "u";
return true;
}
- diagnostics_.AddError(diag::System::Writer, "unknown integer literal suffix type");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unknown integer literal suffix type";
return false;
}, //
TINT_ICE_ON_NO_MATCH);
@@ -4347,8 +4341,8 @@
}
const auto count = arr->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return false;
}
@@ -4587,7 +4581,7 @@
if (auto builtin = attributes.builtin) {
auto name = builtin_to_attribute(builtin.value());
if (name.empty()) {
- diagnostics_.AddError(diag::System::Writer, "unsupported builtin");
+ diagnostics_.AddError(diag::System::Writer, Source{}) << "unsupported builtin";
return false;
}
post += " : " + name;
@@ -4595,7 +4589,8 @@
if (auto interpolation = attributes.interpolation) {
auto mod = interpolation_to_modifiers(interpolation->type, interpolation->sampling);
if (mod.empty()) {
- diagnostics_.AddError(diag::System::Writer, "unsupported interpolation");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unsupported interpolation";
return false;
}
pre += mod;
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
index 88db758..8348b54 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
@@ -35,7 +35,7 @@
using HlslASTPrinterTest = TestHelper;
TEST_F(HlslASTPrinterTest, InvalidProgram) {
- Diagnostics().AddError(diag::System::Writer, "make the program invalid");
+ Diagnostics().AddError(diag::System::Writer, Source{}) << "make the program invalid";
ASSERT_FALSE(IsValid());
auto program = resolver::Resolve(*this);
ASSERT_FALSE(program.IsValid());
diff --git a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
index 610fc4b..f266d83 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
@@ -90,8 +90,8 @@
auto* cfg = inputs.Get<Config>();
if (cfg == nullptr) {
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
index b3fa496..04e7b14 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
@@ -453,9 +453,8 @@
uint32_t ROVRegisterIndex(uint32_t field_index) {
auto idx = cfg.pls_member_to_rov_reg.Get(field_index);
if (TINT_UNLIKELY(!idx)) {
- b.Diagnostics().AddError(diag::System::Transform,
- "PixelLocal::Config::attachments missing entry for field " +
- std::to_string(field_index));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "PixelLocal::Config::attachments missing entry for field " << field_index;
return 0;
}
return *idx;
@@ -466,9 +465,8 @@
core::TexelFormat ROVTexelFormat(uint32_t field_index) {
auto format = cfg.pls_member_to_rov_format.Get(field_index);
if (TINT_UNLIKELY(!format)) {
- b.Diagnostics().AddError(diag::System::Transform,
- "PixelLocal::Config::attachments missing entry for field " +
- std::to_string(field_index));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "PixelLocal::Config::attachments missing entry for field " << field_index;
return core::TexelFormat::kUndefined;
}
return *format;
@@ -485,8 +483,8 @@
auto* cfg = inputs.Get<Config>();
if (!cfg) {
ProgramBuilder b;
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
index d6c1b25..7028093 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
@@ -70,10 +70,9 @@
const auto* data = config.Get<Config>();
if (data == nullptr) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "missing transform data for " +
- std::string(tint::TypeInfo::Of<TruncateInterstageVariables>().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for "
+ << tint::TypeInfo::Of<TruncateInterstageVariables>().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/hlsl/writer/common/option_helpers.cc b/src/tint/lang/hlsl/writer/common/option_helpers.cc
index aace10b..416569d 100644
--- a/src/tint/lang/hlsl/writer/common/option_helpers.cc
+++ b/src/tint/lang/hlsl/writer/common/option_helpers.cc
@@ -54,10 +54,8 @@
const binding::BindingInfo& dst) -> bool {
if (auto binding = seen_wgsl_bindings.Get(src)) {
if (*binding != dst) {
- std::stringstream str;
- str << "found duplicate WGSL binding point: " << src;
-
- diagnostics.AddError(diag::System::Writer, str.str());
+ diagnostics.AddError(diag::System::Writer, Source{})
+ << "found duplicate WGSL binding point: " << src;
return true;
}
}
@@ -69,9 +67,8 @@
const tint::BindingPoint& dst) -> bool {
if (auto binding = map.Get(src)) {
if (*binding != dst) {
- std::stringstream str;
- str << "found duplicate MSL binding point: [binding: " << src.binding << "]";
- diagnostics.AddError(diag::System::Writer, str.str());
+ diagnostics.AddError(diag::System::Writer, Source{})
+ << "found duplicate MSL binding point: [binding: " << src.binding << "]";
return true;
}
}
@@ -97,27 +94,27 @@
// Storage and uniform are both [[buffer()]]
if (!valid(seen_hlsl_buffer_bindings, options.bindings.uniform)) {
- diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing uniform";
return Failure{std::move(diagnostics)};
}
if (!valid(seen_hlsl_buffer_bindings, options.bindings.storage)) {
- diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing storage";
return Failure{std::move(diagnostics)};
}
// Sampler is [[sampler()]]
if (!valid(seen_hlsl_sampler_bindings, options.bindings.sampler)) {
- diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing sampler";
return Failure{std::move(diagnostics)};
}
// Texture and storage texture are [[texture()]]
if (!valid(seen_hlsl_texture_bindings, options.bindings.texture)) {
- diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing texture";
return Failure{std::move(diagnostics)};
}
if (!valid(seen_hlsl_texture_bindings, options.bindings.storage_texture)) {
- diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing storage_texture";
return Failure{std::move(diagnostics)};
}
@@ -129,22 +126,26 @@
// Validate with the actual source regardless of what the remapper will do
if (wgsl_seen(src_binding, plane0)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
// Plane0 & Plane1 are [[texture()]]
if (hlsl_seen(seen_hlsl_texture_bindings, plane0, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
if (hlsl_seen(seen_hlsl_texture_bindings, plane1, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
// Metadata is [[buffer()]]
if (hlsl_seen(seen_hlsl_buffer_bindings, metadata, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
}
diff --git a/src/tint/lang/msl/intrinsic/data.cc b/src/tint/lang/msl/intrinsic/data.cc
index 261ee51..c4f7487 100644
--- a/src/tint/lang/msl/intrinsic/data.cc
+++ b/src/tint/lang/msl/intrinsic/data.cc
@@ -82,8 +82,8 @@
}
return BuildU32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "u32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "u32";
}
};
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 5a3a574..c2442f5 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -305,9 +305,9 @@
},
[&](const ast::Override*) {
// Override is removed with SubstituteOverride
- diagnostics_.AddError(diag::System::Writer,
- "override-expressions should have been removed with the "
- "SubstituteOverride transform.");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "override-expressions should have been removed with the "
+ "SubstituteOverride transform.";
return false;
},
[&](const ast::Function* func) {
@@ -364,7 +364,8 @@
return false;
}
} else {
- diagnostics_.AddError(diag::System::Writer, "unknown alias type: " + ty->FriendlyName());
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unknown alias type: " << ty->FriendlyName();
return false;
}
@@ -1063,7 +1064,8 @@
std::vector<const char*> dims;
switch (texture_type->dim()) {
case core::type::TextureDimension::kNone:
- diagnostics_.AddError(diag::System::Writer, "texture dimension is kNone");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "texture dimension is kNone";
return false;
case core::type::TextureDimension::k1d:
dims = {"width"};
@@ -1262,9 +1264,8 @@
out << "gradientcube(";
break;
default: {
- StringStream err;
- err << "MSL does not support gradients for " << dim << " textures";
- diagnostics_.AddError(diag::System::Writer, err.str());
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "MSL does not support gradients for " << dim << " textures";
return false;
}
}
@@ -1620,15 +1621,13 @@
out += "unpack_unorm2x16_to_float";
break;
case wgsl::BuiltinFn::kArrayLength:
- diagnostics_.AddError(
- diag::System::Writer,
- "Unable to translate builtin: " + std::string(builtin->str()) +
- "\nDid you forget to pass array_length_from_uniform generator "
- "options?");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Unable to translate builtin: " << builtin->Fn()
+ << "\nDid you forget to pass array_length_from_uniform generator options?";
return "";
default:
- diagnostics_.AddError(diag::System::Writer,
- "Unknown import method: " + std::string(builtin->str()));
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Unknown import method: " << builtin->Fn();
return "";
}
return out;
@@ -1803,8 +1802,8 @@
auto count = a->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return false;
}
@@ -1874,7 +1873,8 @@
return true;
}
}
- diagnostics_.AddError(diag::System::Writer, "unknown integer literal suffix type");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unknown integer literal suffix type";
return false;
}, //
TINT_ICE_ON_NO_MATCH);
@@ -2069,7 +2069,8 @@
auto name = BuiltinToAttribute(builtin);
if (name.empty()) {
- diagnostics_.AddError(diag::System::Writer, "unknown builtin");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unknown builtin";
return false;
}
out << " [[" << name << "]]";
@@ -2526,8 +2527,8 @@
} else {
auto count = arr->ConstantCount();
if (!count) {
- diagnostics_.AddError(diag::System::Writer,
- core::type::Array::kErrExpectedConstantCount);
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return false;
}
@@ -2622,7 +2623,8 @@
out << "cube_array";
break;
default:
- diagnostics_.AddError(diag::System::Writer, "Invalid texture dimensions");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Invalid texture dimensions";
return false;
}
if (tex->IsAnyOf<core::type::MultisampledTexture,
@@ -2655,8 +2657,8 @@
} else if (storage->access() == core::Access::kWrite) {
out << ", access::write";
} else {
- diagnostics_.AddError(diag::System::Writer,
- "Invalid access control for storage texture");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "Invalid access control for storage texture";
return false;
}
return true;
@@ -2797,7 +2799,7 @@
if (auto builtin = attributes.builtin) {
auto name = BuiltinToAttribute(builtin.value());
if (name.empty()) {
- diagnostics_.AddError(diag::System::Writer, "unknown builtin");
+ diagnostics_.AddError(diag::System::Writer, Source{}) << "unknown builtin";
return false;
}
out << " [[" << name << "]]";
@@ -2839,7 +2841,8 @@
if (auto interpolation = attributes.interpolation) {
auto name = InterpolationToAttribute(interpolation->type, interpolation->sampling);
if (name.empty()) {
- diagnostics_.AddError(diag::System::Writer, "unknown interpolation attribute");
+ diagnostics_.AddError(diag::System::Writer, Source{})
+ << "unknown interpolation attribute";
return false;
}
out << " [[" << name << "]]";
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc
index ab858e3..a78f3ee 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc
@@ -39,7 +39,7 @@
using MslASTPrinterTest = TestHelper;
TEST_F(MslASTPrinterTest, InvalidProgram) {
- Diagnostics().AddError(diag::System::Writer, "make the program invalid");
+ Diagnostics().AddError(diag::System::Writer, Source{}) << "make the program invalid";
ASSERT_FALSE(IsValid());
auto program = resolver::Resolve(*this);
ASSERT_FALSE(program.IsValid());
diff --git a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
index 140b209..0084d30 100644
--- a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
@@ -244,9 +244,8 @@
case core::AddressSpace::kWorkgroup:
break;
case core::AddressSpace::kPushConstant: {
- ctx.dst->Diagnostics().AddError(
- diag::System::Transform,
- "unhandled module-scope address space (" + tint::ToString(sc) + ")");
+ ctx.dst->Diagnostics().AddError(diag::System::Transform, Source{})
+ << "unhandled module-scope address space (" << sc << ")";
break;
}
default: {
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
index 2f2a216..c6cc55a 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
@@ -257,9 +257,8 @@
uint32_t AttachmentIndex(uint32_t field_index) {
auto idx = cfg.attachments.Get(field_index);
if (TINT_UNLIKELY(!idx)) {
- b.Diagnostics().AddError(diag::System::Transform,
- "PixelLocal::Config::attachments missing entry for field " +
- std::to_string(field_index));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "PixelLocal::Config::attachments missing entry for field " << field_index;
return 0;
}
return *idx;
@@ -276,8 +275,8 @@
auto* cfg = inputs.Get<Config>();
if (!cfg) {
ProgramBuilder b;
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/msl/writer/common/option_helpers.cc b/src/tint/lang/msl/writer/common/option_helpers.cc
index d72d984..cb6a162 100644
--- a/src/tint/lang/msl/writer/common/option_helpers.cc
+++ b/src/tint/lang/msl/writer/common/option_helpers.cc
@@ -54,10 +54,8 @@
const binding::BindingInfo& dst) -> bool {
if (auto binding = seen_wgsl_bindings.Get(src)) {
if (*binding != dst) {
- std::stringstream str;
- str << "found duplicate WGSL binding point: " << src;
-
- diagnostics.AddError(diag::System::Writer, str.str());
+ diagnostics.AddError(diag::System::Writer, Source{})
+ << "found duplicate WGSL binding point: " << src;
return true;
}
}
@@ -69,9 +67,8 @@
const tint::BindingPoint& dst) -> bool {
if (auto binding = map.Get(src)) {
if (*binding != dst) {
- std::stringstream str;
- str << "found duplicate MSL binding point: [binding: " << src.binding << "]";
- diagnostics.AddError(diag::System::Writer, str.str());
+ diagnostics.AddError(diag::System::Writer, Source{})
+ << "found duplicate MSL binding point: [binding: " << src.binding << "]";
return true;
}
}
@@ -97,27 +94,27 @@
// Storage and uniform are both [[buffer()]]
if (!valid(seen_msl_buffer_bindings, options.bindings.uniform)) {
- diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing uniform";
return Failure{std::move(diagnostics)};
}
if (!valid(seen_msl_buffer_bindings, options.bindings.storage)) {
- diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing storage";
return Failure{std::move(diagnostics)};
}
// Sampler is [[sampler()]]
if (!valid(seen_msl_sampler_bindings, options.bindings.sampler)) {
- diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing sampler";
return Failure{std::move(diagnostics)};
}
// Texture and storage texture are [[texture()]]
if (!valid(seen_msl_texture_bindings, options.bindings.texture)) {
- diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing texture";
return Failure{std::move(diagnostics)};
}
if (!valid(seen_msl_texture_bindings, options.bindings.storage_texture)) {
- diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing storage_texture";
return Failure{std::move(diagnostics)};
}
@@ -129,22 +126,26 @@
// Validate with the actual source regardless of what the remapper will do
if (wgsl_seen(src_binding, plane0)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
// Plane0 & Plane1 are [[texture()]]
if (msl_seen(seen_msl_texture_bindings, plane0, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
if (msl_seen(seen_msl_texture_bindings, plane1, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
// Metadata is [[buffer()]]
if (msl_seen(seen_msl_buffer_bindings, metadata, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
}
diff --git a/src/tint/lang/spirv/intrinsic/data.cc b/src/tint/lang/spirv/intrinsic/data.cc
index 110a151..691263a 100644
--- a/src/tint/lang/spirv/intrinsic/data.cc
+++ b/src/tint/lang/spirv/intrinsic/data.cc
@@ -83,8 +83,8 @@
}
return BuildBool(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "bool";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "bool";
}
};
@@ -97,8 +97,8 @@
}
return BuildF32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "f32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "f32";
}
};
@@ -111,8 +111,8 @@
}
return BuildF16(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "f16";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "f16";
}
};
@@ -125,8 +125,8 @@
}
return BuildI32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "i32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "i32";
}
};
@@ -139,8 +139,8 @@
}
return BuildU32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "u32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "u32";
}
};
@@ -158,9 +158,9 @@
}
return BuildVec2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -178,9 +178,9 @@
}
return BuildVec3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -198,9 +198,9 @@
}
return BuildVec4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -218,9 +218,9 @@
}
return BuildMat2X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -238,9 +238,9 @@
}
return BuildMat2X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -258,9 +258,9 @@
}
return BuildMat2X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -278,9 +278,9 @@
}
return BuildMat3X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -298,9 +298,9 @@
}
return BuildMat3X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -318,9 +318,9 @@
}
return BuildMat3X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -338,9 +338,9 @@
}
return BuildMat4X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -358,9 +358,9 @@
}
return BuildMat4X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -378,9 +378,9 @@
}
return BuildMat4X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -403,12 +403,10 @@
}
return BuildVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "vec" << N << "<" << T << ">";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec" << style::Type << N << style::Type << "<" << style::Type << T << style::Type << ">";
}
};
@@ -436,13 +434,11 @@
}
return BuildMat(state, ty, N, M, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string M = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "mat" << N << "x" << M << "<" << T << ">";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText M;
+ state->PrintNum(M);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat" << style::Type << N << style::Type << "x" << style::Type << M << style::Type << "<" << style::Type << T << style::Type << ">";
}
};
@@ -460,9 +456,9 @@
}
return BuildAtomic(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "atomic<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "atomic" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -475,8 +471,8 @@
}
return BuildSampler(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "sampler";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "sampler";
}
};
@@ -489,8 +485,8 @@
}
return BuildSamplerComparison(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "sampler_comparison";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "sampler_comparison";
}
};
@@ -508,9 +504,9 @@
}
return BuildTexture1D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_1d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_1d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -528,9 +524,9 @@
}
return BuildTexture2D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_2d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_2d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -548,9 +544,9 @@
}
return BuildTexture2DArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_2d_array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_2d_array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -568,9 +564,9 @@
}
return BuildTexture3D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_3d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_3d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -588,9 +584,9 @@
}
return BuildTextureCube(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_cube<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_cube" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -608,9 +604,9 @@
}
return BuildTextureCubeArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_cube_array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_cube_array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -628,9 +624,9 @@
}
return BuildTextureMultisampled2D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_multisampled_2d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_multisampled_2d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -643,8 +639,8 @@
}
return BuildTextureDepth2D(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_2d";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_2d";
}
};
@@ -657,8 +653,8 @@
}
return BuildTextureDepth2DArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_2d_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_2d_array";
}
};
@@ -671,8 +667,8 @@
}
return BuildTextureDepthCube(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_cube";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_cube";
}
};
@@ -685,8 +681,8 @@
}
return BuildTextureDepthCubeArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_cube_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_cube_array";
}
};
@@ -699,8 +695,8 @@
}
return BuildTextureDepthMultisampled2D(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_multisampled_2d";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_multisampled_2d";
}
};
@@ -723,10 +719,10 @@
}
return BuildTextureStorage1D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_1d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_1d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -749,10 +745,10 @@
}
return BuildTextureStorage2D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_2d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_2d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -775,10 +771,10 @@
}
return BuildTextureStorage2DArray(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_2d_array<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_2d_array" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -801,10 +797,10 @@
}
return BuildTextureStorage3D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_3d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_3d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -832,11 +828,11 @@
}
return BuildPtr(state, ty, S, T, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string S = state->NumName();
- const std::string T = state->TypeName();
- const std::string A = state->NumName();
- return "ptr<" + S + ", " + T + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText S;
+ state->PrintNum(S);StyledText T;
+ state->PrintType(T);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "ptr" << style::Code << "<" << style::Type << S << style::Code << ", " << style::Type << T << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -849,8 +845,8 @@
}
return BuildStructWithRuntimeArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "struct_with_runtime_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "struct_with_runtime_array";
}
};
@@ -868,9 +864,9 @@
}
return BuildSampledImage(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "sampled_image<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "sampled_image" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -886,13 +882,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match iu32'
@@ -906,13 +899,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fiu32'
@@ -929,13 +919,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar'
@@ -958,13 +945,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match samplers'
@@ -978,13 +962,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kSamplerMatcher.string(nullptr) << " or " << kSamplerComparisonMatcher.string(nullptr);
- return ss.str();
- }
+ kSamplerMatcher.print(nullptr, out); out << TextStyle{} << " or "; kSamplerComparisonMatcher.print(nullptr, out);}
};
/// EnumMatcher for 'match read_write'
@@ -995,8 +976,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "read_write";
}
};
@@ -1008,8 +989,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "storage";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "storage";
}
};
@@ -1024,8 +1005,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "workgroup or storage";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "workgroup"<< TextStyle{} << " or " << style::Enum << "storage";
}
};
@@ -1045,8 +1026,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "bgra8unorm, rgba8unorm, rgba8snorm, rgba16float, r32float, rg32float or rgba32float";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "bgra8unorm"<< TextStyle{} << ", " << style::Enum << "rgba8unorm"<< TextStyle{} << ", " << style::Enum << "rgba8snorm"<< TextStyle{} << ", " << style::Enum << "rgba16float"<< TextStyle{} << ", " << style::Enum << "r32float"<< TextStyle{} << ", " << style::Enum << "rg32float"<< TextStyle{} << " or " << style::Enum << "rgba32float";
}
};
@@ -1064,8 +1045,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "rgba8sint, rgba16sint, r32sint, rg32sint or rgba32sint";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "rgba8sint"<< TextStyle{} << ", " << style::Enum << "rgba16sint"<< TextStyle{} << ", " << style::Enum << "r32sint"<< TextStyle{} << ", " << style::Enum << "rg32sint"<< TextStyle{} << " or " << style::Enum << "rgba32sint";
}
};
@@ -1083,8 +1064,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "rgba8uint, rgba16uint, r32uint, rg32uint or rgba32uint";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "rgba8uint"<< TextStyle{} << ", " << style::Enum << "rgba16uint"<< TextStyle{} << ", " << style::Enum << "r32uint"<< TextStyle{} << ", " << style::Enum << "rg32uint"<< TextStyle{} << " or " << style::Enum << "rgba32uint";
}
};
@@ -1099,8 +1080,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "read or read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "read"<< TextStyle{} << " or " << style::Enum << "read_write";
}
};
@@ -1115,8 +1096,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "write or read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "write"<< TextStyle{} << " or " << style::Enum << "read_write";
}
};
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics.cc b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
index 06e9d43..181ab19 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
@@ -224,10 +224,9 @@
}
auto count = arr->ConstantCount();
if (!count) {
- ctx.dst->Diagnostics().AddError(
- diag::System::Transform,
- "the Atomics transform does not currently support array counts that "
- "use override values");
+ ctx.dst->Diagnostics().AddError(diag::System::Transform, Source{})
+ << "the Atomics transform does not currently support array counts that use "
+ "override values";
count = 1;
}
return b.ty.array(AtomicTypeFor(arr->ElemType()), u32(count.value()));
diff --git a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
index d106222..7fa6c89 100644
--- a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
@@ -51,7 +51,7 @@
auto p = std::make_unique<ASTParser>(test::Assemble(preamble + spirv));
if (!p->BuildAndParseInternalModule()) {
ProgramBuilder builder;
- builder.Diagnostics().AddError(diag::System::Reader, p->error());
+ builder.Diagnostics().AddError(diag::System::Reader, Source{}) << p->error();
return Program(std::move(builder));
}
return p->Program();
diff --git a/src/tint/lang/spirv/reader/ast_parser/parse.cc b/src/tint/lang/spirv/reader/ast_parser/parse.cc
index 988fc08..c3dea0e 100644
--- a/src/tint/lang/spirv/reader/ast_parser/parse.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/parse.cc
@@ -83,7 +83,7 @@
ProgramBuilder& builder = parser.builder();
if (!parsed) {
// TODO(bclayton): Migrate ASTParser to using diagnostics.
- builder.Diagnostics().AddError(diag::System::Reader, parser.error());
+ builder.Diagnostics().AddError(diag::System::Reader, Source{}) << parser.error();
return Program(std::move(builder));
}
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc
index ad5f484..e76c3c2 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc
@@ -34,7 +34,7 @@
using SpirvASTPrinterTest = TestHelper;
TEST_F(SpirvASTPrinterTest, InvalidProgram) {
- Diagnostics().AddError(diag::System::Writer, "make the program invalid");
+ Diagnostics().AddError(diag::System::Writer, Source{}) << "make the program invalid";
ASSERT_FALSE(IsValid());
auto program = resolver::Resolve(*this);
ASSERT_FALSE(program.IsValid());
diff --git a/src/tint/lang/spirv/writer/common/option_helper.cc b/src/tint/lang/spirv/writer/common/option_helper.cc
index 37f2377..76a21ed 100644
--- a/src/tint/lang/spirv/writer/common/option_helper.cc
+++ b/src/tint/lang/spirv/writer/common/option_helper.cc
@@ -48,10 +48,8 @@
const binding::BindingInfo& dst) -> bool {
if (auto binding = seen_wgsl_bindings.Get(src)) {
if (*binding != dst) {
- std::stringstream str;
- str << "found duplicate WGSL binding point: " << src;
-
- diagnostics.AddError(diag::System::Writer, str.str());
+ diagnostics.AddError(diag::System::Writer, Source{})
+ << "found duplicate WGSL binding point: " << src;
return true;
}
}
@@ -63,10 +61,9 @@
const tint::BindingPoint& dst) -> bool {
if (auto binding = seen_spirv_bindings.Get(src)) {
if (*binding != dst) {
- std::stringstream str;
- str << "found duplicate SPIR-V binding point: [group: " << src.group
+ diagnostics.AddError(diag::System::Writer, Source{})
+ << "found duplicate SPIR-V binding point: [group: " << src.group
<< ", binding: " << src.binding << "]";
- diagnostics.AddError(diag::System::Writer, str.str());
return true;
}
}
@@ -91,23 +88,23 @@
};
if (!valid(options.bindings.uniform)) {
- diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing uniform";
return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.storage)) {
- diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing storage";
return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.texture)) {
- diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing texture";
return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.storage_texture)) {
- diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing storage_texture";
return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.sampler)) {
- diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
+ diagnostics.AddNote(diag::System::Writer, Source{}) << "when processing sampler";
return Failure{std::move(diagnostics)};
}
@@ -119,20 +116,24 @@
// Validate with the actual source regardless of what the remapper will do
if (wgsl_seen(src_binding, plane0)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
if (spirv_seen(plane0, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
if (spirv_seen(plane1, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
if (spirv_seen(metadata, src_binding)) {
- diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ diagnostics.AddNote(diag::System::Writer, Source{})
+ << "when processing external_texture";
return Failure{std::move(diagnostics)};
}
}
diff --git a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
index fa6bc9e..bdb43cf 100644
--- a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
+++ b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
@@ -82,10 +82,9 @@
ApplyResult Run() {
auto* cfg = inputs.Get<Config>();
if (cfg == nullptr) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "missing transform data for " +
- std::string(tint::TypeInfo::Of<ArrayLengthFromUniform>().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for "
+ << tint::TypeInfo::Of<ArrayLengthFromUniform>().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/wgsl/ast/transform/binding_remapper.cc b/src/tint/lang/wgsl/ast/transform/binding_remapper.cc
index c3c8cbe..31ef518 100644
--- a/src/tint/lang/wgsl/ast/transform/binding_remapper.cc
+++ b/src/tint/lang/wgsl/ast/transform/binding_remapper.cc
@@ -66,8 +66,8 @@
auto* remappings = inputs.Get<Remappings>();
if (!remappings) {
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
@@ -112,18 +112,15 @@
if (ac_it != remappings->access_controls.end()) {
core::Access access = ac_it->second;
if (access == core::Access::kUndefined) {
- b.Diagnostics().AddError(diag::System::Transform,
- "invalid access mode (" +
- std::to_string(static_cast<uint32_t>(access)) +
- ")");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "invalid access mode (" << static_cast<uint32_t>(access) << ")";
return resolver::Resolve(b);
}
auto* sem = src.Sem().Get(var);
if (sem->AddressSpace() != core::AddressSpace::kStorage) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "cannot apply access control to variable with address space " +
- std::string(tint::ToString(sem->AddressSpace())));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "cannot apply access control to variable with address space "
+ << sem->AddressSpace();
return resolver::Resolve(b);
}
auto* ty = sem->Type()->UnwrapRef();
diff --git a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
index db9a682..3e2029b 100644
--- a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
@@ -979,8 +979,8 @@
auto* cfg = inputs.Get<Config>();
if (cfg == nullptr) {
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
index 815a3ed..6cbaec6 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
@@ -135,10 +135,9 @@
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
if (it == new_binding_points->bindings_map.end()) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "missing new binding points for texture_external at binding {" +
- std::to_string(bp.group) + "," + std::to_string(bp.binding) + "}");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing new binding points for texture_external at binding {" << bp.group
+ << "," << bp.binding << "}";
continue;
}
@@ -552,8 +551,8 @@
ProgramBuilder b;
program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
if (!new_binding_points) {
- b.Diagnostics().AddError(diag::System::Transform, "missing new binding point data for " +
- std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing new binding point data for " << TypeInfo().name;
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/wgsl/ast/transform/push_constant_helper.cc b/src/tint/lang/wgsl/ast/transform/push_constant_helper.cc
index af6fe57..ba10cf4 100644
--- a/src/tint/lang/wgsl/ast/transform/push_constant_helper.cc
+++ b/src/tint/lang/wgsl/ast/transform/push_constant_helper.cc
@@ -64,7 +64,8 @@
void PushConstantHelper::InsertMember(const char* name, ast::Type type, uint32_t offset) {
auto& member = member_map[offset];
if (TINT_UNLIKELY(member != nullptr)) {
- ctx.dst->Diagnostics().AddError(diag::System::Transform, "struct member offset collision");
+ ctx.dst->Diagnostics().AddError(diag::System::Transform, Source{})
+ << "struct member offset collision";
}
member = ctx.dst->Member(name, type, Vector{ctx.dst->MemberOffset(core::AInt(offset))});
}
diff --git a/src/tint/lang/wgsl/ast/transform/robustness.cc b/src/tint/lang/wgsl/ast/transform/robustness.cc
index c3f9c57..42273c5 100644
--- a/src/tint/lang/wgsl/ast/transform/robustness.cc
+++ b/src/tint/lang/wgsl/ast/transform/robustness.cc
@@ -272,8 +272,8 @@
}
// Note: Don't be tempted to use the array override variable as an expression here,
// the name might be shadowed!
- b.Diagnostics().AddError(diag::System::Transform,
- core::type::Array::kErrExpectedConstantCount);
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return nullptr;
}, //
TINT_ICE_ON_NO_MATCH);
diff --git a/src/tint/lang/wgsl/ast/transform/single_entry_point.cc b/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
index 78843cc..a0952eb 100644
--- a/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
+++ b/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
@@ -55,8 +55,8 @@
auto* cfg = inputs.Get<Config>();
if (cfg == nullptr) {
- b.Diagnostics().AddError(diag::System::Transform,
- "missing transform data for " + std::string(TypeInfo().name));
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "missing transform data for " << TypeInfo().name;
return resolver::Resolve(b);
}
@@ -72,8 +72,8 @@
}
}
if (entry_point == nullptr) {
- b.Diagnostics().AddError(diag::System::Transform,
- "entry point '" + cfg->entry_point_name + "' not found");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "entry point '" << cfg->entry_point_name << "' not found";
return resolver::Resolve(b);
}
diff --git a/src/tint/lang/wgsl/ast/transform/substitute_override.cc b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
index 74d8b7b..4711b36 100644
--- a/src/tint/lang/wgsl/ast/transform/substitute_override.cc
+++ b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
@@ -71,7 +71,8 @@
const auto* data = config.Get<Config>();
if (!data) {
- b.Diagnostics().AddError(diag::System::Transform, "Missing override substitution data");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "Missing override substitution data";
return resolver::Resolve(b);
}
@@ -90,9 +91,8 @@
auto iter = data->map.find(sem->Attributes().override_id.value());
if (iter == data->map.end()) {
if (!w->initializer) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "Initializer not provided for override, and override not overridden.");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "Initializer not provided for override, and override not overridden.";
return nullptr;
}
return b.Const(source, sym, ty, ctx.Clone(w->initializer));
@@ -108,8 +108,8 @@
[&](const core::type::F16*) { return b.Expr(f16(value)); });
if (!ctor) {
- b.Diagnostics().AddError(diag::System::Transform,
- "Failed to create override-expression");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "Failed to create override-expression";
return nullptr;
}
diff --git a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
index 31c2c29..8eae5a6 100644
--- a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
+++ b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
@@ -72,11 +72,11 @@
kFloat, // unsigned normalized, signed normalized, and float
};
-/// Writes the VertexFormat to the stream.
+/// Writes the VertexFormat to the diagnostic.
/// @param out the stream to write to
/// @param format the VertexFormat to write
/// @returns out so calls can be chained
-StringStream& operator<<(StringStream& out, VertexFormat format) {
+diag::Diagnostic& operator<<(diag::Diagnostic& out, VertexFormat format) {
switch (format) {
case VertexFormat::kUint8x2:
return out << "uint8x2";
@@ -260,16 +260,16 @@
for (auto* fn : src.AST().Functions()) {
if (fn->PipelineStage() == PipelineStage::kVertex) {
if (func != nullptr) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "VertexPulling found more than one vertex entry point");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "VertexPulling found more than one vertex entry point";
return resolver::Resolve(b);
}
func = fn;
}
}
if (func == nullptr) {
- b.Diagnostics().AddError(diag::System::Transform, "Vertex stage entry point not found");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "Vertex stage entry point not found";
return resolver::Resolve(b);
}
@@ -357,12 +357,10 @@
const VertexBufferLayoutDescriptor& buffer_layout = cfg.vertex_state[buffer_idx];
if ((buffer_layout.array_stride & 3) != 0) {
- b.Diagnostics().AddError(
- diag::System::Transform,
- "WebGPU requires that vertex stride must be a multiple of 4 bytes, "
- "but VertexPulling array stride for buffer " +
- std::to_string(buffer_idx) + " was " +
- std::to_string(buffer_layout.array_stride) + " bytes");
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "WebGPU requires that vertex stride must be a multiple of 4 bytes, "
+ "but VertexPulling array stride for buffer "
+ << buffer_idx << " was " << buffer_layout.array_stride << " bytes";
return nullptr;
}
@@ -397,12 +395,10 @@
// Base types must match between the vertex stream and the WGSL variable
if (!IsTypeCompatible(var_dt, fmt_dt)) {
- StringStream err;
- err << "VertexAttributeDescriptor for location "
- << std::to_string(attribute_desc.shader_location) << " has format "
- << attribute_desc.format << " but shader expects "
- << var.type->FriendlyName();
- b.Diagnostics().AddError(diag::System::Transform, err.str());
+ b.Diagnostics().AddError(diag::System::Transform, Source{})
+ << "VertexAttributeDescriptor for location "
+ << attribute_desc.shader_location << " has format " << attribute_desc.format
+ << " but shader expects " << var.type->FriendlyName();
return nullptr;
}
diff --git a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
index e394520..d0e7f74 100644
--- a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
@@ -381,8 +381,8 @@
// `(idx % modulo) / division`
auto count = arr->ConstantCount();
if (!count) {
- ctx.dst->Diagnostics().AddError(diag::System::Transform,
- core::type::Array::kErrExpectedConstantCount);
+ ctx.dst->Diagnostics().AddError(diag::System::Transform, Source{})
+ << core::type::Array::kErrExpectedConstantCount;
return Expression{}; // error
}
auto modulo = num_values * count.value();
diff --git a/src/tint/lang/wgsl/extension.cc b/src/tint/lang/wgsl/extension.cc
index 3069ccf..1240173 100644
--- a/src/tint/lang/wgsl/extension.cc
+++ b/src/tint/lang/wgsl/extension.cc
@@ -60,6 +60,9 @@
if (str == "chromium_internal_dual_source_blending") {
return Extension::kChromiumInternalDualSourceBlending;
}
+ if (str == "chromium_internal_graphite") {
+ return Extension::kChromiumInternalGraphite;
+ }
if (str == "chromium_internal_relaxed_uniform_layout") {
return Extension::kChromiumInternalRelaxedUniformLayout;
}
@@ -85,6 +88,8 @@
return "chromium_experimental_subgroups";
case Extension::kChromiumInternalDualSourceBlending:
return "chromium_internal_dual_source_blending";
+ case Extension::kChromiumInternalGraphite:
+ return "chromium_internal_graphite";
case Extension::kChromiumInternalRelaxedUniformLayout:
return "chromium_internal_relaxed_uniform_layout";
case Extension::kF16:
diff --git a/src/tint/lang/wgsl/extension.h b/src/tint/lang/wgsl/extension.h
index 7de7e82..3eccedf 100644
--- a/src/tint/lang/wgsl/extension.h
+++ b/src/tint/lang/wgsl/extension.h
@@ -52,6 +52,7 @@
kChromiumExperimentalPushConstant,
kChromiumExperimentalSubgroups,
kChromiumInternalDualSourceBlending,
+ kChromiumInternalGraphite,
kChromiumInternalRelaxedUniformLayout,
kF16,
};
@@ -74,10 +75,15 @@
Extension ParseExtension(std::string_view str);
constexpr std::string_view kExtensionStrings[] = {
- "chromium_disable_uniformity_analysis", "chromium_experimental_framebuffer_fetch",
- "chromium_experimental_pixel_local", "chromium_experimental_push_constant",
- "chromium_experimental_subgroups", "chromium_internal_dual_source_blending",
- "chromium_internal_relaxed_uniform_layout", "f16",
+ "chromium_disable_uniformity_analysis",
+ "chromium_experimental_framebuffer_fetch",
+ "chromium_experimental_pixel_local",
+ "chromium_experimental_push_constant",
+ "chromium_experimental_subgroups",
+ "chromium_internal_dual_source_blending",
+ "chromium_internal_graphite",
+ "chromium_internal_relaxed_uniform_layout",
+ "f16",
};
/// All extensions
@@ -88,6 +94,7 @@
Extension::kChromiumExperimentalPushConstant,
Extension::kChromiumExperimentalSubgroups,
Extension::kChromiumInternalDualSourceBlending,
+ Extension::kChromiumInternalGraphite,
Extension::kChromiumInternalRelaxedUniformLayout,
Extension::kF16,
};
diff --git a/src/tint/lang/wgsl/extension_bench.cc b/src/tint/lang/wgsl/extension_bench.cc
index 70c0d73..c2128d3 100644
--- a/src/tint/lang/wgsl/extension_bench.cc
+++ b/src/tint/lang/wgsl/extension_bench.cc
@@ -87,20 +87,27 @@
"chromium_internakk_ualsourc_blendHng",
"chromium_inRRrnal_dujl_sourceblgnding",
"chromiuminternal_duab_source_blendin",
- "chromium_internal_relaxed_uniform_lajout",
- "chromium_internal_relxed_uniform_layout",
- "chroium_inqernal_rlaxed_uniform_layout",
+ "chromiumjinternal_graphite",
+ "chromium_inernal_graphite",
+ "cromiu_internaq_graphite",
+ "chromium_internal_graphite",
+ "chromium_intenalNNgraphite",
+ "chromiuminternal_gvaphite",
+ "chromium_internal_grphitQQ",
+ "chromirm_intenal_rfflaxed_unifrm_layout",
+ "chromium_internal_jelaxed_uniform_layout",
+ "chromium_interna_relNNxed_uwwiform_lay82t",
"chromium_internal_relaxed_uniform_layout",
- "chromium_internNNl_relaxed_uniform_layou",
- "chromium_internal_relaxvvd_unifom_laout",
- "chromium_internalrelaxed_uniQQorm_layout",
- "ff",
- "fj6",
- "wNN2",
+ "chromium_internal_relaxed_uniform_layut",
+ "chromium_internal_relaxed_rrniform_layout",
+ "chromium_internal_relaxedGuniform_layout",
+ "FF16",
+ "",
+ "rr1",
"f16",
- "f6",
- "rr16",
- "fG6",
+ "1",
+ "DJ1",
+ "",
};
for (auto _ : state) {
for (auto* str : kStrings) {
diff --git a/src/tint/lang/wgsl/extension_test.cc b/src/tint/lang/wgsl/extension_test.cc
index 8bcbd0c..11a75b0 100644
--- a/src/tint/lang/wgsl/extension_test.cc
+++ b/src/tint/lang/wgsl/extension_test.cc
@@ -63,6 +63,7 @@
{"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant},
{"chromium_experimental_subgroups", Extension::kChromiumExperimentalSubgroups},
{"chromium_internal_dual_source_blending", Extension::kChromiumInternalDualSourceBlending},
+ {"chromium_internal_graphite", Extension::kChromiumInternalGraphite},
{"chromium_internal_relaxed_uniform_layout", Extension::kChromiumInternalRelaxedUniformLayout},
{"f16", Extension::kF16},
};
@@ -86,12 +87,15 @@
{"chromium_internal_dual_soErce_blending", Extension::kUndefined},
{"chromiuPP_internal_dual_sourceblenTTing", Extension::kUndefined},
{"chromim_internadd_dual_sxxurce_blending", Extension::kUndefined},
- {"chromium_interna44_relaxed_uniform_layout", Extension::kUndefined},
- {"chromium_internal_relaxed_uniformSSlayouVV", Extension::kUndefined},
- {"chromiumRnteRnal_re22axed_uniform_layout", Extension::kUndefined},
- {"96", Extension::kUndefined},
- {"f1", Extension::kUndefined},
- {"VOR6", Extension::kUndefined},
+ {"chromi44m_internal_graphite", Extension::kUndefined},
+ {"chromSSuVV_internal_graphite", Extension::kUndefined},
+ {"cRromium_nternR22_graphite", Extension::kUndefined},
+ {"chromium_int9rnal_relaxed_Fnifor_layout", Extension::kUndefined},
+ {"chrmium_internal_relaxed_uniform_layout", Extension::kUndefined},
+ {"VRhHomium_internal_relaxd_uniform_OOayout", Extension::kUndefined},
+ {"y1", Extension::kUndefined},
+ {"l77rrn6", Extension::kUndefined},
+ {"4016", Extension::kUndefined},
};
using ExtensionParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/lang/wgsl/helpers/check_supported_extensions.cc b/src/tint/lang/wgsl/helpers/check_supported_extensions.cc
index bb35e15..72f65c6 100644
--- a/src/tint/lang/wgsl/helpers/check_supported_extensions.cc
+++ b/src/tint/lang/wgsl/helpers/check_supported_extensions.cc
@@ -48,10 +48,9 @@
for (auto* enable : module.Enables()) {
for (auto* ext : enable->extensions) {
if (!set.Contains(ext->name)) {
- diags.AddError(diag::System::Writer,
- std::string(writer_name) + " backend does not support extension '" +
- tint::ToString(ext->name) + "'",
- ext->source);
+ diags.AddError(diag::System::Writer, ext->source)
+ << writer_name << " backend does not support extension " << style::Code
+ << ext->name;
return false;
}
}
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index 8efa350..f6f7980 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -571,12 +571,13 @@
const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
auto* func = program_.AST().Functions().Find(program_.Symbols().Get(name));
if (!func) {
- diagnostics_.AddError(diag::System::Inspector, name + " was not found!");
+ diagnostics_.AddError(diag::System::Inspector, Source{}) << name << " was not found!";
return nullptr;
}
if (!func->IsEntryPoint()) {
- diagnostics_.AddError(diag::System::Inspector, name + " is not an entry point!");
+ diagnostics_.AddError(diag::System::Inspector, Source{})
+ << name << " is not an entry point!";
return nullptr;
}
diff --git a/src/tint/lang/wgsl/intrinsic/data.cc b/src/tint/lang/wgsl/intrinsic/data.cc
index 7c54003..96b5ad0 100644
--- a/src/tint/lang/wgsl/intrinsic/data.cc
+++ b/src/tint/lang/wgsl/intrinsic/data.cc
@@ -105,8 +105,8 @@
}
return BuildBool(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "bool";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "bool";
}
};
@@ -119,10 +119,8 @@
}
return BuildIa(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- ss << "abstract-int";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "abstract-int";
}
};
@@ -135,10 +133,8 @@
}
return BuildFa(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- ss << "abstract-float";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "abstract-float";
}
};
@@ -151,8 +147,8 @@
}
return BuildI32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "i32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "i32";
}
};
@@ -165,8 +161,8 @@
}
return BuildU32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "u32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "u32";
}
};
@@ -179,8 +175,8 @@
}
return BuildF32(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "f32";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "f32";
}
};
@@ -193,8 +189,8 @@
}
return BuildF16(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "f16";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "f16";
}
};
@@ -212,9 +208,9 @@
}
return BuildVec2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -232,9 +228,9 @@
}
return BuildVec3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -252,9 +248,9 @@
}
return BuildVec4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "vec4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -272,9 +268,9 @@
}
return BuildMat2X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -292,9 +288,9 @@
}
return BuildMat2X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -312,9 +308,9 @@
}
return BuildMat2X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat2x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat2x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -332,9 +328,9 @@
}
return BuildMat3X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -352,9 +348,9 @@
}
return BuildMat3X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -372,9 +368,9 @@
}
return BuildMat3X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat3x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat3x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -392,9 +388,9 @@
}
return BuildMat4X2(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x2<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x2" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -412,9 +408,9 @@
}
return BuildMat4X3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -432,9 +428,9 @@
}
return BuildMat4X4(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "mat4x4<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat4x4" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -457,12 +453,10 @@
}
return BuildVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "vec" << N << "<" << T << ">";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "vec" << style::Type << N << style::Type << "<" << style::Type << T << style::Type << ">";
}
};
@@ -490,13 +484,11 @@
}
return BuildMat(state, ty, N, M, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string M = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "mat" << N << "x" << M << "<" << T << ">";
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText M;
+ state->PrintNum(M);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "mat" << style::Type << N << style::Type << "x" << style::Type << M << style::Type << "<" << style::Type << T << style::Type << ">";
}
};
@@ -524,11 +516,11 @@
}
return BuildPtr(state, ty, S, T, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string S = state->NumName();
- const std::string T = state->TypeName();
- const std::string A = state->NumName();
- return "ptr<" + S + ", " + T + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText S;
+ state->PrintNum(S);StyledText T;
+ state->PrintType(T);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "ptr" << style::Code << "<" << style::Type << S << style::Code << ", " << style::Type << T << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -546,9 +538,9 @@
}
return BuildAtomic(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "atomic<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "atomic" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -566,9 +558,9 @@
}
return BuildArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -581,8 +573,8 @@
}
return BuildSampler(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "sampler";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "sampler";
}
};
@@ -595,8 +587,8 @@
}
return BuildSamplerComparison(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "sampler_comparison";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "sampler_comparison";
}
};
@@ -614,9 +606,9 @@
}
return BuildTexture1D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_1d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_1d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -634,9 +626,9 @@
}
return BuildTexture2D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_2d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_2d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -654,9 +646,9 @@
}
return BuildTexture2DArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_2d_array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_2d_array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -674,9 +666,9 @@
}
return BuildTexture3D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_3d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_3d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -694,9 +686,9 @@
}
return BuildTextureCube(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_cube<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_cube" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -714,9 +706,9 @@
}
return BuildTextureCubeArray(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_cube_array<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_cube_array" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -734,9 +726,9 @@
}
return BuildTextureMultisampled2D(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "texture_multisampled_2d<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "texture_multisampled_2d" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -749,8 +741,8 @@
}
return BuildTextureDepth2D(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_2d";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_2d";
}
};
@@ -763,8 +755,8 @@
}
return BuildTextureDepth2DArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_2d_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_2d_array";
}
};
@@ -777,8 +769,8 @@
}
return BuildTextureDepthCube(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_cube";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_cube";
}
};
@@ -791,8 +783,8 @@
}
return BuildTextureDepthCubeArray(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_cube_array";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_cube_array";
}
};
@@ -805,8 +797,8 @@
}
return BuildTextureDepthMultisampled2D(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_depth_multisampled_2d";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_depth_multisampled_2d";
}
};
@@ -829,10 +821,10 @@
}
return BuildTextureStorage1D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_1d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_1d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -855,10 +847,10 @@
}
return BuildTextureStorage2D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_2d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_2d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -881,10 +873,10 @@
}
return BuildTextureStorage2DArray(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_2d_array<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_2d_array" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -907,10 +899,10 @@
}
return BuildTextureStorage3D(state, ty, F, A);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string F = state->NumName();
- const std::string A = state->NumName();
- return "texture_storage_3d<" + F + ", " + A + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText F;
+ state->PrintNum(F);StyledText A;
+ state->PrintNum(A);
+ out << style::Type << "texture_storage_3d" << style::Code << "<" << style::Type << F << style::Code << ", " << style::Type << A << style::Code << ">";
}
};
@@ -923,8 +915,8 @@
}
return BuildTextureExternal(state, ty);
},
-/* string */ [](MatchState*) -> std::string {
- return "texture_external";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type << "texture_external";
}
};
@@ -942,9 +934,9 @@
}
return BuildPackedVec3(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "packedVec3<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "packedVec3" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -962,11 +954,9 @@
}
return BuildModfResult(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__modf_result_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__modf_result_" << style::Type << T;
}
};
@@ -989,12 +979,10 @@
}
return BuildModfResultVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__modf_result_vec" << N << "_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__modf_result_vec" << style::Type << N << style::Type << "_" << style::Type << T;
}
};
@@ -1012,11 +1000,9 @@
}
return BuildFrexpResult(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__frexp_result_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__frexp_result_" << style::Type << T;
}
};
@@ -1039,12 +1025,10 @@
}
return BuildFrexpResultVec(state, ty, N, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string N = state->NumName();
- const std::string T = state->TypeName();
- StringStream ss;
- ss << "__frexp_result_vec" << N << "_" << T;
- return ss.str();
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__frexp_result_vec" << style::Type << N << style::Type << "_" << style::Type << T;
}
};
@@ -1062,9 +1046,9 @@
}
return BuildAtomicCompareExchangeResult(state, ty, T);
},
-/* string */ [](MatchState* state) -> std::string {
- const std::string T = state->TypeName();
- return "__atomic_compare_exchange_result<" + T + ">";
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type << "__atomic_compare_exchange_result" << style::Code << "<" << style::Type << T << style::Code << ">";
}
};
@@ -1095,13 +1079,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match concrete_scalar'
@@ -1124,13 +1105,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_f32'
@@ -1156,13 +1134,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_f16'
@@ -1188,13 +1163,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_i32'
@@ -1220,13 +1192,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_u32'
@@ -1252,13 +1221,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kBoolMatcher.print(nullptr, out);}
};
/// TypeMatcher for 'match scalar_no_bool'
@@ -1284,13 +1250,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kF16Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fia_fiu32_f16'
@@ -1316,13 +1279,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kFaMatcher.string(nullptr) << ", " << kIaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fia_fi32_f16'
@@ -1345,13 +1305,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kFaMatcher.string(nullptr) << ", " << kIaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fia_fiu32'
@@ -1374,13 +1331,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kFaMatcher.string(nullptr) << ", " << kIaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fa_f32'
@@ -1394,13 +1348,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kFaMatcher.string(nullptr) << " or " << kF32Matcher.string(nullptr);
- return ss.str();
- }
+ kFaMatcher.print(nullptr, out); out << TextStyle{} << " or "; kF32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fa_f32_f16'
@@ -1417,13 +1368,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kFaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kF32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match ia_iu32'
@@ -1440,13 +1388,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match ia_i32'
@@ -1460,13 +1405,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kIaMatcher.string(nullptr) << " or " << kI32Matcher.string(nullptr);
- return ss.str();
- }
+ kIaMatcher.print(nullptr, out); out << TextStyle{} << " or "; kI32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fiu32_f16'
@@ -1486,13 +1428,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kU32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fiu32'
@@ -1509,13 +1448,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fi32_f16'
@@ -1532,13 +1468,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << ", "; kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match fi32'
@@ -1552,13 +1485,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << " or " << kI32Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kI32Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match f32_f16'
@@ -1572,13 +1502,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kF32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
- return ss.str();
- }
+ kF32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kF16Matcher.print(nullptr, out);}
};
/// TypeMatcher for 'match iu32'
@@ -1592,13 +1519,10 @@
}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
- return ss.str();
- }
+ kI32Matcher.print(nullptr, out); out << TextStyle{} << " or "; kU32Matcher.print(nullptr, out);}
};
/// EnumMatcher for 'match f32_texel_format'
@@ -1617,8 +1541,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "bgra8unorm, rgba8unorm, rgba8snorm, rgba16float, r32float, rg32float or rgba32float";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "bgra8unorm"<< TextStyle{} << ", " << style::Enum << "rgba8unorm"<< TextStyle{} << ", " << style::Enum << "rgba8snorm"<< TextStyle{} << ", " << style::Enum << "rgba16float"<< TextStyle{} << ", " << style::Enum << "r32float"<< TextStyle{} << ", " << style::Enum << "rg32float"<< TextStyle{} << " or " << style::Enum << "rgba32float";
}
};
@@ -1636,8 +1560,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "rgba8sint, rgba16sint, r32sint, rg32sint or rgba32sint";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "rgba8sint"<< TextStyle{} << ", " << style::Enum << "rgba16sint"<< TextStyle{} << ", " << style::Enum << "r32sint"<< TextStyle{} << ", " << style::Enum << "rg32sint"<< TextStyle{} << " or " << style::Enum << "rgba32sint";
}
};
@@ -1655,8 +1579,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "rgba8uint, rgba16uint, r32uint, rg32uint or rgba32uint";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "rgba8uint"<< TextStyle{} << ", " << style::Enum << "rgba16uint"<< TextStyle{} << ", " << style::Enum << "r32uint"<< TextStyle{} << ", " << style::Enum << "rg32uint"<< TextStyle{} << " or " << style::Enum << "rgba32uint";
}
};
@@ -1668,8 +1592,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "write";
}
};
@@ -1681,8 +1605,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "read_write";
}
};
@@ -1697,8 +1621,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "read or read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "read"<< TextStyle{} << " or " << style::Enum << "read_write";
}
};
@@ -1713,8 +1637,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "write or read_write";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "write"<< TextStyle{} << " or " << style::Enum << "read_write";
}
};
@@ -1730,8 +1654,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "function, private or workgroup";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "function"<< TextStyle{} << ", " << style::Enum << "private"<< TextStyle{} << " or " << style::Enum << "workgroup";
}
};
@@ -1746,8 +1670,8 @@
return Number::invalid;
}
},
-/* string */ [](MatchState*) -> std::string {
- return "workgroup or storage";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "workgroup"<< TextStyle{} << " or " << style::Enum << "storage";
}
};
@@ -1759,8 +1683,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "storage";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "storage";
}
};
@@ -1772,8 +1696,8 @@
}
return Number::invalid;
},
-/* string */ [](MatchState*) -> std::string {
- return "workgroup";
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum << "workgroup";
}
};
diff --git a/src/tint/lang/wgsl/intrinsic/table_test.cc b/src/tint/lang/wgsl/intrinsic/table_test.cc
index 2c98839..cbbeeda 100644
--- a/src/tint/lang/wgsl/intrinsic/table_test.cc
+++ b/src/tint/lang/wgsl/intrinsic/table_test.cc
@@ -79,7 +79,7 @@
auto result =
table.Lookup(wgsl::BuiltinFn::kCos, Empty, Vector{i32}, core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchU32) {
@@ -99,7 +99,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kUnpack2X16Float, Empty, Vector{f32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchI32) {
@@ -126,7 +126,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kTextureLoad, Empty, Vector{tex, f32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchIU32AsI32) {
@@ -154,7 +154,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kCountOneBits, Empty, Vector{f32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchFIU32AsI32) {
@@ -198,7 +198,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kClamp, Empty, Vector{bool_, bool_, bool_},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchBool) {
@@ -219,7 +219,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kSelect, Empty, Vector{f32, f32, f32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchPointer) {
@@ -241,7 +241,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kAtomicLoad, Empty, Vector{atomic_i32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchArray) {
@@ -264,7 +264,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kArrayLength, Empty, Vector{f32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchSampler) {
@@ -293,7 +293,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kTextureSample, Empty, Vector{tex, f32, vec2f},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchSampledTexture) {
@@ -417,7 +417,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kTextureLoad, Empty, Vector{f32, vec2i},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchTemplateType) {
@@ -437,7 +437,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kClamp, Empty, Vector{f32, u32, f32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchOpenSizeVector) {
@@ -460,7 +460,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kClamp, Empty, Vector{vec2f, u32, vec2f},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchOpenSizeMatrix) {
@@ -482,7 +482,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kDeterminant, Empty, Vector{mat3x2f},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, MatchDifferentArgsElementType_Builtin_ConstantEval) {
@@ -544,37 +544,37 @@
auto result = table.Lookup(wgsl::BuiltinFn::kTextureDimensions, Empty, Vector{bool_, bool_},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_EQ(result.Failure(),
- R"(no matching call to textureDimensions(bool, bool)
+ ASSERT_EQ(result.Failure().Plain(),
+ R"(no matching call to 'textureDimensions(bool, bool)'
27 candidate functions:
- textureDimensions(texture: texture_1d<T>, level: L) -> u32 where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_1d<T>) -> u32 where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_3d<T>) -> vec3<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_depth_2d) -> vec2<u32>
- textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
- textureDimensions(texture: texture_storage_1d<F, A>) -> u32
- textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>
- textureDimensions(texture: texture_external) -> vec2<u32>
+ 'textureDimensions(texture: texture_1d<T>, level: L) -> u32' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_1d<T>) -> u32' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_1d<F, A>) -> u32'
+ 'textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>'
+ 'textureDimensions(texture: texture_external) -> vec2<u32>'
)");
}
@@ -584,37 +584,37 @@
auto result = table.Lookup(wgsl::BuiltinFn::kTextureDimensions, Empty, Vector{tex, bool_},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_EQ(result.Failure(),
- R"(no matching call to textureDimensions(texture_depth_2d, bool)
+ ASSERT_EQ(result.Failure().Plain(),
+ R"(no matching call to 'textureDimensions(texture_depth_2d, bool)'
27 candidate functions:
- textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_1d<T>, level: L) -> u32 where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32> where: T is f32, i32 or u32, L is i32 or u32
- textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32> where: L is i32 or u32
- textureDimensions(texture: texture_depth_2d) -> vec2<u32>
- textureDimensions(texture: texture_1d<T>) -> u32 where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_2d_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_3d<T>) -> vec3<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_cube_array<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32> where: T is f32, i32 or u32
- textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube) -> vec2<u32>
- textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
- textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
- textureDimensions(texture: texture_storage_1d<F, A>) -> u32
- textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
- textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>
- textureDimensions(texture: texture_external) -> vec2<u32>
+ 'textureDimensions(texture: texture_depth_2d, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_1d<T>, level: L) -> u32' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>, level: L) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>, level: L) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32', 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_cube_array, level: L) -> vec2<u32>' where: 'L' is 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_1d<T>) -> u32' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_2d_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_3d<T>) -> vec3<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_cube_array<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<u32>' where: 'T' is 'f32', 'i32' or 'u32'
+ 'textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>'
+ 'textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_1d<F, A>) -> u32'
+ 'textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<u32>'
+ 'textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<u32>'
+ 'textureDimensions(texture: texture_external) -> vec2<u32>'
)");
}
@@ -630,11 +630,11 @@
auto* bool_ = create<core::type::Bool>();
auto result = table.Lookup(core::UnaryOp::kNegation, bool_, core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(), R"(no matching overload for operator - (bool)
+ EXPECT_EQ(result.Failure().Plain(), R"(no matching overload for 'operator - (bool)'
2 candidate operators:
- operator - (T) -> T where: T is abstract-float, abstract-int, f32, i32 or f16
- operator - (vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32 or f16
+ 'operator - (T) -> T' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32' or 'f16'
+ 'operator - (vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32' or 'f16'
)");
}
@@ -672,18 +672,18 @@
table.Lookup(core::BinaryOp::kMultiply, f32, bool_, core::EvaluationStage::kConstant,
/* is_compound */ false);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(), R"(no matching overload for operator * (f32, bool)
+ EXPECT_EQ(result.Failure().Plain(), R"(no matching overload for 'operator * (f32, bool)'
9 candidate operators:
- operator * (T, T) -> T where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator * (vecN<T>, T) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator * (T, vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator * (T, matNxM<T>) -> matNxM<T> where: T is abstract-float, f32 or f16
- operator * (matNxM<T>, T) -> matNxM<T> where: T is abstract-float, f32 or f16
- operator * (vecN<T>, vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator * (matCxR<T>, vecC<T>) -> vecR<T> where: T is abstract-float, f32 or f16
- operator * (vecR<T>, matCxR<T>) -> vecC<T> where: T is abstract-float, f32 or f16
- operator * (matKxR<T>, matCxK<T>) -> matCxR<T> where: T is abstract-float, f32 or f16
+ 'operator * (T, T) -> T' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (vecN<T>, T) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (T, vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (T, matNxM<T>) -> matNxM<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator * (matNxM<T>, T) -> matNxM<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator * (vecN<T>, vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator * (matCxR<T>, vecC<T>) -> vecR<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator * (vecR<T>, matCxR<T>) -> vecC<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator * (matKxR<T>, matCxK<T>) -> matCxR<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -706,18 +706,18 @@
table.Lookup(core::BinaryOp::kMultiply, f32, bool_, core::EvaluationStage::kConstant,
/* is_compound */ true);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(), R"(no matching overload for operator *= (f32, bool)
+ EXPECT_EQ(result.Failure().Plain(), R"(no matching overload for 'operator *= (f32, bool)'
9 candidate operators:
- operator *= (T, T) -> T where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator *= (vecN<T>, T) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator *= (T, vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator *= (T, matNxM<T>) -> matNxM<T> where: T is abstract-float, f32 or f16
- operator *= (matNxM<T>, T) -> matNxM<T> where: T is abstract-float, f32 or f16
- operator *= (vecN<T>, vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- operator *= (matCxR<T>, vecC<T>) -> vecR<T> where: T is abstract-float, f32 or f16
- operator *= (vecR<T>, matCxR<T>) -> vecC<T> where: T is abstract-float, f32 or f16
- operator *= (matKxR<T>, matCxK<T>) -> matCxR<T> where: T is abstract-float, f32 or f16
+ 'operator *= (T, T) -> T' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (vecN<T>, T) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (T, vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (T, matNxM<T>) -> matNxM<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator *= (matNxM<T>, T) -> matNxM<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator *= (vecN<T>, vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'operator *= (matCxR<T>, vecC<T>) -> vecR<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator *= (vecR<T>, matCxR<T>) -> vecC<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'operator *= (matKxR<T>, matCxK<T>) -> matCxR<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -757,29 +757,29 @@
auto result = table.Lookup(CtorConv::kVec3, Empty, Vector{i32, f32, i32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(),
- R"(no matching constructor for vec3(i32, f32, i32)
+ EXPECT_EQ(result.Failure().Plain(),
+ R"(no matching constructor for 'vec3(i32, f32, i32)'
12 candidate constructors:
- vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(xy: vec2<T>, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(x: T, yz: vec2<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(vec3<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3() -> vec3<abstract-int>
- vec3<T>() -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(x: T, y: T, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
+ 'vec3(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(vec3<T>) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3() -> vec3<abstract-int>'
+ 'vec3<T>() -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec3<T>(vec3<U>) -> vec3<T> where: T is f32, U is abstract-int, abstract-float, i32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is f16, U is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is i32, U is abstract-int, abstract-float, f32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is u32, U is abstract-int, abstract-float, f32, f16, i32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is bool, U is abstract-int, abstract-float, f32, f16, i32 or u32
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f32', 'U' is 'abstract-int', 'abstract-float', 'i32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f16', 'U' is 'abstract-int', 'abstract-float', 'f32', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'i32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'u32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'bool', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -789,29 +789,29 @@
auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, f32, i32},
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(),
- R"(no matching constructor for vec3<i32>(i32, f32, i32)
+ EXPECT_EQ(result.Failure().Plain(),
+ R"(no matching constructor for 'vec3<i32>(i32, f32, i32)'
12 candidate constructors:
- vec3<T>(x: T, y: T, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(xy: vec2<T>, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(x: T, yz: vec2<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(vec3<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3() -> vec3<abstract-int>
- vec3<T>() -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'vec3<T>(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(vec3<T>) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3() -> vec3<abstract-int>'
+ 'vec3<T>() -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec3<T>(vec3<U>) -> vec3<T> where: T is f32, U is abstract-int, abstract-float, i32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is f16, U is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is i32, U is abstract-int, abstract-float, f32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is u32, U is abstract-int, abstract-float, f32, f16, i32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is bool, U is abstract-int, abstract-float, f32, f16, i32 or u32
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f32', 'U' is 'abstract-int', 'abstract-float', 'i32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f16', 'U' is 'abstract-int', 'abstract-float', 'f32', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'i32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'u32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'bool', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -898,29 +898,29 @@
auto result =
table.Lookup(CtorConv::kVec3, Vector{f32}, Vector{arr}, core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- EXPECT_EQ(result.Failure(),
- R"(no matching constructor for vec3<f32>(array<u32>)
+ EXPECT_EQ(result.Failure().Plain(),
+ R"(no matching constructor for 'vec3<f32>(array<u32>)'
12 candidate constructors:
- vec3<T>(vec3<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3() -> vec3<abstract-int>
- vec3<T>() -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3<T>(x: T, yz: vec2<T>) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(x: T, yz: vec2<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(xy: vec2<T>, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(xy: vec2<T>, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3<T>(x: T, y: T, z: T) -> vec3<T> where: T is f32, f16, i32, u32 or bool
- vec3(x: T, y: T, z: T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3(T) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- vec3(vec3<T>) -> vec3<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'vec3<T>(vec3<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3() -> vec3<abstract-int>'
+ 'vec3<T>() -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(x: T, yz: vec2<T>) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(xy: vec2<T>, z: T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3<T>(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(x: T, y: T, z: T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(T) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'vec3(vec3<T>) -> vec3<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
5 candidate conversions:
- vec3<T>(vec3<U>) -> vec3<T> where: T is f32, U is abstract-int, abstract-float, i32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is f16, U is abstract-int, abstract-float, f32, i32, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is i32, U is abstract-int, abstract-float, f32, f16, u32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is u32, U is abstract-int, abstract-float, f32, f16, i32 or bool
- vec3<T>(vec3<U>) -> vec3<T> where: T is bool, U is abstract-int, abstract-float, f32, f16, i32 or u32
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f32', 'U' is 'abstract-int', 'abstract-float', 'i32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'f16', 'U' is 'abstract-int', 'abstract-float', 'f32', 'i32', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'i32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'u32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'u32', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'bool'
+ 'vec3<T>(vec3<U>) -> vec3<T>' where: 'T' is 'bool', 'U' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32' or 'u32'
)");
}
@@ -964,7 +964,7 @@
auto result = table.Lookup(wgsl::BuiltinFn::kAbs, Empty, std::move(arg_tys),
core::EvaluationStage::kConstant);
ASSERT_NE(result, Success);
- ASSERT_THAT(result.Failure(), HasSubstr("no matching call"));
+ ASSERT_THAT(result.Failure().Plain(), HasSubstr("no matching call"));
}
TEST_F(WgslIntrinsicTableTest, OverloadResolution) {
diff --git a/src/tint/lang/wgsl/program/program.cc b/src/tint/lang/wgsl/program/program.cc
index bcd8e93..c649781 100644
--- a/src/tint/lang/wgsl/program/program.cc
+++ b/src/tint/lang/wgsl/program/program.cc
@@ -81,7 +81,7 @@
// If the builder claims to be invalid, then we really should have an error
// message generated. If we find a situation where the program is not valid
// and there are no errors reported, add one here.
- diagnostics_.AddError(diag::System::Program, "invalid program generated");
+ diagnostics_.AddError(diag::System::Program, Source{}) << "invalid program generated";
}
}
diff --git a/src/tint/lang/wgsl/program/program_test.cc b/src/tint/lang/wgsl/program/program_test.cc
index 1a59adb..2572ca5 100644
--- a/src/tint/lang/wgsl/program/program_test.cc
+++ b/src/tint/lang/wgsl/program/program_test.cc
@@ -93,19 +93,19 @@
}
TEST_F(ProgramTest, DiagnosticsMove) {
- Diagnostics().AddError(diag::System::Program, "an error message");
+ Diagnostics().AddError(diag::System::Program, Source{}) << "an error message";
Program program_a(std::move(*this));
EXPECT_FALSE(program_a.IsValid());
EXPECT_EQ(program_a.Diagnostics().Count(), 1u);
EXPECT_EQ(program_a.Diagnostics().NumErrors(), 1u);
- EXPECT_EQ(program_a.Diagnostics().begin()->message, "an error message");
+ EXPECT_EQ(program_a.Diagnostics().begin()->message.Plain(), "an error message");
Program program_b(std::move(program_a));
EXPECT_FALSE(program_b.IsValid());
EXPECT_EQ(program_b.Diagnostics().Count(), 1u);
EXPECT_EQ(program_b.Diagnostics().NumErrors(), 1u);
- EXPECT_EQ(program_b.Diagnostics().begin()->message, "an error message");
+ EXPECT_EQ(program_b.Diagnostics().begin()->message.Plain(), "an error message");
}
TEST_F(ProgramTest, ReuseMovedFromVariable) {
diff --git a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
index 6f689b3..adb1d1c 100644
--- a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
@@ -205,7 +205,7 @@
// Error when unknown extension found
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_framebuffer_fetch', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_framebuffer_fetch', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_graphite', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
diff --git a/src/tint/lang/wgsl/reader/parser/error_msg_test.cc b/src/tint/lang/wgsl/reader/parser/error_msg_test.cc
index dc46bc5..2e79a9b 100644
--- a/src/tint/lang/wgsl/reader/parser/error_msg_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/error_msg_test.cc
@@ -38,16 +38,16 @@
class ParserImplErrorTest : public WGSLParserTest {};
-#define EXPECT(SOURCE, EXPECTED) \
- do { \
- std::string source = SOURCE; \
- std::string expected = EXPECTED; \
- auto p = parser(source); \
- p->set_max_errors(5); \
- EXPECT_EQ(false, p->Parse()); \
- auto diagnostics = p->builder().Diagnostics(); \
- EXPECT_EQ(true, diagnostics.ContainsErrors()); \
- EXPECT_EQ(expected, diag::Formatter(formatter_style).Format(diagnostics)); \
+#define EXPECT(SOURCE, EXPECTED) \
+ do { \
+ std::string source = SOURCE; \
+ std::string expected = EXPECTED; \
+ auto p = parser(source); \
+ p->set_max_errors(5); \
+ EXPECT_EQ(false, p->Parse()); \
+ auto diagnostics = p->builder().Diagnostics(); \
+ EXPECT_EQ(true, diagnostics.ContainsErrors()); \
+ EXPECT_EQ(expected, diag::Formatter(formatter_style).Format(diagnostics).Plain()); \
} while (false)
TEST_F(ParserImplErrorTest, AdditiveInvalidExpr) {
diff --git a/src/tint/lang/wgsl/reader/parser/error_resync_test.cc b/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
index 31a6dbc..54818ea 100644
--- a/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
@@ -36,15 +36,15 @@
class ParserImplErrorResyncTest : public WGSLParserTest {};
-#define EXPECT(SOURCE, EXPECTED) \
- do { \
- std::string source = SOURCE; \
- std::string expected = EXPECTED; \
- auto p = parser(source); \
- EXPECT_EQ(false, p->Parse()); \
- auto diagnostics = p->builder().Diagnostics(); \
- EXPECT_EQ(true, diagnostics.ContainsErrors()); \
- EXPECT_EQ(expected, diag::Formatter(formatter_style).Format(diagnostics)); \
+#define EXPECT(SOURCE, EXPECTED) \
+ do { \
+ std::string source = SOURCE; \
+ std::string expected = EXPECTED; \
+ auto p = parser(source); \
+ EXPECT_EQ(false, p->Parse()); \
+ auto diagnostics = p->builder().Diagnostics(); \
+ EXPECT_EQ(true, diagnostics.ContainsErrors()); \
+ EXPECT_EQ(expected, diag::Formatter(formatter_style).Format(diagnostics).Plain()); \
} while (false)
TEST_F(ParserImplErrorResyncTest, BadFunctionDecls) {
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index 0716617..315d701 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -242,22 +242,28 @@
Parser::Failure::Errored Parser::AddError(const Source& source, std::string_view err) {
if (silence_diags_ == 0) {
- builder_.Diagnostics().AddError(diag::System::Reader, err, source);
+ builder_.Diagnostics().AddError(diag::System::Reader, source) << err;
+ }
+ return Failure::kErrored;
+}
+
+Parser::Failure::Errored Parser::AddError(const Source& source, StyledText&& err) {
+ if (silence_diags_ == 0) {
+ builder_.Diagnostics().AddError(diag::System::Reader, source) << std::move(err);
}
return Failure::kErrored;
}
void Parser::AddNote(const Source& source, std::string_view err) {
if (silence_diags_ == 0) {
- builder_.Diagnostics().AddNote(diag::System::Reader, err, source);
+ builder_.Diagnostics().AddNote(diag::System::Reader, source) << err;
}
}
void Parser::deprecated(const Source& source, std::string_view msg) {
if (silence_diags_ == 0) {
- builder_.Diagnostics().AddWarning(diag::System::Reader,
- "use of deprecated language feature: " + std::string(msg),
- source);
+ builder_.Diagnostics().AddWarning(diag::System::Reader, source)
+ << "use of deprecated language feature: " << msg;
}
}
@@ -927,7 +933,7 @@
}
/// Create a sensible error message
- StringStream err;
+ StyledText err;
err << "expected " << name;
if (!use.empty()) {
@@ -951,7 +957,7 @@
}
synchronized_ = false;
- return AddError(t.source(), err.str());
+ return AddError(t.source(), std::move(err));
}
Expect<ast::Type> Parser::expect_type(std::string_view use) {
diff --git a/src/tint/lang/wgsl/reader/parser/parser.h b/src/tint/lang/wgsl/reader/parser/parser.h
index 9124e89..993c544 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.h
+++ b/src/tint/lang/wgsl/reader/parser/parser.h
@@ -41,6 +41,7 @@
#include "src/tint/lang/wgsl/reader/parser/token.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
#include "src/tint/utils/diagnostic/formatter.h"
+#include "src/tint/utils/text/styled_text.h"
namespace tint::ast {
class BreakStatement;
@@ -328,7 +329,7 @@
/// @returns the parser error string
std::string error() const {
diag::Formatter formatter{{false, false, false, false}};
- return formatter.Format(builder_.Diagnostics());
+ return formatter.Format(builder_.Diagnostics()).Plain();
}
/// @returns the Program. The program builder in the parser will be reset
@@ -373,6 +374,12 @@
/// @return `Failure::Errored::kError` so that you can combine an AddError()
/// call and return on the same line.
Failure::Errored AddError(const Source& source, std::string_view msg);
+ /// Appends an error at `source` with the message `msg`
+ /// @param source the source to associate the error with
+ /// @param msg the error message
+ /// @return `Failure::Errored::kError` so that you can combine an AddError()
+ /// call and return on the same line.
+ Failure::Errored AddError(const Source& source, StyledText&& msg);
/// Appends a note at `source` with the message `msg`
/// @param source the source to associate the error with
/// @param msg the note message
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index 751f21c..f54aba6 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -200,8 +200,8 @@
~ControlStackScope() { impl_->control_stack_.Pop(); }
};
- void AddError(const Source& s, const std::string& err) {
- diagnostics_.AddError(tint::diag::System::IR, err, s);
+ diag::Diagnostic& AddError(const Source& source) {
+ return diagnostics_.AddError(tint::diag::System::IR, source);
}
bool NeedTerminator() { return current_block_ && !current_block_->Terminator(); }
@@ -1003,8 +1003,8 @@
if (mat->ConstantValue()) {
auto* cv = mat->ConstantValue()->Clone(impl.clone_ctx_);
if (!cv) {
- impl.AddError(expr->source, "failed to get constant value for call " +
- std::string(expr->TypeInfo().name));
+ impl.AddError(expr->source) << "failed to get constant value for call "
+ << expr->TypeInfo().name;
return;
}
Bind(expr, impl.builder_.Constant(cv));
@@ -1017,15 +1017,15 @@
for (const auto* arg : expr->args) {
auto value = GetValue(arg);
if (!value) {
- impl.AddError(arg->source, "failed to convert arguments");
+ impl.AddError(arg->source) << "failed to convert arguments";
return;
}
args.Push(value);
}
auto* sem = impl.program_.Sem().Get<sem::Call>(expr);
if (!sem) {
- impl.AddError(expr->source, "failed to get semantic information for call " +
- std::string(expr->TypeInfo().name));
+ impl.AddError(expr->source)
+ << "failed to get semantic information for call " << expr->TypeInfo().name;
return;
}
auto* ty = sem->Target()->ReturnType()->Clone(impl.clone_ctx_.type_ctx);
@@ -1063,8 +1063,8 @@
void EmitIdentifier(const ast::IdentifierExpression* i) {
auto* v = impl.scopes_.Get(i->identifier->symbol);
if (TINT_UNLIKELY(!v)) {
- impl.AddError(i->source,
- "unable to find identifier " + i->identifier->symbol.Name());
+ impl.AddError(i->source)
+ << "unable to find identifier " << i->identifier->symbol.Name();
return;
}
Bind(i, v);
@@ -1073,14 +1073,14 @@
void EmitLiteral(const ast::LiteralExpression* lit) {
auto* sem = impl.program_.Sem().Get(lit);
if (!sem) {
- impl.AddError(lit->source, "failed to get semantic information for node " +
- std::string(lit->TypeInfo().name));
+ impl.AddError(lit->source)
+ << "failed to get semantic information for node " << lit->TypeInfo().name;
return;
}
auto* cv = sem->ConstantValue()->Clone(impl.clone_ctx_);
if (!cv) {
- impl.AddError(lit->source, "failed to get constant value for node " +
- std::string(lit->TypeInfo().name));
+ impl.AddError(lit->source)
+ << "failed to get constant value for node " << lit->TypeInfo().name;
return;
}
auto* val = impl.builder_.Constant(cv);
@@ -1270,9 +1270,8 @@
scopes_.Set(l->name->symbol, let->Result(0));
},
[&](const ast::Override*) {
- AddError(var->source,
- "found an `Override` variable. The SubstituteOverrides "
- "transform must be run before converting to IR");
+ AddError(var->source) << "found an `Override` variable. The SubstituteOverrides "
+ "transform must be run before converting to IR";
},
[&](const ast::Const*) {
// Skip. This should be handled by const-eval already, so the const will be a
@@ -1344,7 +1343,7 @@
auto r = b.Build();
if (r != Success) {
diag::List err = std::move(r.Failure().reason);
- err.AddNote(diag::System::IR, "AST:\n" + Program::printer(program), Source{});
+ err.AddNote(diag::System::IR, Source{}) << "AST:\n" + Program::printer(program);
return Failure{err};
}
diff --git a/src/tint/lang/wgsl/reader/reader.cc b/src/tint/lang/wgsl/reader/reader.cc
index 40c4f79..f2e20be 100644
--- a/src/tint/lang/wgsl/reader/reader.cc
+++ b/src/tint/lang/wgsl/reader/reader.cc
@@ -41,8 +41,8 @@
if (TINT_UNLIKELY(file->content.data.size() >
static_cast<size_t>(std::numeric_limits<uint32_t>::max()))) {
ProgramBuilder b;
- b.Diagnostics().AddError(tint::diag::System::Reader,
- "WGSL source must be 0xffffffff bytes or fewer");
+ b.Diagnostics().AddError(tint::diag::System::Reader, Source{})
+ << "WGSL source must be 0xffffffff bytes or fewer";
return Program(std::move(b));
}
Parser parser(file);
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 c415620..aacf005 100644
--- a/src/tint/lang/wgsl/resolver/address_space_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/address_space_validation_test.cc
@@ -56,7 +56,7 @@
Alias("g", ty(Source{{12, 34}}, "ptr", ty.f32()));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: 'ptr' requires at least 2 template arguments");
+ EXPECT_EQ(r()->error(), R"(12:34 error: 'ptr' requires at least 2 template arguments)");
}
TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_FunctionAddressSpace_Fail) {
@@ -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 826fbd0..61eb5a5 100644
--- a/src/tint/lang/wgsl/resolver/assignment_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/assignment_validation_test.cc
@@ -54,8 +54,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "56:78 error: cannot store into a read-only type 'ref<storage, "
- "i32, read>'");
+ R"(56:78 error: cannot store into a read-only type 'ref<storage, i32, read>')");
}
TEST_F(ResolverAssignmentValidationTest, AssignIncompatibleTypes) {
@@ -234,9 +233,9 @@
WrapInFunction(Assign(Expr(Source{{12, 34}}, "a"), 2_i));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to override 'a'
+ EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to 'override a'
12:34 note: 'override' variables are immutable
-56:78 note: override 'a' declared here)");
+56:78 note: 'override a' declared here)");
}
TEST_F(ResolverAssignmentValidationTest, AssignToLet_Fail) {
@@ -248,9 +247,9 @@
Assign(Expr(Source{{12, 34}}, "a"), 2_i));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to let 'a'
+ EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to 'let a'
12:34 note: 'let' variables are immutable
-56:78 note: let 'a' declared here)");
+56:78 note: 'let a' declared here)");
}
TEST_F(ResolverAssignmentValidationTest, AssignToConst_Fail) {
@@ -262,9 +261,9 @@
Assign(Expr(Source{{12, 34}}, "a"), 2_i));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to const 'a'
+ EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to 'const a'
12:34 note: 'const' variables are immutable
-56:78 note: const 'a' declared here)");
+56:78 note: 'const a' declared here)");
}
TEST_F(ResolverAssignmentValidationTest, AssignToParam_Fail) {
@@ -294,7 +293,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: cannot assign to value of type 'i32'
56:78 note: 'let' variables are immutable
-98:76 note: let 'a' declared here)");
+98:76 note: 'let a' declared here)");
}
TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) {
@@ -366,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) {
@@ -388,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 33cccae..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) {
@@ -1522,8 +1523,8 @@
Vector{Member(Source{{12, 5}}, "a", ty.f32(),
Vector{MemberAlign(Expr(Source{{12, 35}}, "val"))})});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:35 error: var 'val' cannot be referenced at module-scope
-1:2 note: var 'val' declared here)");
+ EXPECT_EQ(r()->error(), R"(12:35 error: 'var val' cannot be referenced at module-scope
+1:2 note: 'var val' declared here)");
}
TEST_F(StructMemberAttributeTest, Align_Attribute_Override) {
@@ -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) {
@@ -1595,8 +1596,8 @@
Vector{Member(Source{{12, 5}}, "a", ty.f32(),
Vector{MemberSize(Expr(Source{{12, 35}}, "val"))})});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:35 error: var 'val' cannot be referenced at module-scope
-1:2 note: var 'val' declared here)");
+ EXPECT_EQ(r()->error(), R"(12:35 error: 'var val' cannot be referenced at module-scope
+1:2 note: 'var val' declared here)");
}
TEST_F(StructMemberAttributeTest, Size_Attribute_Override) {
@@ -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/bitcast_validation_test.cc b/src/tint/lang/wgsl/resolver/bitcast_validation_test.cc
index e96a255..bcd8bab 100644
--- a/src/tint/lang/wgsl/resolver/bitcast_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/bitcast_validation_test.cc
@@ -168,7 +168,7 @@
WrapInFunction(Bitcast(Source{{12, 34}}, dst.ast(*this), src.expr(*this, 0)));
- std::string expected = "12:34 error: no matching call to bitcast<${TO}>(${FROM})";
+ std::string expected = "12:34 error: no matching call to 'bitcast<${TO}>(${FROM})'";
expected = ReplaceAll(expected, "${FROM}", src.sem(*this)->FriendlyName());
expected = ReplaceAll(expected, "${TO}", dst.sem(*this)->FriendlyName());
diff --git a/src/tint/lang/wgsl/resolver/builtin_test.cc b/src/tint/lang/wgsl/resolver/builtin_test.cc
index 37dc276..7dfdf9f 100644
--- a/src/tint/lang/wgsl/resolver/builtin_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_test.cc
@@ -163,12 +163,12 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to select()
+ R"(error: no matching call to 'select()'
3 candidate functions:
- select(T, T, bool) -> T where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'select(T, T, bool) -> T' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, bool) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -179,12 +179,12 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to select(i32, i32, i32)
+ R"(error: no matching call to 'select(i32, i32, i32)'
3 candidate functions:
- select(T, T, bool) -> T where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'select(T, T, bool) -> T' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, bool) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -197,12 +197,12 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to select(mat2x2<f32>, mat2x2<f32>, bool)
+ R"(error: no matching call to 'select(mat2x2<f32>, mat2x2<f32>, bool)'
3 candidate functions:
- select(T, T, bool) -> T where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'select(T, T, bool) -> T' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, bool) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -213,12 +213,12 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to select(f32, vec2<f32>, bool)
+ R"(error: no matching call to 'select(f32, vec2<f32>, bool)'
3 candidate functions:
- select(T, T, bool) -> T where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'select(T, T, bool) -> T' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, bool) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -229,12 +229,12 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to select(vec2<f32>, vec3<f32>, bool)
+ R"(error: no matching call to 'select(vec2<f32>, vec3<f32>, bool)'
3 candidate functions:
- select(T, T, bool) -> T where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
- select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ 'select(T, T, bool) -> T' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, bool) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
+ 'select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T>' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'i32', 'u32' or 'bool'
)");
}
@@ -268,10 +268,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
+ R"(error: no matching call to 'arrayLength(ptr<private, array<i32, 4>, read_write>)'
1 candidate function:
- arrayLength(ptr<storage, array<T>, A>) -> u32
+ 'arrayLength(ptr<storage, array<T>, A>) -> u32'
)");
}
@@ -306,7 +306,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "()"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) + "()'"));
}
TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Scalar_f32) {
@@ -331,7 +331,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "(f32)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) + "(f32)'"));
}
}
@@ -357,8 +357,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<f32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<f32>)'"));
}
}
@@ -378,8 +378,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(f32, f32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(f32, f32)'"));
}
}
@@ -402,8 +402,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<f32>, vec3<f32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<f32>, vec3<f32>)'"));
}
}
@@ -423,8 +423,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(f32, f32, f32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(f32, f32, f32)'"));
}
}
@@ -449,8 +449,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<f32>, vec3<f32>, vec3<f32>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<f32>, vec3<f32>, vec3<f32>)'"));
}
}
@@ -470,8 +470,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(f32, f32, f32, f32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(f32, f32, f32, f32)'"));
}
}
@@ -496,8 +496,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<f32>, vec3<f32>, vec3<f32>, vec3<f32>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<f32>, vec3<f32>, vec3<f32>, vec3<f32>)'"));
}
}
@@ -525,7 +525,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "(f16)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) + "(f16)'"));
}
}
@@ -553,8 +553,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<f16>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<f16>)'"));
}
}
@@ -576,8 +576,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(f16, f16)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(f16, f16)'"));
}
}
@@ -602,8 +602,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<f16>, vec3<f16>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<f16>, vec3<f16>)'"));
}
}
@@ -625,8 +625,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(f16, f16, f16)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(f16, f16, f16)'"));
}
}
@@ -653,8 +653,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<f16>, vec3<f16>, vec3<f16>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<f16>, vec3<f16>, vec3<f16>)'"));
}
}
@@ -676,8 +676,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(f16, f16, f16, f16)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(f16, f16, f16, f16)'"));
}
}
@@ -704,8 +704,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<f16>, vec3<f16>, vec3<f16>, vec3<f16>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<f16>, vec3<f16>, vec3<f16>, vec3<f16>)'"));
}
}
@@ -797,10 +797,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'cross()'
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
+ 'cross(vec3<T>, vec3<T>) -> vec3<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -810,10 +810,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'cross(f32, f32)'
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
+ 'cross(vec3<T>, vec3<T>) -> vec3<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -824,10 +824,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
+ R"(error: no matching call to 'cross(vec3<i32>, vec3<i32>)'
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
+ 'cross(vec3<T>, vec3<T>) -> vec3<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -840,10 +840,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
+ R"(error: no matching call to 'cross(vec4<f32>, vec4<f32>)'
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
+ 'cross(vec3<T>, vec3<T>) -> vec3<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -856,10 +856,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
+ R"(error: no matching call to 'cross(vec3<f32>, vec3<f32>, vec3<f32>)'
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
+ 'cross(vec3<T>, vec3<T>) -> vec3<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -915,11 +915,12 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to distance(vec3<f32>, vec3<f32>, vec3<f32>)
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching call to 'distance(vec3<f32>, vec3<f32>, vec3<f32>)'
2 candidate functions:
- distance(T, T) -> T where: T is abstract-float, f32 or f16
- distance(vecN<T>, vecN<T>) -> T where: T is abstract-float, f32 or f16
+ 'distance(T, T) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'distance(vecN<T>, vecN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -929,11 +930,11 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to distance(vec3<f32>)
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'distance(vec3<f32>)'
2 candidate functions:
- distance(T, T) -> T where: T is abstract-float, f32 or f16
- distance(vecN<T>, vecN<T>) -> T where: T is abstract-float, f32 or f16
+ 'distance(T, T) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'distance(vecN<T>, vecN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -943,11 +944,11 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to distance()
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'distance()'
2 candidate functions:
- distance(T, T) -> T where: T is abstract-float, f32 or f16
- distance(vecN<T>, vecN<T>) -> T where: T is abstract-float, f32 or f16
+ 'distance(T, T) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'distance(vecN<T>, vecN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1089,11 +1090,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to frexp(i32, ptr<workgroup, i32, read_write>)
+ R"(error: no matching call to 'frexp(i32, ptr<workgroup, i32, read_write>)'
2 candidate functions:
- frexp(T) -> __frexp_result_T where: T is abstract-float, f32 or f16
- frexp(vecN<T>) -> __frexp_result_vecN_T where: T is abstract-float, f32 or f16
+ 'frexp(T) -> __frexp_result_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'frexp(vecN<T>) -> __frexp_result_vecN_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1148,11 +1149,11 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to length()
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'length()'
2 candidate functions:
- length(T) -> T where: T is abstract-float, f32 or f16
- length(vecN<T>) -> T where: T is abstract-float, f32 or f16
+ 'length(T) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'length(vecN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1162,11 +1163,11 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to length(f32, f32)
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'length(f32, f32)'
2 candidate functions:
- length(T) -> T where: T is abstract-float, f32 or f16
- length(vecN<T>) -> T where: T is abstract-float, f32 or f16
+ 'length(T) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'length(vecN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1338,11 +1339,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to modf(i32, ptr<workgroup, f32, read_write>)
+ R"(error: no matching call to 'modf(i32, ptr<workgroup, f32, read_write>)'
2 candidate functions:
- modf(T) -> __modf_result_T where: T is abstract-float, f32 or f16
- modf(vecN<T>) -> __modf_result_vecN_T where: T is abstract-float, f32 or f16
+ 'modf(T) -> __modf_result_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'modf(vecN<T>) -> __modf_result_vecN_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1354,11 +1355,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to modf(f32, ptr<workgroup, i32, read_write>)
+ R"(error: no matching call to 'modf(f32, ptr<workgroup, i32, read_write>)'
2 candidate functions:
- modf(T) -> __modf_result_T where: T is abstract-float, f32 or f16
- modf(vecN<T>) -> __modf_result_vecN_T where: T is abstract-float, f32 or f16
+ 'modf(T) -> __modf_result_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'modf(vecN<T>) -> __modf_result_vecN_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1368,11 +1369,11 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to modf(f32, f32)
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'modf(f32, f32)'
2 candidate functions:
- modf(T) -> __modf_result_T where: T is abstract-float, f32 or f16
- modf(vecN<T>) -> __modf_result_vecN_T where: T is abstract-float, f32 or f16
+ 'modf(T) -> __modf_result_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'modf(vecN<T>) -> __modf_result_vecN_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1384,11 +1385,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)
+ R"(error: no matching call to 'modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)'
2 candidate functions:
- modf(T) -> __modf_result_T where: T is abstract-float, f32 or f16
- modf(vecN<T>) -> __modf_result_vecN_T where: T is abstract-float, f32 or f16
+ 'modf(T) -> __modf_result_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
+ 'modf(vecN<T>) -> __modf_result_vecN_T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1425,10 +1426,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'normalize()'
1 candidate function:
- normalize(vecN<T>) -> vecN<T> where: T is abstract-float, f32 or f16
+ 'normalize(vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1463,7 +1464,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "()"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) + "()'"));
}
TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Scalar_i32) {
@@ -1483,7 +1484,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "(i32)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) + "(i32)'"));
}
}
@@ -1506,8 +1507,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<i32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<i32>)'"));
}
}
@@ -1528,7 +1529,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) + "(u32)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) + "(u32)'"));
}
}
@@ -1551,8 +1552,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<u32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<u32>)'"));
}
}
@@ -1572,8 +1573,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(i32, i32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(i32, i32)'"));
}
}
@@ -1596,8 +1597,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<i32>, vec3<i32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<i32>, vec3<i32>)'"));
}
}
@@ -1617,8 +1618,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(u32, u32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(u32, u32)'"));
}
}
@@ -1641,8 +1642,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(vec3<u32>, vec3<u32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(vec3<u32>, vec3<u32>)'"));
}
}
@@ -1662,8 +1663,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(i32, i32, i32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(i32, i32, i32)'"));
}
}
@@ -1688,8 +1689,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<i32>, vec3<i32>, vec3<i32>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<i32>, vec3<i32>, vec3<i32>)'"));
}
}
@@ -1709,8 +1710,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(u32, u32, u32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(u32, u32, u32)'"));
}
}
@@ -1735,8 +1736,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<u32>, vec3<u32>, vec3<u32>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<u32>, vec3<u32>, vec3<u32>)'"));
}
}
@@ -1756,8 +1757,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(i32, i32, i32, i32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(i32, i32, i32, i32)'"));
}
}
@@ -1782,8 +1783,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<i32>, vec3<i32>, vec3<i32>, vec3<i32>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<i32>, vec3<i32>, vec3<i32>, vec3<i32>)'"));
}
}
@@ -1803,8 +1804,8 @@
// Invalid parameter count.
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
- std::string(param.name) + "(u32, u32, u32, u32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" +
+ std::string(param.name) + "(u32, u32, u32, u32)'"));
}
}
@@ -1829,8 +1830,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("error: no matching call to " + std::string(param.name) +
- "(vec3<u32>, vec3<u32>, vec3<u32>, vec3<u32>)"));
+ HasSubstr("error: no matching call to '" + std::string(param.name) +
+ "(vec3<u32>, vec3<u32>, vec3<u32>, vec3<u32>)'"));
}
}
@@ -1942,10 +1943,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(mat2x3<f32>)
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'determinant(mat2x3<f32>)'
1 candidate function:
- determinant(matNxN<T>) -> T where: T is abstract-float, f32 or f16
+ 'determinant(matNxN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -1957,10 +1958,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(f32)
+ EXPECT_EQ(r()->error(), R"(error: no matching call to 'determinant(f32)'
1 candidate function:
- determinant(matNxN<T>) -> T where: T is abstract-float, f32 or f16
+ 'determinant(matNxN<T>) -> T' where: 'T' is 'abstract-float', 'f32' or 'f16'
)");
}
@@ -2026,10 +2027,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to dot(f32, f32)
+ R"(error: no matching call to 'dot(f32, f32)'
1 candidate function:
- dot(vecN<T>, vecN<T>) -> T where: T is abstract-float, abstract-int, f32, i32, u32 or f16
+ 'dot(vecN<T>, vecN<T>) -> T' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
)");
}
@@ -2079,10 +2080,10 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: no matching call to " + name +
- "()\n\n"
- "2 candidate functions:\n " +
- name + "(f32) -> f32\n " + name + "(vecN<f32>) -> vecN<f32>\n");
+ EXPECT_EQ(r()->error(), "error: no matching call to '" + name +
+ "()'\n\n"
+ "2 candidate functions:\n '" +
+ name + "(f32) -> f32'\n '" + name + "(vecN<f32>) -> vecN<f32>'\n");
}
INSTANTIATE_TEST_SUITE_P(ResolverTest,
@@ -2612,7 +2613,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" + std::string(param.name)));
}
TEST_P(ResolverBuiltinTest_DataPacking, Error_NoParams) {
@@ -2623,7 +2624,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" + std::string(param.name)));
}
TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
@@ -2638,7 +2639,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" + std::string(param.name)));
}
INSTANTIATE_TEST_SUITE_P(
@@ -2709,7 +2710,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to '" + std::string(param.name)));
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/src/tint/lang/wgsl/resolver/builtin_validation_test.cc b/src/tint/lang/wgsl/resolver/builtin_validation_test.cc
index 9dcab3d..0c063d8 100644
--- a/src/tint/lang/wgsl/resolver/builtin_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_validation_test.cc
@@ -164,14 +164,14 @@
WrapInFunction(Call(Source{{56, 78}}, "mix", 1_f, 2_f, 3_f));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(56:78 error: no matching constructor for i32(f32, f32, f32)
+ EXPECT_EQ(r()->error(), R"(56:78 error: no matching constructor for 'i32(f32, f32, f32)'
2 candidate constructors:
- i32(i32) -> i32
- i32() -> i32
+ 'i32(i32) -> i32'
+ 'i32() -> i32'
1 candidate conversion:
- i32(T) -> i32 where: T is abstract-int, abstract-float, f32, f16, u32 or bool
+ 'i32(T) -> i32' where: 'T' is 'abstract-int', 'abstract-float', 'f32', 'f16', 'u32' or 'bool'
)");
}
@@ -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");
}
@@ -778,10 +778,10 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(error: no matching call to workgroupUniformLoad(ptr<storage, i32, read_write>)
+ R"(error: no matching call to 'workgroupUniformLoad(ptr<storage, i32, read_write>)'
1 candidate function:
- workgroupUniformLoad(ptr<workgroup, T, read_write>) -> T
+ 'workgroupUniformLoad(ptr<workgroup, T, read_write>) -> T'
)");
}
@@ -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 25121ae..001fb4e 100644
--- a/src/tint/lang/wgsl/resolver/call_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/call_validation_test.cc
@@ -143,7 +143,7 @@
});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of let 'z'");
+ EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of 'let z'");
}
TEST_F(ResolverCallValidationTest,
@@ -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)");
}
@@ -519,11 +519,11 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: no matching call to min<i32>(abstract-int, abstract-int)
+ R"(12:34 error: no matching call to 'min<i32>(abstract-int, abstract-int)'
2 candidate functions:
- min(T, T) -> T where: T is abstract-float, abstract-int, f32, i32, u32 or f16
- min(vecN<T>, vecN<T>) -> vecN<T> where: T is abstract-float, abstract-int, f32, i32, u32 or f16
+ 'min(T, T) -> T' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
+ 'min(vecN<T>, vecN<T>) -> vecN<T>' where: 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16'
)");
}
diff --git a/src/tint/lang/wgsl/resolver/compound_assignment_validation_test.cc b/src/tint/lang/wgsl/resolver/compound_assignment_validation_test.cc
index 578cd22..132ef50 100644
--- a/src/tint/lang/wgsl/resolver/compound_assignment_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/compound_assignment_validation_test.cc
@@ -86,7 +86,7 @@
ASSERT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching overload for operator += (i32, f32)"));
+ HasSubstr("12:34 error: no matching overload for 'operator += (i32, f32)'"));
}
TEST_F(ResolverCompoundAssignmentValidationTest, IncompatibleOp) {
@@ -103,7 +103,7 @@
ASSERT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching overload for operator |= (f32, f32)"));
+ HasSubstr("12:34 error: no matching overload for 'operator |= (f32, f32)'"));
}
TEST_F(ResolverCompoundAssignmentValidationTest, VectorScalar_Pass) {
@@ -198,7 +198,7 @@
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching overload for operator *= (vec4<f32>, mat4x2<f32>)"));
+ HasSubstr("12:34 error: no matching overload for 'operator *= (vec4<f32>, mat4x2<f32>)'"));
}
TEST_F(ResolverCompoundAssignmentValidationTest, VectorMatrix_ResultMismatch) {
@@ -242,7 +242,7 @@
WrapInFunction(CompoundAssign(Source{{56, 78}}, Phony(), 1_i, core::BinaryOp::kAdd));
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("56:78 error: no matching overload for operator += (void, i32)"));
+ HasSubstr("56:78 error: no matching overload for 'operator += (void, i32)'"));
}
TEST_F(ResolverCompoundAssignmentValidationTest, ReadOnlyBuffer) {
@@ -266,9 +266,9 @@
WrapInFunction(a, CompoundAssign(Expr(Source{{56, 78}}, "a"), 1_i, core::BinaryOp::kAdd));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to let 'a'
+ EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to 'let a'
56:78 note: 'let' variables are immutable
-12:34 note: let 'a' declared here)");
+12:34 note: 'let a' declared here)");
}
TEST_F(ResolverCompoundAssignmentValidationTest, LhsLiteral) {
@@ -288,7 +288,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("error: no matching overload for operator += (atomic<i32>, atomic<i32>)"));
+ HasSubstr("error: no matching overload for 'operator += (atomic<i32>, atomic<i32>)'"));
}
} // namespace
diff --git a/src/tint/lang/wgsl/resolver/control_block_validation_test.cc b/src/tint/lang/wgsl/resolver/control_block_validation_test.cc
index a5eb482..9f38183 100644
--- a/src/tint/lang/wgsl/resolver/control_block_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/control_block_validation_test.cc
@@ -360,8 +360,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "56:78 error: duplicate switch case '2'\n"
- "12:34 note: previous case declared here");
+ R"(56:78 error: duplicate switch case '2'
+12:34 note: previous case declared here)");
}
TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorValueSint_Fail) {
@@ -387,8 +387,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "56:78 error: duplicate switch case '-10'\n"
- "12:34 note: previous case declared here");
+ R"(56:78 error: duplicate switch case '-10'
+12:34 note: previous case declared here)");
}
TEST_F(ResolverControlBlockValidationTest, SwitchCase_Pass) {
@@ -511,8 +511,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "56:78 error: duplicate switch case '10'\n"
- "12:34 note: previous case declared here");
+ R"(56:78 error: duplicate switch case '10'
+12:34 note: previous case declared here)");
}
TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorSameCase_BothExpression_Fail) {
@@ -532,8 +532,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: duplicate switch case '10'\n"
- "56:78 note: previous case declared here");
+ R"(12:34 error: duplicate switch case '10'
+56:78 note: previous case declared here)");
}
TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorSame_Case_Expression_Fail) {
@@ -553,8 +553,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: duplicate switch case '10'\n"
- "56:78 note: previous case declared here");
+ R"(12:34 error: duplicate switch case '10'
+56:78 note: previous case declared here)");
}
TEST_F(ResolverControlBlockValidationTest, Switch_OverrideCondition_Fail) {
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index 27f11ae..7e2db61 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -131,14 +131,14 @@
/// A map of global name to Global
using GlobalMap = Hashmap<Symbol, Global*, 16>;
-/// Raises an error diagnostic with the given message and source.
-void AddError(diag::List& diagnostics, const std::string& msg, const Source& source) {
- diagnostics.AddError(diag::System::Resolver, msg, source);
+/// @returns a new error diagnostic with the given source.
+diag::Diagnostic& AddError(diag::List& diagnostics, const Source& source) {
+ return diagnostics.AddError(diag::System::Resolver, source);
}
-/// Raises a note diagnostic with the given message and source.
-void AddNote(diag::List& diagnostics, const std::string& msg, const Source& source) {
- diagnostics.AddNote(diag::System::Resolver, msg, source);
+/// @returns a new note diagnostic with the given source.
+diag::Diagnostic& AddNote(diag::List& diagnostics, const Source& source) {
+ return diagnostics.AddNote(diag::System::Resolver, source);
}
/// DependencyScanner is used to traverse a module to build the list of
@@ -335,8 +335,8 @@
auto* old = scope_stack_.Set(symbol, node);
if (old != nullptr && node != old) {
auto name = symbol.Name();
- AddError(diagnostics_, "redeclaration of '" + name + "'", node->source);
- AddNote(diagnostics_, "'" + name + "' previously declared here", old->source);
+ AddError(diagnostics_, node->source) << "redeclaration of '" << name << "'";
+ AddNote(diagnostics_, old->source) << "'" << name << "' previously declared here";
}
}
@@ -355,7 +355,7 @@
return ast::TraverseAction::Descend;
});
if (!ok) {
- AddError(diagnostics_, "TraverseExpressions failed", next->source);
+ AddError(diagnostics_, next->source) << "TraverseExpressions failed";
return;
}
}
@@ -768,8 +768,8 @@
/// found in `stack`.
/// @param stack is the global dependency stack that contains a loop.
void CyclicDependencyFound(const Global* root, VectorRef<const Global*> stack) {
- StringStream msg;
- msg << "cyclic dependency found: ";
+ auto& err = AddError(diagnostics_, root->node->source);
+ err << "cyclic dependency found: ";
constexpr size_t kLoopNotStarted = ~0u;
size_t loop_start = kLoopNotStarted;
for (size_t i = 0; i < stack.Length(); i++) {
@@ -778,19 +778,18 @@
loop_start = i;
}
if (loop_start != kLoopNotStarted) {
- msg << "'" << NameOf(e->node) << "' -> ";
+ err << "'" << NameOf(e->node) << "' -> ";
}
}
- msg << "'" << NameOf(root->node) << "'";
- AddError(diagnostics_, msg.str(), root->node->source);
+ err << "'" << NameOf(root->node) << "'";
+
for (size_t i = loop_start; i < stack.Length(); i++) {
auto* from = stack[i];
auto* to = (i + 1 < stack.Length()) ? stack[i + 1] : stack[loop_start];
auto info = DepInfoFor(from, to);
- AddNote(diagnostics_,
- KindOf(from->node) + " '" + NameOf(from->node) + "' references " +
- KindOf(to->node) + " '" + NameOf(to->node) + "' here",
- info.source);
+ AddNote(diagnostics_, info.source)
+ << KindOf(from->node) + " '" << NameOf(from->node) << "' references "
+ << KindOf(to->node) << " '" << NameOf(to->node) << "' 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/expression_kind_test.cc b/src/tint/lang/wgsl/resolver/expression_kind_test.cc
index 94c91c8..1334b8b 100644
--- a/src/tint/lang/wgsl/resolver/expression_kind_test.cc
+++ b/src/tint/lang/wgsl/resolver/expression_kind_test.cc
@@ -622,34 +622,34 @@
{Def::kParameter, Use::kUnaryOp, kPass},
{Def::kStruct, Use::kAccess, R"(5:6 error: cannot use type 'STRUCT' as access
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: 'struct STRUCT' declared here)"},
{Def::kStruct, Use::kAddressSpace,
R"(5:6 error: cannot use type 'STRUCT' as address space
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: 'struct STRUCT' declared here)"},
{Def::kStruct, Use::kBinaryOp, R"(5:6 error: cannot use type 'STRUCT' as value
-1:2 note: struct 'STRUCT' declared here
+1:2 note: 'struct STRUCT' declared here
7:8 note: are you missing '()'?)"},
{Def::kStruct, Use::kBuiltinValue,
R"(5:6 error: cannot use type 'STRUCT' as builtin value
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: 'struct STRUCT' declared here)"},
{Def::kStruct, Use::kFunctionReturnType, kPass},
{Def::kStruct, Use::kInterpolationSampling,
R"(5:6 error: cannot use type 'STRUCT' as interpolation sampling
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: 'struct STRUCT' declared here)"},
{Def::kStruct, Use::kInterpolationType,
R"(5:6 error: cannot use type 'STRUCT' as interpolation type
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: 'struct STRUCT' declared here)"},
{Def::kStruct, Use::kMemberType, kPass},
{Def::kStruct, Use::kTexelFormat, R"(5:6 error: cannot use type 'STRUCT' as texel format
-1:2 note: struct 'STRUCT' declared here)"},
+1:2 note: 'struct STRUCT' declared here)"},
{Def::kStruct, Use::kValueExpression,
R"(5:6 error: cannot use type 'STRUCT' as value
-1:2 note: struct 'STRUCT' declared here
+1:2 note: 'struct STRUCT' declared here
7:8 note: are you missing '()'?)"},
{Def::kStruct, Use::kVariableType, kPass},
{Def::kStruct, Use::kUnaryOp,
R"(5:6 error: cannot use type 'STRUCT' as value
-1:2 note: struct 'STRUCT' declared here
+1:2 note: 'struct STRUCT' declared here
7:8 note: are you missing '()'?)"},
{Def::kTexelFormat, Use::kAccess,
@@ -704,40 +704,40 @@
R"(5:6 error: cannot use type 'i32' as value
7:8 note: are you missing '()'?)"},
- {Def::kVariable, Use::kAccess, R"(5:6 error: cannot use const 'VARIABLE' as access
-1:2 note: const 'VARIABLE' declared here)"},
+ {Def::kVariable, Use::kAccess, R"(5:6 error: cannot use 'const VARIABLE' as access
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kAddressSpace,
- R"(5:6 error: cannot use const 'VARIABLE' as address space
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as address space
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kBinaryOp, kPass},
{Def::kVariable, Use::kBuiltinValue,
- R"(5:6 error: cannot use const 'VARIABLE' as builtin value
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as builtin value
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kCallStmt,
- R"(5:6 error: cannot use const 'VARIABLE' as call target
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as call target
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kCallExpr,
- R"(5:6 error: cannot use const 'VARIABLE' as call target
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as call target
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kFunctionReturnType,
- R"(5:6 error: cannot use const 'VARIABLE' as type
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as type
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kInterpolationSampling,
- R"(5:6 error: cannot use const 'VARIABLE' as interpolation sampling
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as interpolation sampling
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kInterpolationType,
- R"(5:6 error: cannot use const 'VARIABLE' as interpolation type
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as interpolation type
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kMemberType,
- R"(5:6 error: cannot use const 'VARIABLE' as type
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as type
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kTexelFormat,
- R"(5:6 error: cannot use const 'VARIABLE' as texel format
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as texel format
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kValueExpression, kPass},
{Def::kVariable, Use::kVariableType,
- R"(5:6 error: cannot use const 'VARIABLE' as type
-1:2 note: const 'VARIABLE' declared here)"},
+ R"(5:6 error: cannot use 'const VARIABLE' as type
+1:2 note: 'const VARIABLE' declared here)"},
{Def::kVariable, Use::kUnaryOp, kPass},
}));
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/materialize_test.cc b/src/tint/lang/wgsl/resolver/materialize_test.cc
index 19eff8c..d156bda 100644
--- a/src/tint/lang/wgsl/resolver/materialize_test.cc
+++ b/src/tint/lang/wgsl/resolver/materialize_test.cc
@@ -440,16 +440,16 @@
std::string expect;
switch (method) {
case Method::kBuiltinArg:
- expect = "error: no matching call to min(" + data.target_type_name + ", " +
- data.abstract_type_name + ")";
+ expect = "error: no matching call to 'min(" + data.target_type_name + ", " +
+ data.abstract_type_name + ")'";
break;
case Method::kBinaryOp:
- expect = "error: no matching overload for operator + (" +
- data.target_type_name + ", " + data.abstract_type_name + ")";
+ expect = "error: no matching overload for 'operator + (" +
+ data.target_type_name + ", " + data.abstract_type_name + ")'";
break;
case Method::kCompoundAssign:
- expect = "error: no matching overload for operator += (" +
- data.target_type_name + ", " + data.abstract_type_name + ")";
+ expect = "error: no matching overload for 'operator += (" +
+ data.target_type_name + ", " + data.abstract_type_name + ")'";
break;
default:
expect = "error: cannot convert value of type '" + data.abstract_type_name +
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 1895890..e7b05da 100644
--- a/src/tint/lang/wgsl/resolver/ptr_ref_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/ptr_ref_validation_test.cc
@@ -61,7 +61,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: cannot take the address of let 'l')");
+ EXPECT_EQ(r()->error(), R"(12:34 error: cannot take the address of 'let l')");
}
TEST_F(ResolverPtrRefValidationTest, AddressOfConst) {
@@ -74,7 +74,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: cannot take the address of const 'c')");
+ EXPECT_EQ(r()->error(), R"(12:34 error: cannot take the address of 'const c')");
}
TEST_F(ResolverPtrRefValidationTest, AddressOfOverride) {
@@ -87,7 +87,7 @@
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: cannot take the address of override 'o')");
+ EXPECT_EQ(r()->error(), R"(12:34 error: cannot take the address of 'override o')");
}
TEST_F(ResolverPtrRefValidationTest, AddressOfParameter) {
@@ -112,7 +112,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: cannot take the address of var 't' in handle address space)");
+ R"(12:34 error: cannot take the address of 'var t' in handle address space)");
}
TEST_F(ResolverPtrRefValidationTest, AddressOfFunction) {
@@ -255,7 +255,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: cannot take the address of var 't' in handle address space)");
+ R"(12:34 error: cannot take the address of 'var t' in handle address space)");
}
TEST_F(ResolverPtrRefValidationTest, DerefOfLiteral) {
@@ -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 2bf95e9..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("'let' declaration must have an initializer", v->source);
+ 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("while instantiating 'let' " + v->name->symbol.Name(), v->source);
+ AddNote(v->source) << "while instantiating " << style::Keyword << "let " << style::Variable
+ << v->name->symbol.Name();
return nullptr;
}
@@ -346,7 +351,7 @@
ty = init->Type();
}
} else if (!ty) {
- AddError("override declaration requires a type or initializer", v->source);
+ AddError(v->source) << "override declaration requires a type or initializer";
return nullptr;
}
sem->SetType(ty);
@@ -357,7 +362,8 @@
if (!ApplyAddressSpaceUsageToType(core::AddressSpace::kUndefined,
const_cast<core::type::Type*>(ty), v->source)) {
- AddNote("while instantiating 'override' " + v->name->symbol.Name(), v->source);
+ AddNote(v->source) << "while instantiating " << style::Keyword << "override "
+ << style::Variable << v->name->symbol.Name();
return nullptr;
}
@@ -374,21 +380,25 @@
return false;
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@id must be an i32 or u32 value", attr->source);
+ 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("@id value must be non-negative", attr->source);
+ 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(
- "@id value must be between 0 and " +
- std::to_string(std::numeric_limits<decltype(OverrideId::value)>::max()),
- attr->source);
+ AddError(attr->source)
+ << style::Attribute << "@id" << style::Plain
+ << " value must be between 0 and "
+ << std::numeric_limits<decltype(OverrideId::value)>::max();
return false;
}
@@ -400,7 +410,8 @@
return true;
},
[&](Default) {
- ErrorInvalidAttribute(attribute, "'override' declaration");
+ ErrorInvalidAttribute(attribute, StyledText{} << style::Keyword << "override"
+ << style::Plain << " declaration");
return false;
});
if (!ok) {
@@ -426,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) {
@@ -435,7 +448,7 @@
}
if (TINT_UNLIKELY(!c->initializer)) {
- AddError("'const' declaration must have an initializer", c->source);
+ AddError(c->source) << "'const' declaration must have an initializer";
return nullptr;
}
@@ -480,7 +493,7 @@
if (!ApplyAddressSpaceUsageToType(core::AddressSpace::kUndefined,
const_cast<core::type::Type*>(ty), c->source)) {
- AddNote("while instantiating 'const' " + c->name->symbol.Name(), c->source);
+ AddNote(c->source) << "while instantiating 'const' " << c->name->symbol.Name();
return nullptr;
}
@@ -542,7 +555,7 @@
}
if (!storage_ty) {
- AddError("var declaration requires a type or initializer", var->source);
+ AddError(var->source) << "var declaration requires a type or initializer";
return nullptr;
}
@@ -568,7 +581,8 @@
if (!is_global && sem->AddressSpace() != core::AddressSpace::kFunction &&
validator_.IsValidationEnabled(var->attributes,
ast::DisabledValidation::kIgnoreAddressSpace)) {
- AddError("function-scope 'var' declaration must use 'function' address space", var->source);
+ AddError(var->source)
+ << "function-scope 'var' declaration must use 'function' address space";
return nullptr;
}
@@ -592,7 +606,7 @@
if (!ApplyAddressSpaceUsageToType(sem->AddressSpace(),
const_cast<core::type::Type*>(sem->Type()),
var->type ? var->type->source : var->source)) {
- AddNote("while instantiating 'var' " + var->name->symbol.Name(), var->source);
+ AddNote(var->source) << "while instantiating 'var' " << var->name->symbol.Name();
return nullptr;
}
@@ -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) {
@@ -721,7 +737,7 @@
b.Sem().Add(param, sem);
auto add_note = [&] {
- AddNote("while instantiating parameter " + param->name->symbol.Name(), param->source);
+ AddNote(param->source) << "while instantiating parameter " << param->name->symbol.Name();
};
if (func->IsEntryPoint()) {
@@ -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;
});
@@ -895,9 +912,8 @@
increment_next_id();
}
if (ids_exhausted) {
- AddError(
- "number of 'override' variables exceeded limit of " + std::to_string(kLimit),
- decl->source);
+ AddError(decl->source)
+ << "number of 'override' variables exceeded limit of " << kLimit;
return false;
}
id = next_id;
@@ -952,12 +968,12 @@
}
auto* cond = expr->ConstantValue();
if (auto* ty = cond->Type(); !ty->Is<core::type::Bool>()) {
- AddError("const assertion condition must be a bool, got '" + ty->FriendlyName() + "'",
- assertion->condition->source);
+ AddError(assertion->condition->source)
+ << "const assertion condition must be a bool, got '" << ty->FriendlyName() << "'";
return nullptr;
}
if (!cond->ValueAs<bool>()) {
- AddError("const assertion failed", assertion->source);
+ AddError(assertion->source) << "const assertion failed";
return nullptr;
}
auto* sem = b.create<sem::Statement>(assertion, current_compound_statement_, current_function_);
@@ -997,7 +1013,7 @@
},
[&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
[&](Default) {
- ErrorInvalidAttribute(attribute, "functions");
+ ErrorInvalidAttribute(attribute, StyledText{} << "functions");
return false;
});
if (!ok) {
@@ -1017,8 +1033,8 @@
{ // Check the parameter name is unique for the function
if (auto added = parameter_names.Add(param->name->symbol, param->source); !added) {
auto name = param->name->symbol.Name();
- AddError("redefinition of parameter '" + name + "'", param->source);
- AddNote("previous definition is here", added.value);
+ AddError(param->source) << "redefinition of parameter '" << name << "'";
+ AddNote(added.value) << "previous definition is here";
return nullptr;
}
}
@@ -1119,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;
}
@@ -1140,8 +1157,8 @@
if (auto* str = return_type->As<core::type::Struct>()) {
if (!ApplyAddressSpaceUsageToType(core::AddressSpace::kUndefined, str, decl->source)) {
- AddNote("while instantiating return type for " + decl->name->symbol.Name(),
- decl->source);
+ AddNote(decl->source) << "while instantiating return type for "
+ << decl->name->symbol.Name();
return nullptr;
}
@@ -1169,9 +1186,8 @@
if (decl->body) {
Mark(decl->body);
if (TINT_UNLIKELY(current_compound_statement_)) {
- StringStream err;
- err << "Resolver::Function() called with a current compound statement";
- AddICE(err.str(), decl->body->source);
+ AddICE("Resolver::Function() called with a current compound statement",
+ decl->body->source);
return nullptr;
}
auto* body = StatementScope(decl->body, b.create<sem::FunctionBlockStatement>(func),
@@ -1265,11 +1281,12 @@
// Error cases
[&](const ast::CaseStatement*) {
- AddError("case statement can only be used inside a switch statement", stmt->source);
+ AddError(stmt->source) << "case statement can only be used inside a switch statement";
return nullptr;
},
[&](Default) {
- AddError("unknown statement type: " + std::string(stmt->TypeInfo().name), stmt->source);
+ AddError(stmt->source)
+ << "unknown statement type: " << std::string(stmt->TypeInfo().name);
return nullptr;
});
}
@@ -1294,12 +1311,12 @@
return false;
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("case selector must be an i32 or u32 value", sel->source);
+ AddError(sel->source) << "case selector must be an i32 or u32 value";
return false;
}
const_value = materialized->ConstantValue();
if (!const_value) {
- AddError("case selector must be a constant expression", sel->source);
+ AddError(sel->source) << "case selector must be a constant expression";
return false;
}
}
@@ -1491,9 +1508,8 @@
if (!ast::TraverseExpressions<ast::TraverseOrder::RightToLeft>(
root, [&](const ast::Expression* expr, size_t depth) {
if (depth > kMaxExpressionDepth) {
- AddError(
- "reached max expression depth of " + std::to_string(kMaxExpressionDepth),
- expr->source);
+ AddError(expr->source)
+ << "reached max expression depth of " << kMaxExpressionDepth;
failed = true;
return ast::TraverseAction::Stop;
}
@@ -1509,7 +1525,7 @@
sorted.Push(expr);
return ast::TraverseAction::Descend;
})) {
- AddError("TraverseExpressions failed", root->source);
+ AddError(root->source) << "TraverseExpressions failed";
return nullptr;
}
@@ -1569,7 +1585,7 @@
return ast::TraverseAction::Descend;
});
if (!r) {
- AddError("TraverseExpressions failed", root->source);
+ AddError(root->source) << "TraverseExpressions failed";
return nullptr;
}
}
@@ -1630,10 +1646,9 @@
if (TINT_UNLIKELY(
address_space_expr->Value() == core::AddressSpace::kPixelLocal &&
!enabled_extensions_.Contains(wgsl::Extension::kChromiumExperimentalPixelLocal))) {
- StringStream err;
- err << "'pixel_local' address space requires the '"
- << wgsl::Extension::kChromiumExperimentalPixelLocal << "' extension enabled";
- AddError(err.str(), expr->source);
+ AddError(expr->source) << "'pixel_local' address space requires the '"
+ << wgsl::Extension::kChromiumExperimentalPixelLocal
+ << "' extension enabled";
return nullptr;
}
return address_space_expr;
@@ -1702,18 +1717,18 @@
std::string access; // the access performed for the "other" expression
};
auto make_error = [&](const sem::ValueExpression* arg, Alias&& var) {
- AddError("invalid aliased pointer argument", arg->Declaration()->source);
+ AddError(arg->Declaration()->source) << "invalid aliased pointer argument";
switch (var.type) {
case Alias::Argument:
- AddNote("aliases with another argument passed here",
- var.expr->Declaration()->source);
+ AddNote(var.expr->Declaration()->source)
+ << "aliases with another argument passed here";
break;
case Alias::ModuleScope: {
auto* func = var.expr->Stmt()->Function();
auto func_name = func->Declaration()->name->symbol.Name();
- AddNote(
- "aliases with module-scope variable " + var.access + " in '" + func_name + "'",
- var.expr->Declaration()->source);
+ AddNote(var.expr->Declaration()->source)
+ << "aliases with module-scope variable " << var.access << " in '" << func_name
+ << "'";
break;
}
}
@@ -1987,10 +2002,9 @@
if (memory_view) {
if (memory_view->Is<core::type::Pointer>() &&
!allowed_features_.features.count(wgsl::LanguageFeature::kPointerCompositeAccess)) {
- AddError(
- "pointer composite access requires the pointer_composite_access language feature, "
- "which is not allowed in the current environment",
- expr->source);
+ AddError(expr->source)
+ << "pointer composite access requires the pointer_composite_access language "
+ "feature, which is not allowed in the current environment";
return nullptr;
}
storage_ty = memory_view->StoreType();
@@ -2004,7 +2018,7 @@
return b.create<core::type::Vector>(mat->type(), mat->rows());
},
[&](Default) {
- AddError("cannot index type '" + sem_.TypeNameOf(storage_ty) + "'", expr->source);
+ AddError(expr->source) << "cannot index type '" << sem_.TypeNameOf(storage_ty) << "'";
return nullptr;
});
if (ty == nullptr) {
@@ -2013,8 +2027,8 @@
auto* idx_ty = idx->Type()->UnwrapRef();
if (!idx_ty->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("index must be of type 'i32' or 'u32', found: '" + sem_.TypeNameOf(idx_ty) + "'",
- idx->Declaration()->source);
+ AddError(idx->Declaration()->source)
+ << "index must be of type 'i32' or 'u32', found: '" << sem_.TypeNameOf(idx_ty) << "'";
return nullptr;
}
@@ -2084,7 +2098,7 @@
auto arg_tys = tint::Transform(args, [](auto* arg) { return arg->Type()->UnwrapRef(); });
auto match = intrinsic_table_.Lookup(ty, template_args, arg_tys, args_stage);
if (match != Success) {
- AddError(match.Failure(), expr->source);
+ AddError(expr->source) << match.Failure();
return nullptr;
}
@@ -2243,7 +2257,7 @@
return arr_or_str_init(str, call_target);
},
[&](Default) {
- AddError("type is not constructible", expr->source);
+ AddError(expr->source) << "type is not constructible";
return nullptr;
});
};
@@ -2283,14 +2297,14 @@
tint::Transform(args, [](auto* arg) { return arg->Type()->UnwrapRef(); });
auto el_ty = core::type::Type::Common(arg_tys);
if (TINT_UNLIKELY(!el_ty)) {
- AddError("cannot infer common array element type from constructor arguments",
- expr->source);
+ AddError(expr->source)
+ << "cannot infer common array element type from constructor arguments";
Hashset<const core::type::Type*, 8> types;
for (size_t i = 0; i < args.Length(); i++) {
if (types.Add(args[i]->Type())) {
- AddNote("argument " + std::to_string(i) + " is of type '" +
- sem_.TypeNameOf(args[i]->Type()) + "'",
- args[i]->Declaration()->source);
+ AddNote(args[i]->Declaration()->source)
+ << "argument " << i << " is of type '"
+ << sem_.TypeNameOf(args[i]->Type()) << "'";
}
}
return nullptr;
@@ -2367,7 +2381,7 @@
auto arg_tys = tint::Transform(args, [](auto* arg) { return arg->Type()->UnwrapRef(); });
auto overload = intrinsic_table_.Lookup(fn, tmpl_args, arg_tys, arg_stage);
if (overload != Success) {
- AddError(overload.Failure(), expr->source);
+ AddError(expr->source) << overload.Failure();
return nullptr;
}
@@ -2406,7 +2420,7 @@
}
if (target->IsDeprecated()) {
- AddWarning("use of deprecated builtin", expr->source);
+ AddWarning(expr->source) << "use of deprecated builtin";
}
// If the builtin is @const, and all arguments have constant values, evaluate the builtin
@@ -2903,7 +2917,7 @@
}
if (!ApplyAddressSpaceUsageToType(address_space, store_ty, tmpl_ident->arguments[1]->source)) {
- AddNote("while instantiating " + out->FriendlyName(), ident->source);
+ AddNote(ident->source) << "while instantiating " << out->FriendlyName();
return nullptr;
}
return out;
@@ -2990,8 +3004,9 @@
auto* tmpl_ident = ident->As<ast::TemplatedIdentifier>();
if (!tmpl_ident) {
if (TINT_UNLIKELY(min_args != 0)) {
- AddError("expected '<' for '" + ident->symbol.Name() + "'",
- Source{ident->source.range.end});
+ AddError(Source{ident->source.range.end})
+ << "expected " << style::Code << "<" << style::Plain << " for " << style::Code
+ << ident->symbol.Name();
}
return nullptr;
}
@@ -3006,22 +3021,19 @@
}
if (min_args == max_args) {
if (TINT_UNLIKELY(ident->arguments.Length() != min_args)) {
- AddError("'" + ident->symbol.Name() + "' requires " + std::to_string(min_args) +
- " template arguments",
- ident->source);
+ 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->symbol.Name() + "' requires at least " +
- std::to_string(min_args) + " template arguments",
- ident->source);
+ 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->symbol.Name() + "' requires at most " + std::to_string(max_args) +
- " template arguments",
- ident->source);
+ AddError(ident->source) << style::Code << ident->symbol.Name() << style::Plain
+ << " requires at most " << max_args << " template arguments";
return false;
}
}
@@ -3047,9 +3059,7 @@
const auto& signature = builtin->Signature();
int texture_index = signature.IndexOf(core::ParameterUsage::kTexture);
if (TINT_UNLIKELY(texture_index == -1)) {
- StringStream err;
- err << "texture builtin without texture parameter";
- AddICE(err.str(), {});
+ AddICE("texture builtin without texture parameter", {});
return;
}
if (auto* user =
@@ -3287,14 +3297,14 @@
auto symbol = ident->symbol;
if (auto decl = loop_block->Decls().Get(symbol)) {
if (decl->order >= loop_block->NumDeclsAtFirstContinue()) {
- AddError("continue statement bypasses declaration of '" +
- symbol.Name() + "'",
- loop_block->FirstContinue()->source);
- AddNote("identifier '" + symbol.Name() + "' declared here",
- decl->variable->Declaration()->source);
- AddNote("identifier '" + symbol.Name() +
- "' referenced in continuing block here",
- expr->source);
+ AddError(loop_block->FirstContinue()->source)
+ << "continue statement bypasses declaration of '"
+ << symbol.Name() << "'";
+ AddNote(decl->variable->Declaration()->source)
+ << "identifier '" << symbol.Name() << "' declared here";
+ AddNote(expr->source)
+ << "identifier '" << symbol.Name()
+ << "' referenced in continuing block here";
return nullptr;
}
}
@@ -3308,9 +3318,10 @@
}
if (!current_function_ && variable->Declaration()->Is<ast::Var>()) {
// Use of a module-scope 'var' outside of a function.
- std::string desc = "var '" + ident->symbol.Name() + "' ";
- AddError(desc + "cannot be referenced at module-scope", expr->source);
- AddNote(desc + "declared here", variable->Declaration()->source);
+ AddError(expr->source)
+ << style::Keyword << "var " << style::Variable << ident->symbol.Name()
+ << style::Plain << " cannot be referenced at module-scope";
+ sem_.NoteDeclarationSource(variable->Declaration());
return nullptr;
}
}
@@ -3420,10 +3431,9 @@
if (memory_view) {
if (memory_view->Is<core::type::Pointer>() &&
!allowed_features_.features.count(wgsl::LanguageFeature::kPointerCompositeAccess)) {
- AddError(
- "pointer composite access requires the pointer_composite_access language feature, "
- "which is not allowed in the current environment",
- expr->source);
+ AddError(expr->source)
+ << "pointer composite access requires the pointer_composite_access language "
+ "feature, which is not allowed in the current environment";
return nullptr;
}
storage_ty = memory_view->StoreType();
@@ -3452,7 +3462,7 @@
}
if (member == nullptr) {
- AddError("struct member " + symbol.Name() + " not found", expr->source);
+ AddError(expr->source) << "struct member " << symbol.Name() << " not found";
return nullptr;
}
@@ -3497,20 +3507,20 @@
swizzle.Push(3u);
break;
default:
- AddError(
- "invalid vector swizzle character",
- expr->member->source.Begin() + static_cast<uint32_t>(swizzle.Length()));
+ AddError(expr->member->source.Begin() +
+ static_cast<uint32_t>(swizzle.Length()))
+ << "invalid vector swizzle character";
return nullptr;
}
if (swizzle.Back() >= vec->Width()) {
- AddError("invalid vector swizzle member", expr->member->source);
+ AddError(expr->member->source) << "invalid vector swizzle member";
return nullptr;
}
}
if (size < 1 || size > 4) {
- AddError("invalid vector swizzle size", expr->member->source);
+ AddError(expr->member->source) << "invalid vector swizzle size";
return nullptr;
}
@@ -3519,8 +3529,8 @@
auto is_xyzw = [](char c) { return c == 'x' || c == 'y' || c == 'z' || c == 'w'; };
if (!std::all_of(s.begin(), s.end(), is_rgba) &&
!std::all_of(s.begin(), s.end(), is_xyzw)) {
- AddError("invalid mixing of vector swizzle characters rgba with xyzw",
- expr->member->source);
+ AddError(expr->member->source)
+ << "invalid mixing of vector swizzle characters rgba with xyzw";
return nullptr;
}
@@ -3554,8 +3564,8 @@
},
[&](Default) {
- AddError("cannot index into expression of type '" + sem_.TypeNameOf(storage_ty) + "'",
- expr->object->source);
+ AddError(expr->object->source)
+ << "cannot index into expression of type '" << sem_.TypeNameOf(storage_ty) << "'";
return nullptr;
});
}
@@ -3581,7 +3591,7 @@
auto overload = intrinsic_table_.Lookup(expr->op, lhs->Type()->UnwrapRef(),
rhs->Type()->UnwrapRef(), stage, false);
if (overload != Success) {
- AddError(overload.Failure(), expr->source);
+ AddError(expr->source) << overload.Failure();
return nullptr;
}
@@ -3663,9 +3673,9 @@
case core::UnaryOp::kAddressOf:
if (auto* ref = expr_ty->As<core::type::Reference>()) {
if (ref->StoreType()->UnwrapRef()->is_handle()) {
- AddError("cannot take the address of " + sem_.Describe(expr) +
- " in handle address space",
- unary->expr->source);
+ AddError(unary->expr->source)
+ << "cannot take the address of " << sem_.Describe(expr)
+ << " in handle address space";
return nullptr;
}
@@ -3674,7 +3684,8 @@
if ((array && sem_.TypeOf(array->object)->UnwrapRef()->Is<core::type::Vector>()) ||
(member &&
sem_.TypeOf(member->object)->UnwrapRef()->Is<core::type::Vector>())) {
- AddError("cannot take the address of a vector component", unary->expr->source);
+ AddError(unary->expr->source)
+ << "cannot take the address of a vector component";
return nullptr;
}
@@ -3683,7 +3694,8 @@
root_ident = expr->RootIdentifier();
} else {
- AddError("cannot take the address of " + sem_.Describe(expr), unary->expr->source);
+ AddError(unary->expr->source)
+ << "cannot take the address of " << sem_.Describe(expr);
return nullptr;
}
break;
@@ -3694,8 +3706,8 @@
ptr->Access());
root_ident = expr->RootIdentifier();
} else {
- AddError("cannot dereference expression of type '" + sem_.TypeNameOf(expr_ty) + "'",
- unary->expr->source);
+ AddError(unary->expr->source) << "cannot dereference expression of type "
+ << style::Type << sem_.TypeNameOf(expr_ty);
return nullptr;
}
break;
@@ -3704,7 +3716,7 @@
stage = expr->Stage();
auto overload = intrinsic_table_.Lookup(unary->op, expr_ty->UnwrapRef(), stage);
if (overload != Success) {
- AddError(overload.Failure(), unary->source);
+ AddError(unary->source) << overload.Failure();
return nullptr;
}
ty = overload->return_type;
@@ -3755,14 +3767,17 @@
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@location must be an i32 or u32 value", attr->source);
+ 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("@location value must be non-negative", attr->source);
+ AddError(attr->source) << style::Attribute << "@location" << style::Plain
+ << " value must be non-negative";
return Failure{};
}
@@ -3779,14 +3794,17 @@
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@color must be an i32 or u32 value", attr->source);
+ 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("@color value must be non-negative", attr->source);
+ AddError(attr->source) << style::Attribute << "@color" << style::Plain
+ << " value must be non-negative";
return Failure{};
}
@@ -3802,14 +3820,17 @@
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@location must be an i32 or u32 value", attr->source);
+ 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("@blend_src value must be zero or one", attr->source);
+ AddError(attr->source) << style::Attribute << "@blend_src" << style::Plain
+ << " value must be zero or one";
return Failure{};
}
@@ -3825,14 +3846,17 @@
return Failure{};
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@binding must be an i32 or u32 value", attr->source);
+ 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("@binding value must be non-negative", attr->source);
+ AddError(attr->source) << style::Attribute << "@binding" << style::Plain
+ << " value must be non-negative";
return Failure{};
}
return static_cast<uint32_t>(value);
@@ -3847,14 +3871,17 @@
return Failure{};
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@group must be an i32 or u32 value", attr->source);
+ 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("@group value must be non-negative", attr->source);
+ AddError(attr->source) << style::Attribute << "@group" << style::Plain
+ << " value must be non-negative";
return Failure{};
}
return static_cast<uint32_t>(value);
@@ -3871,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
@@ -3888,13 +3919,13 @@
}
auto* ty = expr->Type();
if (!ty->IsAnyOf<core::type::I32, core::type::U32, core::type::AbstractInt>()) {
- AddError(kErrBadExpr, value->source);
+ err_bad_expr(value);
return Failure{};
}
if (expr->Stage() != core::EvaluationStage::kConstant &&
expr->Stage() != core::EvaluationStage::kOverride) {
- AddError(kErrBadExpr, value->source);
+ err_bad_expr(value);
return Failure{};
}
@@ -3904,8 +3935,9 @@
auto* common_ty = core::type::Type::Common(arg_tys);
if (!common_ty) {
- AddError("workgroup_size arguments must be of the same type, either i32 or u32",
- attr->source);
+ 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{};
}
@@ -3921,7 +3953,8 @@
}
if (auto* value = materialized->ConstantValue()) {
if (value->ValueAs<AInt>() < 1) {
- AddError("workgroup_size argument must be at least 1", values[i]->source);
+ AddError(values[i]->source) << style::Attribute << "@workgroup_size" << style::Plain
+ << " argument must be at least 1";
return Failure{};
}
ws[i] = value->ValueAs<u32>();
@@ -3934,7 +3967,7 @@
for (size_t i = 1; i < 3; i++) {
total_size *= static_cast<uint64_t>(ws[i].value_or(1));
if (total_size > 0xffffffff) {
- AddError("total workgroup grid size cannot exceed 0xffffffff", values[i]->source);
+ AddError(values[i]->source) << "total workgroup grid size cannot exceed 0xffffffff";
return Failure{};
}
}
@@ -4013,12 +4046,13 @@
if (rule != wgsl::ChromiumDiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity);
} else {
- StringStream ss;
- ss << "unrecognized diagnostic rule 'chromium." << name << "'\n";
+ auto& warning = AddWarning(control.rule_name->source)
+ << "unrecognized diagnostic rule " << style::Code << "chromium."
+ << name << style::Plain << "\n";
tint::SuggestAlternativeOptions opts;
opts.prefix = "chromium.";
- tint::SuggestAlternatives(name, wgsl::kChromiumDiagnosticRuleStrings, ss, opts);
- AddWarning(ss.str(), control.rule_name->source);
+ tint::SuggestAlternatives(name, wgsl::kChromiumDiagnosticRuleStrings,
+ warning.message, opts);
}
}
return true;
@@ -4028,10 +4062,10 @@
if (rule != wgsl::CoreDiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity);
} else {
- StringStream ss;
- ss << "unrecognized diagnostic rule '" << name << "'\n";
- tint::SuggestAlternatives(name, wgsl::kCoreDiagnosticRuleStrings, ss);
- AddWarning(ss.str(), control.rule_name->source);
+ auto& warning = AddWarning(control.rule_name->source)
+ << "unrecognized diagnostic rule " << style::Code << name << style::Plain
+ << "\n";
+ tint::SuggestAlternatives(name, wgsl::kCoreDiagnosticRuleStrings, warning.message);
}
return true;
}
@@ -4041,9 +4075,8 @@
Mark(ext);
enabled_extensions_.Add(ext->name);
if (!allowed_features_.extensions.count(ext->name)) {
- StringStream ss;
- ss << "extension '" << ext->name << "' is not allowed in the current environment";
- AddError(ss.str(), ext->source);
+ AddError(ext->source) << "extension " << style::Code << ext->name << style::Plain
+ << " is not allowed in the current environment";
return false;
}
}
@@ -4053,10 +4086,8 @@
bool Resolver::Requires(const ast::Requires* req) {
for (auto feature : req->features) {
if (!allowed_features_.features.count(feature)) {
- StringStream ss;
- ss << "language feature '" << wgsl::ToString(feature)
- << "' is not allowed in the current environment";
- AddError(ss.str(), req->source);
+ AddError(req->source) << "language feature " << style::Code << wgsl::ToString(feature)
+ << style::Plain << " is not allowed in the current environment";
return false;
}
}
@@ -4111,17 +4142,16 @@
case core::EvaluationStage::kConstant: {
auto* count_val = count_sem->ConstantValue();
if (auto* ty = count_val->Type(); !ty->is_integer_scalar()) {
- AddError(
- "array count must evaluate to a constant integer expression, but is type '" +
- ty->FriendlyName() + "'",
- count_expr->source);
+ AddError(count_expr->source)
+ << "array count must evaluate to a constant integer expression, but is type "
+ << style::Type << ty->FriendlyName();
return nullptr;
}
int64_t count = count_val->ValueAs<AInt>();
if (count < 1) {
- AddError("array count (" + std::to_string(count) + ") must be greater than 0",
- count_expr->source);
+ AddError(count_expr->source)
+ << "array count (" << count << ") must be greater than 0";
return nullptr;
}
@@ -4129,9 +4159,9 @@
}
default: {
- AddError(
- "array count must evaluate to a constant integer expression or override variable",
- count_expr->source);
+ AddError(count_expr->source)
+ << "array count must evaluate to a constant integer expression "
+ "or override variable";
return nullptr;
}
}
@@ -4162,7 +4192,8 @@
return true;
},
[&](Default) {
- ErrorInvalidAttribute(attribute, "array types");
+ ErrorInvalidAttribute(
+ attribute, StyledText{} << style::Type << "array" << style::Plain << " types");
return false;
});
if (!ok) {
@@ -4188,10 +4219,8 @@
if (auto const_count = el_count->As<core::type::ConstantArrayCount>()) {
size = const_count->value * stride;
if (size > std::numeric_limits<uint32_t>::max()) {
- StringStream msg;
- msg << "array byte size (0x" << std::hex << size
- << ") must not exceed 0xffffffff bytes";
- AddError(msg.str(), count_source);
+ AddError(count_source) << "array byte size (0x" << std::hex << size
+ << ") must not exceed 0xffffffff bytes";
return nullptr;
}
} else if (el_count->Is<core::type::RuntimeArrayCount>()) {
@@ -4205,9 +4234,8 @@
// https://gpuweb.github.io/gpuweb/wgsl/#limits
const size_t nest_depth = 1 + NestDepth(el_ty);
if (nest_depth > kMaxNestDepthOfCompositeType) {
- AddError("array has nesting depth of " + std::to_string(nest_depth) + ", maximum is " +
- std::to_string(kMaxNestDepthOfCompositeType),
- array_source);
+ AddError(array_source) << "array has nesting depth of " << nest_depth << ", maximum is "
+ << kMaxNestDepthOfCompositeType;
return nullptr;
}
nest_depth_.Add(out, nest_depth);
@@ -4241,9 +4269,9 @@
// https://gpuweb.github.io/gpuweb/wgsl/#limits
const size_t kMaxNumStructMembers = 16383;
if (str->members.Length() > kMaxNumStructMembers) {
- AddError("struct '" + struct_name() + "' has " + std::to_string(str->members.Length()) +
- " members, maximum is " + std::to_string(kMaxNumStructMembers),
- str->source);
+ AddError(str->source) << style::Keyword << "struct " << style::Type << struct_name()
+ << style::Plain << " has " << str->members.Length()
+ << " members, maximum is " << kMaxNumStructMembers;
return nullptr;
}
}
@@ -4257,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) {
@@ -4283,8 +4312,9 @@
Mark(member);
Mark(member->name);
if (auto added = member_map.Add(member->name->symbol, member); !added) {
- AddError("redefinition of '" + member->name->symbol.Name() + "'", member->source);
- AddNote("previous definition is here", added.value->source);
+ AddError(member->source)
+ << "redefinition of " << style::Code << member->name->symbol.Name();
+ AddNote(added.value->source) << "previous definition is here";
return nullptr;
}
@@ -4298,8 +4328,8 @@
// validator_.Validate member type
if (!validator_.IsPlain(type)) {
- AddError(sem_.TypeNameOf(type) + " cannot be used as the type of a structure member",
- member->source);
+ AddError(member->source)
+ << sem_.TypeNameOf(type) << " cannot be used as the type of a structure member";
return nullptr;
}
@@ -4333,13 +4363,13 @@
}
auto const_value = materialized->ConstantValue();
if (!const_value) {
- AddError("@offset must be constant expression", attr->expr->source);
+ AddError(attr->expr->source) << "@offset must be constant expression";
return false;
}
offset = const_value->ValueAs<uint64_t>();
if (offset < struct_size) {
- AddError("offsets must be in ascending order", attr->source);
+ AddError(attr->source) << "offsets must be in ascending order";
return false;
}
has_offset_attr = true;
@@ -4354,20 +4384,23 @@
return false;
}
if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
- AddError("@align must be an i32 or u32 value", attr->source);
+ 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("@align must be constant expression", attr->source);
+ 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("@align value must be a positive, power-of-two integer",
- attr->source);
+ AddError(attr->source) << style::Attribute << "@align" << style::Plain
+ << " value must be a positive, power-of-two integer";
return false;
}
align = u32(value);
@@ -4383,27 +4416,31 @@
return false;
}
if (!materialized->Type()->IsAnyOf<core::type::U32, core::type::I32>()) {
- AddError("@size must be an i32 or u32 value", attr->source);
+ 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("@size must be constant expression", attr->expr->source);
+ 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("@size must be a positive integer", attr->source);
+ 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("@size must be at least as big as the type's size (" +
- std::to_string(size) + ")",
- attr->source);
+ AddError(attr->source)
+ << style::Attribute << "@size" << style::Plain
+ << " must be at least as big as the type's size (" << size << ")";
return false;
}
size = u32(value);
@@ -4460,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) {
@@ -4476,16 +4516,17 @@
}
if (has_offset_attr && (has_align_attr || has_size_attr)) {
- AddError("@offset cannot be used with @align or @size", member->source);
+ AddError(member->source) << style::Attribute << "@offset" << style::Plain
+ << " cannot be used with " << style::Attribute << "@align"
+ << style::Plain << " or " << style::Attribute << "@size";
return nullptr;
}
offset = tint::RoundUp(align, offset);
if (offset > std::numeric_limits<uint32_t>::max()) {
- StringStream msg;
- msg << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x"
+ AddError(member->source)
+ << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x"
<< std::hex << std::numeric_limits<uint32_t>::max() << " bytes";
- AddError(msg.str(), member->source);
return nullptr;
}
@@ -4504,9 +4545,8 @@
struct_size = tint::RoundUp(struct_align, struct_size);
if (struct_size > std::numeric_limits<uint32_t>::max()) {
- StringStream msg;
- msg << "struct size (0x" << std::hex << struct_size << ") must not exceed 0xffffffff bytes";
- AddError(msg.str(), str->source);
+ AddError(str->source) << "struct size (0x" << std::hex << struct_size
+ << ") must not exceed 0xffffffff bytes";
return nullptr;
}
if (TINT_UNLIKELY(struct_align > std::numeric_limits<uint32_t>::max())) {
@@ -4543,10 +4583,9 @@
// https://gpuweb.github.io/gpuweb/wgsl/#limits
const size_t nest_depth = 1 + members_nest_depth;
if (nest_depth > kMaxNestDepthOfCompositeType) {
- AddError("struct '" + struct_name() + "' has nesting depth of " +
- std::to_string(nest_depth) + ", maximum is " +
- std::to_string(kMaxNestDepthOfCompositeType),
- str->source);
+ 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);
@@ -4634,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) {
@@ -4789,7 +4829,7 @@
auto overload = intrinsic_table_.Lookup(stmt->op, lhs->Type()->UnwrapRef(),
rhs->Type()->UnwrapRef(), stage, true);
if (overload != Success) {
- AddError(overload.Failure(), stmt->source);
+ AddError(stmt->source) << overload.Failure();
return false;
}
@@ -4861,10 +4901,9 @@
if (decl && !ApplyAddressSpaceUsageToType(address_space,
const_cast<core::type::Type*>(member->Type()),
decl->type->source)) {
- StringStream err;
- err << "while analyzing structure member " << sem_.TypeNameOf(str) << "."
+ AddNote(member->Declaration()->source)
+ << "while analyzing structure member " << sem_.TypeNameOf(str) << "."
<< member->Name().Name();
- AddNote(err.str(), member->Declaration()->source);
return false;
}
}
@@ -4874,16 +4913,15 @@
if (auto* arr = ty->As<sem::Array>()) {
if (address_space != core::AddressSpace::kStorage) {
if (arr->Count()->Is<core::type::RuntimeArrayCount>()) {
- AddError("runtime-sized arrays can only be used in the <storage> address space",
- usage);
+ AddError(usage)
+ << "runtime-sized arrays can only be used in the <storage> address space";
return false;
}
auto count = arr->ConstantCount();
if (count.has_value() && count.value() >= kMaxArrayElementCount) {
- AddError("array count (" + std::to_string(count.value()) + ") must be less than " +
- std::to_string(kMaxArrayElementCount),
- usage);
+ AddError(usage) << "array count (" << count.value() << ") must be less than "
+ << kMaxArrayElementCount;
return false;
}
}
@@ -4892,10 +4930,9 @@
}
if (core::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
- StringStream err;
- err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '"
- << address_space << "' as it is non-host-shareable";
- AddError(err.str(), usage);
+ 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;
}
@@ -4917,7 +4954,7 @@
attribute, //
[&](const ast::DiagnosticAttribute* attr) { return DiagnosticAttribute(attr); },
[&](Default) {
- ErrorInvalidAttribute(attribute, use);
+ ErrorInvalidAttribute(attribute, StyledText{} << use);
return false;
});
if (!ok) {
@@ -4964,9 +5001,8 @@
TINT_SCOPED_ASSIGNMENT(current_scoping_depth_, current_scoping_depth_ + 1);
if (current_scoping_depth_ > kMaxStatementDepth) {
- AddError("statement nesting depth / chaining length exceeds limit of " +
- std::to_string(kMaxStatementDepth),
- ast->source);
+ AddError(ast->source) << "statement nesting depth / chaining length exceeds limit of "
+ << kMaxStatementDepth;
return nullptr;
}
@@ -5004,9 +5040,8 @@
bool Resolver::CheckNotTemplated(const char* use, const ast::Identifier* ident) {
if (TINT_UNLIKELY(ident->Is<ast::TemplatedIdentifier>())) {
- AddError(
- std::string(use) + " '" + ident->symbol.Name() + "' does not take template arguments",
- ident->source);
+ 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);
@@ -5017,11 +5052,12 @@
return true;
}
-void Resolver::ErrorInvalidAttribute(const ast::Attribute* attr, std::string_view use) {
- AddError("@" + attr->Name() + " is not valid for " + std::string(use), attr->source);
+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(const std::string& msg, const Source& source) const {
+void Resolver::AddICE(std::string_view msg, const Source& source) const {
if (source.file) {
TINT_ICE() << source << ": " << msg;
} else {
@@ -5031,20 +5067,19 @@
err.severity = diag::Severity::InternalCompilerError;
err.system = diag::System::Resolver;
err.source = source;
- err.message = msg;
- diagnostics_.Add(std::move(err));
+ diagnostics_.Add(std::move(err)) << msg;
}
-void Resolver::AddError(const std::string& msg, const Source& source) const {
- diagnostics_.AddError(diag::System::Resolver, msg, source);
+diag::Diagnostic& Resolver::AddError(const Source& source) const {
+ return diagnostics_.AddError(diag::System::Resolver, source);
}
-void Resolver::AddWarning(const std::string& msg, const Source& source) const {
- diagnostics_.AddWarning(diag::System::Resolver, msg, source);
+diag::Diagnostic& Resolver::AddWarning(const Source& source) const {
+ return diagnostics_.AddWarning(diag::System::Resolver, source);
}
-void Resolver::AddNote(const std::string& msg, const Source& source) const {
- diagnostics_.AddNote(diag::System::Resolver, msg, source);
+diag::Diagnostic& Resolver::AddNote(const Source& source) const {
+ return diagnostics_.AddNote(diag::System::Resolver, source);
}
} // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 5cf2e60..5dcab43 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -51,6 +51,7 @@
#include "src/tint/lang/wgsl/sem/struct.h"
#include "src/tint/utils/containers/bitset.h"
#include "src/tint/utils/containers/unique_vector.h"
+#include "src/tint/utils/text/styled_text.h"
// Forward declarations
namespace tint::ast {
@@ -635,19 +636,19 @@
/// 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(const std::string& msg, const Source& source) const;
+ void AddICE(std::string_view msg, const Source& source) const;
- /// Adds the given error message to the diagnostics
- void AddError(const std::string& msg, const Source& source) const;
+ /// @returns a new error message added to the program's diagnostics
+ diag::Diagnostic& AddError(const Source& source) const;
- /// Adds the given warning message to the diagnostics
- void AddWarning(const std::string& msg, const Source& source) const;
+ /// @returns a new warning message added to the program's diagnostics
+ diag::Diagnostic& AddWarning(const Source& source) const;
- /// Adds the given note message to the diagnostics
- void AddNote(const std::string& msg, const Source& source) const;
+ /// @returns a new note message added to the program's diagnostics
+ diag::Diagnostic& AddNote(const Source& source) const;
/// @returns the core::type::Type for the builtin type @p builtin_ty with the identifier @p
/// ident
diff --git a/src/tint/lang/wgsl/resolver/resolver_test.cc b/src/tint/lang/wgsl/resolver/resolver_test.cc
index c2392dd..3d21f7a 100644
--- a/src/tint/lang/wgsl/resolver/resolver_test.cc
+++ b/src/tint/lang/wgsl/resolver/resolver_test.cc
@@ -1751,7 +1751,7 @@
WrapInFunction(expr);
ASSERT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching overload for operator "));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching overload for 'operator "));
}
INSTANTIATE_TEST_SUITE_P(ResolverTest,
Expr_Binary_Test_Invalid,
@@ -1795,7 +1795,7 @@
ASSERT_TRUE(TypeOf(expr) == result_type);
} else {
ASSERT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("no matching overload for operator *"));
+ EXPECT_THAT(r()->error(), HasSubstr("no matching overload for 'operator *"));
}
}
auto all_dimension_values = testing::Values(2u, 3u, 4u);
@@ -1833,7 +1833,7 @@
ASSERT_TRUE(TypeOf(expr) == result_type);
} else {
ASSERT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching overload for operator * "));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching overload for 'operator * "));
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTest,
@@ -2117,7 +2117,7 @@
WrapInFunction(der);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching overload for operator ! (vec4<f32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching overload for 'operator ! (vec4<f32>)"));
}
TEST_F(ResolverTest, UnaryOp_Complement) {
@@ -2127,7 +2127,7 @@
WrapInFunction(der);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching overload for operator ~ (vec4<f32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching overload for 'operator ~ (vec4<f32>)"));
}
TEST_F(ResolverTest, UnaryOp_Negation) {
@@ -2137,7 +2137,7 @@
WrapInFunction(der);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("error: no matching overload for operator - (u32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("error: no matching overload for 'operator - (u32)"));
}
TEST_F(ResolverTest, TextureSampler_TextureSample) {
@@ -2419,7 +2419,7 @@
});
ASSERT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: cannot take the address of var 's' in handle address space");
+ EXPECT_EQ(r()->error(), "error: cannot take the address of 'var s' in handle address space");
}
TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
@@ -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 e364a91..5164284 100644
--- a/src/tint/lang/wgsl/resolver/sem_helper.cc
+++ b/src/tint/lang/wgsl/resolver/sem_helper.cc
@@ -35,6 +35,8 @@
#include "src/tint/lang/wgsl/sem/type_expression.h"
#include "src/tint/lang/wgsl/sem/value_expression.h"
#include "src/tint/utils/rtti/switch.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/text_style.h"
namespace tint::resolver {
@@ -68,69 +70,71 @@
auto* type = ty_expr->Type();
if (auto* incomplete = type->As<IncompleteType>(); TINT_UNLIKELY(incomplete)) {
- AddError("expected '<' for '" + std::string(ToString(incomplete->builtin)) + "'",
- expr->Declaration()->source.End());
+ AddError(expr->Declaration()->source.End())
+ << "expected " << style::Code << "<" << style::Plain << " for " << style::Type
+ << incomplete->builtin;
return nullptr;
}
return ty_expr;
}
-std::string SemHelper::Describe(const sem::Expression* expr) const {
- return Switch(
+StyledText SemHelper::Describe(const sem::Expression* expr) const {
+ StyledText text;
+
+ Switch(
expr, //
[&](const sem::VariableUser* var_expr) {
auto* variable = var_expr->Variable()->Declaration();
auto name = variable->name->symbol.Name();
- auto* kind = Switch(
- variable, //
- [&](const ast::Var*) { return "var"; }, //
- [&](const ast::Let*) { return "let"; }, //
- [&](const ast::Const*) { return "const"; }, //
- [&](const ast::Parameter*) { return "parameter"; }, //
- [&](const ast::Override*) { return "override"; }, //
- [&](Default) { return "variable"; });
- return std::string(kind) + " '" + name + "'";
+ Switch(
+ variable, //
+ [&](const ast::Var*) { text << style::Keyword << "var"; }, //
+ [&](const ast::Let*) { text << style::Keyword << "let"; }, //
+ [&](const ast::Const*) { text << style::Keyword << "const"; }, //
+ [&](const ast::Parameter*) { text << "parameter"; }, //
+ [&](const ast::Override*) { text << style::Keyword << "override"; }, //
+ [&](Default) { text << "variable"; });
+ text << " " << style::Variable << name;
},
[&](const sem::ValueExpression* val_expr) {
- auto type = val_expr->Type()->FriendlyName();
- return "value of type '" + type + "'";
+ text << "value of type " << style::Type << val_expr->Type()->FriendlyName();
},
[&](const sem::TypeExpression* ty_expr) {
- auto name = ty_expr->Type()->FriendlyName();
- return "type '" + name + "'";
+ text << "type " << style::Type << ty_expr->Type()->FriendlyName();
},
[&](const sem::FunctionExpression* fn_expr) {
auto* fn = fn_expr->Function()->Declaration();
- auto name = fn->name->symbol.Name();
- return "function '" + name + "'";
+ text << "function " << style::Function << fn->name->symbol.Name();
},
[&](const sem::BuiltinEnumExpression<wgsl::BuiltinFn>* fn) {
- return "builtin function '" + tint::ToString(fn->Value()) + "'";
+ text << "builtin function " << style::Function << fn->Value();
},
[&](const sem::BuiltinEnumExpression<core::Access>* access) {
- return "access '" + tint::ToString(access->Value()) + "'";
+ text << "access " << style::Enum << access->Value();
},
[&](const sem::BuiltinEnumExpression<core::AddressSpace>* addr) {
- return "address space '" + tint::ToString(addr->Value()) + "'";
+ text << "address space " << style::Enum << addr->Value();
},
[&](const sem::BuiltinEnumExpression<core::BuiltinValue>* builtin) {
- return "builtin value '" + tint::ToString(builtin->Value()) + "'";
+ text << "builtin value " << style::Enum << builtin->Value();
},
[&](const sem::BuiltinEnumExpression<core::InterpolationSampling>* fmt) {
- return "interpolation sampling '" + tint::ToString(fmt->Value()) + "'";
+ text << "interpolation sampling " << style::Enum << fmt->Value();
},
[&](const sem::BuiltinEnumExpression<core::InterpolationType>* fmt) {
- return "interpolation type '" + tint::ToString(fmt->Value()) + "'";
+ text << "interpolation type " << style::Enum << fmt->Value();
},
[&](const sem::BuiltinEnumExpression<core::TexelFormat>* fmt) {
- return "texel format '" + tint::ToString(fmt->Value()) + "'";
+ text << "texel format " << style::Enum << fmt->Value();
},
[&](const UnresolvedIdentifier* ui) {
auto name = ui->Identifier()->identifier->symbol.Name();
- return "unresolved identifier '" + name + "'";
+ text << "unresolved identifier " << style::Code << name;
}, //
TINT_ICE_ON_NO_MATCH);
+
+ return text << style::Plain;
}
void SemHelper::ErrorUnexpectedExprKind(
@@ -140,7 +144,7 @@
if (auto* ui = expr->As<UnresolvedIdentifier>()) {
auto* ident = ui->Identifier();
auto name = ident->identifier->symbol.Name();
- AddError("unresolved " + std::string(wanted) + " '" + name + "'", ident->source);
+ AddError(ident->source) << "unresolved " << wanted << " " << style::Code << name;
if (!suggestions.IsEmpty()) {
// Filter out suggestions that have a leading underscore.
Vector<std::string_view, 8> filtered;
@@ -149,15 +153,13 @@
filtered.Push(str);
}
}
- StringStream msg;
- tint::SuggestAlternatives(name, filtered.Slice(), msg);
- AddNote(msg.str(), ident->source);
+ auto& note = AddNote(ident->source);
+ tint::SuggestAlternatives(name, filtered.Slice(), note.message);
}
return;
}
- AddError("cannot use " + Describe(expr) + " as " + std::string(wanted),
- expr->Declaration()->source);
+ AddError(expr->Declaration()->source) << "cannot use " << Describe(expr) << " as " << wanted;
NoteDeclarationSource(expr->Declaration());
}
@@ -166,7 +168,8 @@
if (auto* ident = expr->Declaration()->As<ast::IdentifierExpression>()) {
if (expr->IsAnyOf<sem::FunctionExpression, sem::TypeExpression,
sem::BuiltinEnumExpression<wgsl::BuiltinFn>>()) {
- AddNote("are you missing '()'?", ident->source.End());
+ AddNote(ident->source.End())
+ << "are you missing " << style::Code << "()" << style::Plain << "?";
}
}
}
@@ -188,40 +191,48 @@
Switch(
node,
[&](const ast::Struct* n) {
- AddNote("struct '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << style::Keyword << "struct " << style::Type
+ << n->name->symbol.Name() << style::Plain << " declared here";
},
[&](const ast::Alias* n) {
- AddNote("alias '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << style::Keyword << "alias " << style::Type
+ << n->name->symbol.Name() << style::Plain << " declared here";
},
[&](const ast::Var* n) {
- AddNote("var '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << style::Keyword << "var " << style::Variable
+ << n->name->symbol.Name() << style::Plain << " declared here";
},
[&](const ast::Let* n) {
- AddNote("let '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << style::Keyword << "let " << style::Variable
+ << n->name->symbol.Name() << style::Plain << " declared here";
},
[&](const ast::Override* n) {
- AddNote("override '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << style::Keyword << "override " << style::Variable
+ << n->name->symbol.Name() << style::Plain << " declared here";
},
[&](const ast::Const* n) {
- AddNote("const '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << style::Keyword << "const " << style::Variable
+ << n->name->symbol.Name() << style::Plain << " declared here";
},
[&](const ast::Parameter* n) {
- AddNote("parameter '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << "parameter " << style::Variable << n->name->symbol.Name()
+ << style::Plain << " declared here";
},
[&](const ast::Function* n) {
- AddNote("function '" + n->name->symbol.Name() + "' declared here", n->source);
+ AddNote(n->source) << "function " << style::Function << n->name->symbol.Name()
+ << style::Plain << " declared here";
});
}
-void SemHelper::AddError(const std::string& msg, const Source& source) const {
- builder_->Diagnostics().AddError(diag::System::Resolver, msg, source);
+diag::Diagnostic& SemHelper::AddError(const Source& source) const {
+ return builder_->Diagnostics().AddError(diag::System::Resolver, source);
}
-void SemHelper::AddWarning(const std::string& msg, const Source& source) const {
- builder_->Diagnostics().AddWarning(diag::System::Resolver, msg, source);
+diag::Diagnostic& SemHelper::AddWarning(const Source& source) const {
+ return builder_->Diagnostics().AddWarning(diag::System::Resolver, source);
}
-void SemHelper::AddNote(const std::string& msg, const Source& source) const {
- builder_->Diagnostics().AddNote(diag::System::Resolver, msg, source);
+diag::Diagnostic& SemHelper::AddNote(const Source& source) const {
+ return builder_->Diagnostics().AddNote(diag::System::Resolver, source);
}
} // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/sem_helper.h b/src/tint/lang/wgsl/resolver/sem_helper.h
index ad63ac2..fd7b700 100644
--- a/src/tint/lang/wgsl/resolver/sem_helper.h
+++ b/src/tint/lang/wgsl/resolver/sem_helper.h
@@ -40,6 +40,7 @@
#include "src/tint/lang/wgsl/sem/type_expression.h"
#include "src/tint/utils/containers/map.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/text/styled_text.h"
namespace tint::resolver {
@@ -287,17 +288,17 @@
/// @param expr the expression to describe
/// @return a string that describes @p expr. Useful for diagnostics.
- std::string Describe(const sem::Expression* expr) const;
+ StyledText Describe(const sem::Expression* expr) const;
private:
- /// Adds the given error message to the diagnostics
- void AddError(const std::string& msg, const Source& source) const;
+ /// @returns a new error diagnostics
+ diag::Diagnostic& AddError(const Source& source) const;
- /// Adds the given warning message to the diagnostics
- void AddWarning(const std::string& msg, const Source& source) const;
+ /// @returns a new warning diagnostics
+ diag::Diagnostic& AddWarning(const Source& source) const;
- /// Adds the given note message to the diagnostics
- void AddNote(const std::string& msg, const Source& source) const;
+ /// @returns a new note diagnostics
+ diag::Diagnostic& AddNote(const Source& source) const;
ProgramBuilder* builder_;
};
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 0264afc..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>'");
}
@@ -493,9 +493,9 @@
GlobalVar("b", ty.array(ty.f32(), Add("size", 1_i)), core::AddressSpace::kWorkgroup);
WrapInFunction(Assign(Source{{12, 34}}, "a", "b"));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: cannot assign 'array<f32, [unnamed override-expression]>' to "
- "'array<f32, [unnamed override-expression]>'");
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: cannot assign 'array<f32, [unnamed override-expression]>' to 'array<f32, [unnamed override-expression]>')");
}
TEST_F(ResolverTypeValidationTest, ArraySize_NamedOverride_Param) {
@@ -536,8 +536,8 @@
core::AddressSpace::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 error: var 'size' cannot be referenced at module-scope
-note: var 'size' declared here)");
+ R"(12:34 error: 'var size' cannot be referenced at module-scope
+note: 'var size' declared here)");
}
TEST_F(ResolverTypeValidationTest, ArraySize_FunctionConst) {
@@ -1511,7 +1511,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: type 'A' does not take template arguments
-56:78 note: alias 'A' declared here)");
+56:78 note: 'alias A' declared here)");
}
INSTANTIATE_TEST_SUITE_P(BuiltinTypes,
@@ -1564,7 +1564,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: type 'S' does not take template arguments
-56:78 note: struct 'S' declared here)");
+56:78 note: 'struct S' declared here)");
}
TEST_F(ResolverUntemplatedTypeUsedWithTemplateArgs, Struct_Ctor) {
@@ -1576,7 +1576,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: type 'S' does not take template arguments
-note: struct 'S' declared here)");
+note: 'struct S' declared here)");
}
TEST_F(ResolverUntemplatedTypeUsedWithTemplateArgs, AliasedArray_Type) {
@@ -1589,7 +1589,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: type 'A' does not take template arguments
-note: alias 'A' declared here)");
+note: 'alias A' declared here)");
}
TEST_F(ResolverUntemplatedTypeUsedWithTemplateArgs, AliasedArray_Ctor) {
@@ -1601,7 +1601,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: type 'A' does not take template arguments
-note: alias 'A' declared here)");
+note: 'alias A' declared here)");
}
} // namespace TypeDoesNotTakeTemplateArgs
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index c86127a..818e5e1 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -1829,9 +1829,8 @@
auto* control_flow = TraceBackAlongPathUntil(
non_uniform_source, [](Node* node) { return node->affects_control_flow; });
if (control_flow) {
- diagnostics_.AddNote(diag::System::Resolver,
- "control flow depends on possibly non-uniform value",
- control_flow->ast->source);
+ diagnostics_.AddNote(diag::System::Resolver, control_flow->ast->source)
+ << "control flow depends on possibly non-uniform value";
// TODO(jrprice): There are cases where the function with uniformity requirements is not
// actually inside this control flow construct, for example:
// - A conditional interrupt (e.g. break), with a barrier elsewhere in the loop
@@ -1876,58 +1875,52 @@
non_uniform_source->ast,
[&](const ast::IdentifierExpression* ident) {
auto* var = sem_.GetVal(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable();
- StringStream ss;
if (auto* param = var->As<sem::Parameter>()) {
auto* func = param->Owner()->As<sem::Function>();
- ss << param_type(param) << "'" << NameFor(ident) << "' of '" << NameFor(func)
- << "' may be non-uniform";
+ diagnostics_.AddNote(diag::System::Resolver, ident->source)
+ << param_type(param) << "'" << NameFor(ident) << "' of '" << NameFor(func)
+ << "' may be non-uniform";
} else {
- ss << "reading from " << var_type(var) << "'" << NameFor(ident)
- << "' may result in a non-uniform value";
+ diagnostics_.AddNote(diag::System::Resolver, ident->source)
+ << "reading from " << var_type(var) << "'" << NameFor(ident)
+ << "' may result in a non-uniform value";
}
- diagnostics_.AddNote(diag::System::Resolver, ss.str(), ident->source);
},
[&](const ast::Variable* v) {
auto* var = sem_.Get(v);
- StringStream ss;
- ss << "reading from " << var_type(var) << "'" << NameFor(v)
- << "' may result in a non-uniform value";
- diagnostics_.AddNote(diag::System::Resolver, ss.str(), v->source);
+ diagnostics_.AddNote(diag::System::Resolver, v->source)
+ << "reading from " << var_type(var) << "'" << NameFor(v)
+ << "' may result in a non-uniform value";
},
[&](const ast::CallExpression* c) {
auto target_name = NameFor(c->target);
switch (non_uniform_source->type) {
case Node::kFunctionCallReturnValue: {
- diagnostics_.AddNote(
- diag::System::Resolver,
- "return value of '" + target_name + "' may be non-uniform", c->source);
+ diagnostics_.AddNote(diag::System::Resolver, c->source)
+ << "return value of '" + target_name + "' may be non-uniform";
break;
}
case Node::kFunctionCallArgumentContents: {
auto* arg = c->args[non_uniform_source->arg_index];
auto* var = sem_.GetVal(arg)->RootIdentifier();
- StringStream ss;
- ss << "reading from " << var_type(var) << "'" << NameFor(var)
- << "' may result in a non-uniform value";
- diagnostics_.AddNote(diag::System::Resolver, ss.str(),
- var->Declaration()->source);
+ diagnostics_.AddNote(diag::System::Resolver, var->Declaration()->source)
+ << "reading from " << var_type(var) << "'" << NameFor(var)
+ << "' may result in a non-uniform value";
break;
}
case Node::kFunctionCallArgumentValue: {
auto* arg = c->args[non_uniform_source->arg_index];
// TODO(jrprice): Which output? (return value vs another pointer argument).
- diagnostics_.AddNote(diag::System::Resolver,
- "passing non-uniform pointer to '" + target_name +
- "' may produce a non-uniform output",
- arg->source);
+ diagnostics_.AddNote(diag::System::Resolver, arg->source)
+ << "passing non-uniform pointer to '" << target_name
+ << "' may produce a non-uniform output";
break;
}
case Node::kFunctionCallPointerArgumentResult: {
- diagnostics_.AddNote(
- diag::System::Resolver,
- "contents of pointer may become non-uniform after calling '" +
- target_name + "'",
- c->args[non_uniform_source->arg_index]->source);
+ diagnostics_.AddNote(diag::System::Resolver,
+ c->args[non_uniform_source->arg_index]->source)
+ << "contents of pointer may become non-uniform after calling '"
+ << target_name << "'";
break;
}
default: {
@@ -1937,8 +1930,8 @@
}
},
[&](const ast::Expression* e) {
- diagnostics_.AddNote(diag::System::Resolver,
- "result of expression may be non-uniform", e->source);
+ diagnostics_.AddNote(diag::System::Resolver, e->source)
+ << "result of expression may be non-uniform";
}, //
TINT_ICE_ON_NO_MATCH);
}
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 18f23cc..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.
-std::string AttrToStr(const ast::Attribute* attr) {
- return "@" + attr->Name();
-}
-
template <typename CALLBACK>
void TraverseCallChain(const sem::Function* from, const sem::Function* to, CALLBACK&& callback) {
for (auto* f : from->TransitivelyCalledFunctions()) {
@@ -180,34 +177,29 @@
Validator::~Validator() = default;
-void Validator::AddError(const std::string& msg, const Source& source) const {
- diagnostics_.AddError(diag::System::Resolver, msg, source);
+diag::Diagnostic& Validator::AddError(const Source& source) const {
+ return diagnostics_.AddError(diag::System::Resolver, source);
}
-void Validator::AddWarning(const std::string& msg, const Source& source) const {
- diagnostics_.AddWarning(diag::System::Resolver, msg, source);
+diag::Diagnostic& Validator::AddWarning(const Source& source) const {
+ return diagnostics_.AddWarning(diag::System::Resolver, source);
}
-void Validator::AddNote(const std::string& msg, const Source& source) const {
- diagnostics_.AddNote(diag::System::Resolver, msg, source);
+diag::Diagnostic& Validator::AddNote(const Source& source) const {
+ return diagnostics_.AddNote(diag::System::Resolver, source);
}
-bool Validator::AddDiagnostic(wgsl::DiagnosticRule rule,
- const std::string& msg,
- const Source& source) const {
+diag::Diagnostic* Validator::MaybeAddDiagnostic(wgsl::DiagnosticRule rule,
+ const Source& source) const {
auto severity = diagnostic_filters_.Get(rule);
if (severity != wgsl::DiagnosticSeverity::kOff) {
diag::Diagnostic d{};
d.severity = ToSeverity(severity);
d.system = diag::System::Resolver;
d.source = source;
- d.message = msg;
- diagnostics_.Add(std::move(d));
- if (severity == wgsl::DiagnosticSeverity::kError) {
- return false;
- }
+ return &diagnostics_.Add(std::move(d));
}
- return true;
+ return nullptr;
}
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
@@ -316,11 +308,11 @@
for (auto pair : incompatible) {
if (enabled_extensions_.Contains(pair.first) && enabled_extensions_.Contains(pair.second)) {
- std::string a{ToString(pair.first)};
- std::string b{ToString(pair.second)};
- AddError("extension '" + a + "' cannot be used with extension '" + b + "'",
- source_of(pair.first));
- AddNote("'" + b + "' enabled here", source_of(pair.second));
+ AddError(source_of(pair.first))
+ << "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;
}
}
@@ -332,7 +324,7 @@
// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
// T must be either u32 or i32.
if (!s->Type()->IsAnyOf<core::type::U32, core::type::I32>()) {
- AddError("atomic only supports i32 or u32 types", a->arguments[0]->source);
+ AddError(a->arguments[0]->source) << "atomic only supports i32 or u32 types";
return false;
}
return true;
@@ -340,7 +332,7 @@
bool Validator::Pointer(const ast::TemplatedIdentifier* a, const core::type::Pointer* s) const {
if (s->AddressSpace() == core::AddressSpace::kUndefined) {
- AddError("ptr missing address space", a->source);
+ AddError(a->source) << "ptr missing address space";
return false;
}
@@ -350,15 +342,15 @@
// * For the storage address space, the access mode is optional, and defaults to read.
// * For other address spaces, the access mode must not be written.
if (s->AddressSpace() != core::AddressSpace::kStorage) {
- AddError("only pointers in <storage> address space may specify an access mode",
- a->source);
+ AddError(a->source)
+ << "only pointers in <storage> address space may specify an access mode";
return false;
}
}
if (auto* store_ty = s->StoreType(); !IsStorable(store_ty)) {
- AddError(sem_.TypeNameOf(store_ty) + " cannot be used as the store type of a pointer",
- a->arguments[1]->source);
+ AddError(a->arguments[1]->source)
+ << sem_.TypeNameOf(store_ty) + " cannot be used as the store type of a pointer";
return false;
}
@@ -371,42 +363,39 @@
case core::Access::kRead:
if (!allowed_features_.features.count(
wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures)) {
- AddError(
+ AddError(source) <<
+
"read-only storage textures require the "
"readonly_and_readwrite_storage_textures language feature, which is not "
- "allowed in the current environment",
- source);
+ "allowed in the current environment";
return false;
}
break;
case core::Access::kReadWrite:
if (!allowed_features_.features.count(
wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures)) {
- AddError(
- "read-write storage textures require the "
- "readonly_and_readwrite_storage_textures language feature, which is not "
- "allowed in the current environment",
- source);
+ AddError(source)
+ << "read-write storage textures require the "
+ "readonly_and_readwrite_storage_textures language feature, which is not "
+ "allowed in the current environment";
return false;
}
break;
case core::Access::kWrite:
break;
case core::Access::kUndefined:
- AddError("storage texture missing access control", source);
+ AddError(source) << "storage texture missing access control";
return false;
}
if (!IsValidStorageTextureDimension(t->dim())) {
- AddError("cube dimensions for storage textures are not supported", source);
+ AddError(source) << "cube dimensions for storage textures are not supported";
return false;
}
if (!IsValidStorageTextureTexelFormat(t->texel_format())) {
- AddError(
- "image format must be one of the texel formats specified for storage "
- "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
- source);
+ AddError(source) << "image format must be one of the texel formats specified for storage "
+ "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats";
return false;
}
return true;
@@ -414,7 +403,7 @@
bool Validator::SampledTexture(const core::type::SampledTexture* t, const Source& source) const {
if (!t->type()->UnwrapRef()->IsAnyOf<core::type::F32, core::type::I32, core::type::U32>()) {
- AddError("texture_2d<type>: type must be f32, i32 or u32", source);
+ AddError(source) << "texture_2d<type>: type must be f32, i32 or u32";
return false;
}
@@ -424,12 +413,12 @@
bool Validator::MultisampledTexture(const core::type::MultisampledTexture* t,
const Source& source) const {
if (t->dim() != core::type::TextureDimension::k2d) {
- AddError("only 2d multisampled textures are supported", source);
+ AddError(source) << "only 2d multisampled textures are supported";
return false;
}
if (!t->type()->UnwrapRef()->IsAnyOf<core::type::F32, core::type::I32, core::type::U32>()) {
- AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32", source);
+ AddError(source) << "texture_multisampled_2d<type>: type must be f32, i32 or u32";
return false;
}
@@ -440,9 +429,8 @@
const core::type::Type* from,
const Source& source) const {
if (core::type::Type::ConversionRank(from, to) == core::type::Type::kNoConversion) {
- AddError("cannot convert value of type '" + sem_.TypeNameOf(from) + "' to type '" +
- sem_.TypeNameOf(to) + "'",
- source);
+ 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;
@@ -456,10 +444,10 @@
// Value type has to match storage type
if (storage_ty != value_type) {
- StringStream s;
- s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty)
- << "' with value of type '" << sem_.TypeNameOf(initializer_ty) << "'";
- AddError(s.str(), v->source);
+ 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;
}
@@ -501,16 +489,18 @@
}
auto note_usage = [&] {
- AddNote("'" + store_ty->FriendlyName() + "' used in address space '" +
- tint::ToString(address_space) + "' here",
- source);
+ 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("using f16 types in 'push_constant' address space is not implemented yet", source);
+ AddError(source) << "using " << style::Type << "f16" << style::Plain << " in "
+ << style::Enum << "push_constant" << style::Plain
+ << " address space is not implemented yet";
return false;
}
@@ -521,7 +511,7 @@
// Recurse into the member type.
if (!AddressSpaceLayout(m->Type(), address_space, m->Declaration()->type->source)) {
- AddNote("see layout of struct:\n" + str->Layout(), str->Declaration()->source);
+ AddNote(str->Declaration()->source) << "see layout of struct:\n" << str->Layout();
note_usage();
return false;
}
@@ -530,20 +520,21 @@
if (m->Offset() % required_align != 0 &&
!enabled_extensions_.Contains(
wgsl::Extension::kChromiumInternalRelaxedUniformLayout)) {
- AddError("the offset of a struct member of type '" +
- m->Type()->UnwrapRef()->FriendlyName() + "' in address space '" +
- tint::ToString(address_space) + "' must be a multiple of " +
- std::to_string(required_align) + " bytes, but '" + member_name_of(m) +
- "' is currently at offset " + std::to_string(m->Offset()) +
- ". Consider setting @align(" + std::to_string(required_align) +
- ") on this member",
- m->Declaration()->source);
+ AddError(m->Declaration()->source)
+ << "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("see layout of struct:\n" + str->Layout(), str->Declaration()->source);
+ AddNote(str->Declaration()->source) << "see layout of struct:\n" << str->Layout();
if (auto* member_str = m->Type()->As<sem::Struct>()) {
- AddNote("and layout of struct member:\n" + member_str->Layout(),
- member_str->Declaration()->source);
+ AddNote(member_str->Declaration()->source) << "and layout of struct member:\n"
+ << member_str->Layout();
}
note_usage();
@@ -558,20 +549,24 @@
if (prev_to_curr_offset % 16 != 0 &&
!enabled_extensions_.Contains(
wgsl::Extension::kChromiumInternalRelaxedUniformLayout)) {
- AddError(
- "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 " +
- std::to_string(prev_to_curr_offset) + " bytes between '" +
- member_name_of(prev_member) + "' and '" + member_name_of(m) +
- "'. Consider setting @align(16) on this member",
- m->Declaration()->source);
+ AddError(m->Declaration()->source)
+ << 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 " << 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("see layout of struct:\n" + str->Layout(), str->Declaration()->source);
+ AddNote(str->Declaration()->source) << "see layout of struct:\n"
+ << str->Layout();
auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
- AddNote("and layout of previous member struct:\n" + prev_member_str->Layout(),
- prev_member_str->Declaration()->source);
+ AddNote(prev_member_str->Declaration()->source)
+ << "and layout of previous member struct:\n"
+ << prev_member_str->Layout();
note_usage();
return false;
}
@@ -596,25 +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 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(
- "uniform storage requires that array elements are aligned to 16 bytes, but "
- "array element of type '" +
- arr->ElemType()->FriendlyName() + "' has a stride of " +
- std::to_string(arr->Stride()) + " bytes. " + hint,
- source);
+ 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;
}
}
@@ -636,8 +630,9 @@
if (IsValidationEnabled(var->attributes,
ast::DisabledValidation::kIgnoreAddressSpace)) {
if (!local->Type()->UnwrapRef()->IsConstructible()) {
- AddError("function-scope 'var' must have a constructible type",
- var->type ? var->type->source : var->source);
+ AddError(var->type ? var->type->source : var->source)
+ << "function-scope " << style::Keyword << "var" << style::Plain
+ << " must have a constructible type";
return false;
}
}
@@ -663,16 +658,18 @@
[&](const ast::Var* var) {
if (auto* init = global->Initializer();
init && init->Stage() > core::EvaluationStage::kOverride) {
- AddError("module-scope 'var' initializer must be a constant or override-expression",
- init->Declaration()->source);
+ AddError(init->Declaration()->source)
+ << "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(
- "module-scope 'var' declarations that are not of texture or sampler types must "
- "provide an address space",
- decl->source);
+ 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;
}
@@ -687,7 +684,8 @@
}
if (global->AddressSpace() == core::AddressSpace::kFunction) {
- AddError("module-scope 'var' must not use address space 'function'", decl->source);
+ AddError(decl->source) << "module-scope " << style::Keyword << "var" << style::Plain
+ << " must not use address space " << style::Enum << "function";
return false;
}
@@ -698,7 +696,9 @@
// https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
// Each resource variable must be declared with both group and binding attributes.
if (!decl->HasBindingPoint()) {
- AddError("resource variables require @group and @binding attributes", decl->source);
+ AddError(decl->source)
+ << "resource variables require " << style::Attribute << "@group" << style::Plain
+ << " and " << style::Attribute << "@binding" << style::Plain << " attributes";
return false;
}
break;
@@ -709,8 +709,10 @@
if (binding_attr || group_attr) {
// https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
// Must only be applied to a resource variable
- AddError("non-resource variables must not have @group or @binding attributes",
- decl->source);
+ AddError(decl->source)
+ << "non-resource variables must not have " << style::Attribute << "@group"
+ << style::Plain << " or " << style::Attribute << "@binding" << style::Plain
+ << " attributes";
return false;
}
}
@@ -724,7 +726,8 @@
auto* store_ty = v->Type()->UnwrapRef();
if (!IsStorable(store_ty)) {
- AddError(sem_.TypeNameOf(store_ty) + " cannot be used as the type of a var", var->source);
+ AddError(var->source) << sem_.TypeNameOf(store_ty)
+ << " cannot be used as the type of a var";
return false;
}
@@ -732,9 +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("variables of type '" + sem_.TypeNameOf(store_ty) +
- "' must not specifiy an address space",
- var->source);
+ AddError(var->source) << "variables of type " << style::Type << sem_.TypeNameOf(store_ty)
+ << style::Plain << " must not specifiy an address space";
return false;
}
@@ -744,8 +746,8 @@
// * For the storage address space, the access mode is optional, and defaults to read.
// * For other address spaces, the access mode must not be written.
if (v->AddressSpace() != core::AddressSpace::kStorage) {
- AddError("only variables in <storage> address space may specify an access mode",
- var->source);
+ AddError(var->source)
+ << "only variables in <storage> address space may specify an access mode";
return false;
}
}
@@ -759,10 +761,12 @@
// https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
// Optionally has an initializer expression, if the variable is in the private or
// function address spaces.
- AddError("var of address space '" + tint::ToString(v->AddressSpace()) +
- "' cannot have an initializer. var initializers are only supported "
- "for the address spaces 'private' and 'function'",
- var->source);
+ AddError(var->source)
+ << "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;
}
}
@@ -775,7 +779,7 @@
if (IsValidationEnabled(var->attributes, ast::DisabledValidation::kIgnoreAddressSpace) &&
(v->AddressSpace() == core::AddressSpace::kIn ||
v->AddressSpace() == core::AddressSpace::kOut)) {
- AddError("invalid use of input/output address space", var->source);
+ AddError(var->source) << "invalid use of input/output address space";
return false;
}
return true;
@@ -786,8 +790,8 @@
auto* storage_ty = v->Type()->UnwrapRef();
if (!(storage_ty->IsConstructible() || storage_ty->Is<core::type::Pointer>())) {
- AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a 'let'",
- decl->source);
+ AddError(decl->source) << sem_.TypeNameOf(storage_ty) << " cannot be used as the type of a "
+ << style::Keyword << "let";
return false;
}
return true;
@@ -799,25 +803,25 @@
auto* storage_ty = v->Type()->UnwrapRef();
if (auto* init = v->Initializer(); init && init->Stage() > core::EvaluationStage::kOverride) {
- AddError("'override' initializer must be an override-expression",
- init->Declaration()->source);
+ 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("@id values must be unique", attr->source);
- AddNote("a override with an ID of " + std::to_string(id->value) +
- " was previously declared here:",
- ast::GetAttribute<ast::IdAttribute>((*var)->Declaration()->attributes)->source);
+ 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";
return false;
}
}
if (!storage_ty->Is<core::type::Scalar>()) {
- AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a 'override'",
- decl->source);
+ AddError(decl->source) << sem_.TypeNameOf(storage_ty) << " cannot be used as the type of a "
+ << style::Keyword << "override";
return false;
}
@@ -855,10 +859,8 @@
break;
}
if (!ok) {
- StringStream ss;
- ss << "function parameter of pointer type cannot be in '" << sc
- << "' address space";
- AddError(ss.str(), decl->source);
+ AddError(decl->source) << "function parameter of pointer type cannot be in "
+ << style::Enum << sc << style::Plain << " address space";
return false;
}
}
@@ -866,13 +868,13 @@
if (IsPlain(var->Type())) {
if (!var->Type()->IsConstructible()) {
- AddError("type of function parameter must be constructible", decl->type->source);
+ AddError(decl->type->source) << "type of function parameter must be constructible";
return false;
}
} else if (!var->Type()
->IsAnyOf<core::type::Texture, core::type::Sampler, core::type::Pointer>()) {
- AddError("type of function parameter cannot be " + sem_.TypeNameOf(var->Type()),
- decl->source);
+ AddError(decl->source) << "type of function parameter cannot be "
+ << sem_.TypeNameOf(var->Type());
return false;
}
@@ -889,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 &&
@@ -898,9 +907,7 @@
}
auto* vec = type->As<core::type::Vector>();
if (!(vec && vec->Width() == 4 && vec->type()->Is<core::type::F32>())) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'vec4<f32>'";
- AddError(err.str(), attr->source);
+ err_builtin_type("vec4<f32>");
return false;
}
break;
@@ -915,9 +922,7 @@
}
if (!(type->is_unsigned_integer_vector() &&
type->As<core::type::Vector>()->Width() == 3)) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'vec3<u32>'";
- AddError(err.str(), attr->source);
+ err_builtin_type("vec3<u32>");
return false;
}
break;
@@ -927,9 +932,7 @@
is_stage_mismatch = true;
}
if (!type->Is<core::type::F32>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'f32'";
- AddError(err.str(), attr->source);
+ err_builtin_type("f32");
return false;
}
break;
@@ -939,9 +942,7 @@
is_stage_mismatch = true;
}
if (!type->Is<core::type::Bool>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'bool'";
- AddError(err.str(), attr->source);
+ err_builtin_type("bool");
return false;
}
break;
@@ -951,9 +952,7 @@
is_stage_mismatch = true;
}
if (!type->Is<core::type::U32>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'u32'";
- AddError(err.str(), attr->source);
+ err_builtin_type("u32");
return false;
}
break;
@@ -964,9 +963,7 @@
is_stage_mismatch = true;
}
if (!type->Is<core::type::U32>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'u32'";
- AddError(err.str(), attr->source);
+ err_builtin_type("u32");
return false;
}
break;
@@ -975,9 +972,7 @@
is_stage_mismatch = true;
}
if (!type->Is<core::type::U32>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'u32'";
- AddError(err.str(), attr->source);
+ err_builtin_type("u32");
return false;
}
break;
@@ -987,31 +982,28 @@
is_stage_mismatch = true;
}
if (!type->Is<core::type::U32>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'u32'";
- AddError(err.str(), attr->source);
+ err_builtin_type("u32");
return false;
}
break;
case core::BuiltinValue::kSubgroupInvocationId:
case core::BuiltinValue::kSubgroupSize:
if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumExperimentalSubgroups)) {
- StringStream err;
- err << "use of @builtin(" << builtin
- << ") attribute requires enabling extension 'chromium_experimental_subgroups'";
- AddError(err.str(), attr->source);
+ 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>()) {
- StringStream err;
- err << "store type of @builtin(" << builtin << ") must be 'u32'";
- AddError(err.str(), attr->source);
+ err_builtin_type("u32");
return false;
}
if (stage != ast::PipelineStage::kNone && stage != ast::PipelineStage::kCompute) {
- StringStream err;
- err << "@builtin(" << builtin << ") is only valid as a compute shader input";
- AddError(err.str(), attr->source);
+ AddError(attr->source)
+ << style::Attribute << "@builtin" << style::Code << "(" << style::Enum
+ << builtin << style::Code << ")" << style::Plain
+ << " is only valid as a compute shader input";
return false;
}
break;
@@ -1020,10 +1012,10 @@
}
if (is_stage_mismatch) {
- StringStream err;
- err << "@builtin(" << builtin << ") cannot be used for " << stage_name.str() << " shader "
- << (is_input ? "input" : "output");
- AddError(err.str(), attr->source);
+ 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;
}
@@ -1034,7 +1026,8 @@
const core::type::Type* storage_ty,
const ast::PipelineStage stage) const {
if (stage == ast::PipelineStage::kCompute) {
- AddError(AttrToStr(attr) + " cannot be used by compute shaders", attr->source);
+ AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+ << " cannot be used by compute shaders";
return false;
}
@@ -1046,13 +1039,13 @@
}
if (type->is_integer_scalar_or_vector() && i_type->Value() != core::InterpolationType::kFlat) {
- AddError("interpolation type must be 'flat' for integral user-defined IO types",
- attr->source);
+ AddError(attr->source) << "interpolation type must be " << style::Enum << "flat"
+ << style::Plain << " for integral user-defined IO types";
return false;
}
if (attr->sampling && i_type->Value() == core::InterpolationType::kFlat) {
- AddError("flat interpolation attribute must not have a sampling parameter", attr->source);
+ AddError(attr->source) << "flat interpolation attribute must not have a sampling parameter";
return false;
}
@@ -1062,7 +1055,8 @@
bool Validator::InvariantAttribute(const ast::InvariantAttribute* attr,
const ast::PipelineStage stage) const {
if (stage == ast::PipelineStage::kCompute) {
- AddError(AttrToStr(attr) + " cannot be used by compute shaders", attr->source);
+ AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+ << " cannot be used by compute shaders";
return false;
}
return true;
@@ -1076,15 +1070,17 @@
attr, //
[&](const ast::WorkgroupAttribute*) {
if (decl->PipelineStage() != ast::PipelineStage::kCompute) {
- AddError("@workgroup_size is only valid for compute stages", attr->source);
+ AddError(attr->source) << style::Attribute << "@workgroup_size" << style::Plain
+ << " is only valid for compute stages";
return false;
}
return true;
},
[&](const ast::MustUseAttribute*) {
if (func->ReturnType()->Is<core::type::Void>()) {
- AddError("@must_use can only be applied to functions that return a value",
- attr->source);
+ AddError(attr->source)
+ << style::Attribute << "@must_use" << style::Plain
+ << " can only be applied to functions that return a value";
return false;
}
return true;
@@ -1096,16 +1092,15 @@
}
if (decl->params.Length() > kMaxFunctionParameters) {
- AddError("function declares " + std::to_string(decl->params.Length()) +
- " parameters, maximum is " + std::to_string(kMaxFunctionParameters),
- decl->source);
+ AddError(decl->source) << "function declares " << decl->params.Length()
+ << " parameters, maximum is " << kMaxFunctionParameters;
return false;
}
if (!func->ReturnType()->Is<core::type::Void>()) {
if (!func->ReturnType()->IsConstructible()) {
- AddError("function return type must be a constructible type",
- decl->return_type->source);
+ AddError(decl->return_type->source)
+ << "function return type must be a constructible type";
return false;
}
@@ -1115,12 +1110,12 @@
behaviors = sem_.Get(last)->Behaviors();
}
if (behaviors.Contains(sem::Behavior::kNext)) {
- AddError("missing return at end of function", decl->source);
+ AddError(decl->source) << "missing return at end of function";
return false;
}
} 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";
}
}
@@ -1183,18 +1178,20 @@
auto builtin = sem_.Get(builtin_attr)->Value();
if (pipeline_io_attribute) {
- AddError("multiple entry point IO attributes", attr->source);
- AddNote("previously consumed " + AttrToStr(pipeline_io_attribute),
- pipeline_io_attribute->source);
+ AddError(attr->source) << "multiple entry point IO attributes";
+ AddNote(pipeline_io_attribute->source)
+ << "previously consumed " << style::Attribute << "@"
+ << pipeline_io_attribute->Name();
return false;
}
pipeline_io_attribute = attr;
if (builtins.Contains(builtin)) {
- StringStream err;
- err << "@builtin(" << builtin << ") appears multiple times as pipeline "
+ AddError(decl->source)
+ << style::Attribute << "@builtin" << style::Code << "(" << style::Enum
+ << builtin << style::Code << ")" << style::Plain
+ << " appears multiple times as pipeline "
<< (param_or_ret == ParamOrRetType::kParameter ? "input" : "output");
- AddError(err.str(), decl->source);
return false;
}
@@ -1209,9 +1206,10 @@
[&](const ast::LocationAttribute* loc_attr) {
location_attribute = loc_attr;
if (pipeline_io_attribute) {
- AddError("multiple entry point IO attributes", attr->source);
- AddNote("previously consumed " + AttrToStr(pipeline_io_attribute),
- pipeline_io_attribute->source);
+ AddError(attr->source) << "multiple entry point IO attributes";
+ AddNote(pipeline_io_attribute->source)
+ << "previously consumed " << style::Attribute << "@"
+ << pipeline_io_attribute->Name();
return false;
}
pipeline_io_attribute = attr;
@@ -1236,9 +1234,10 @@
[&](const ast::ColorAttribute* col_attr) {
color_attribute = col_attr;
if (pipeline_io_attribute) {
- AddError("multiple entry point IO attributes", attr->source);
- AddNote("previously consumed " + AttrToStr(pipeline_io_attribute),
- pipeline_io_attribute->source);
+ AddError(attr->source) << "multiple entry point IO attributes";
+ AddNote(pipeline_io_attribute->source)
+ << "previously consumed " << style::Attribute << "@"
+ << pipeline_io_attribute->Name();
return false;
}
pipeline_io_attribute = attr;
@@ -1269,17 +1268,16 @@
if (IsValidationEnabled(attrs, ast::DisabledValidation::kEntryPointParameter)) {
if (is_struct_member && ty->Is<core::type::Struct>()) {
- AddError("nested structures cannot be used for entry point IO", source);
+ AddError(source) << "nested structures cannot be used for entry point IO";
return false;
}
if (!ty->Is<core::type::Struct>() && !pipeline_io_attribute) {
- std::string err = "missing entry point IO attribute";
+ auto& err = AddError(source) << "missing entry point IO attribute";
if (!is_struct_member) {
- err += (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
+ err << (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
: " on return type");
}
- AddError(err, source);
return false;
}
@@ -1287,18 +1285,18 @@
if (ty->is_integer_scalar_or_vector() && !interpolate_attribute) {
if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
param_or_ret == ParamOrRetType::kReturnType) {
- AddError(
- "integral user-defined vertex outputs must have a flat interpolation "
- "attribute",
- source);
+ AddError(source) << "integral user-defined vertex outputs must have a "
+ << 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(
- "integral user-defined fragment inputs must have a flat interpolation "
- "attribute",
- source);
+ 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;
}
}
@@ -1309,8 +1307,10 @@
// should restrict targets with @blend_src to location 0 for easy translation
// in the backend writers.
if (location.value_or(1) != 0) {
- AddError("@blend_src can only be used with @location(0)",
- blend_src_attribute->source);
+ AddError(blend_src_attribute->source)
+ << style::Attribute << "@blend_src" << style::Plain
+ << " can only be used with " << style::Attribute << "@location"
+ << style::Code << "(" << style::Literal << "0" << style::Code << ")";
return false;
}
}
@@ -1322,11 +1322,13 @@
}
if (first_blend_src && first_location_without_blend_src) {
- AddError(
- "use of @blend_src requires all the output @location attributes of the entry "
- "point to be paired with a @blend_src attribute",
- first_location_without_blend_src->source);
- AddNote("use of @blend_src here", first_blend_src->source);
+ AddError(first_location_without_blend_src->source)
+ << "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;
}
@@ -1335,38 +1337,44 @@
first_nonzero_location = location_attribute;
}
if (first_nonzero_location && first_blend_src) {
- AddError("pipeline cannot use both a @blend_src and non-zero @location",
- first_blend_src->source);
- AddNote("non-zero @location declared here", first_nonzero_location->source);
+ AddError(first_blend_src->source)
+ << "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;
}
std::pair<uint32_t, uint32_t> location_and_blend_src(location.value(),
blend_src.value_or(0));
if (!locations_and_blend_srcs.Add(location_and_blend_src)) {
- StringStream err;
- err << "@location(" << location.value() << ") ";
+ auto& err = AddError(location_attribute->source)
+ << 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";
- AddError(err.str(), location_attribute->source);
+ err << style::Plain << " appears multiple times";
return false;
}
}
if (color_attribute && !colors.Add(color.value())) {
- StringStream err;
- err << "@color(" << color.value() << ") appears multiple times";
- AddError(err.str(), color_attribute->source);
+ AddError(color_attribute->source)
+ << style::Attribute << "@color" << style::Code << "(" << style::Literal
+ << color.value() << style::Code << ")" << style::Plain
+ << " appears multiple times";
return false;
}
if (interpolate_attribute) {
if (!pipeline_io_attribute ||
!pipeline_io_attribute->Is<ast::LocationAttribute>()) {
- AddError("@interpolate can only be used with @location",
- interpolate_attribute->source);
+ AddError(interpolate_attribute->source)
+ << style::Attribute << "@interpolate" << style::Plain
+ << " can only be used with " << style::Attribute << "@location";
return false;
}
}
@@ -1380,8 +1388,10 @@
}
}
if (!has_position) {
- AddError("@invariant must be applied to a position builtin",
- invariant_attribute->source);
+ AddError(invariant_attribute->source)
+ << style::Attribute << "@invariant" << style::Plain
+ << " must be applied to a " << style::Attribute << "@builtin" << style::Code
+ << "(" << style::Enum << "position" << style::Code << ")";
return false;
}
}
@@ -1407,8 +1417,8 @@
member->Declaration()->source, param_or_ret,
/*is_struct_member*/ true, member->Attributes().location,
member->Attributes().blend_src, member->Attributes().color)) {
- AddNote("while analyzing entry point '" + decl->name->symbol.Name() + "'",
- decl->source);
+ AddNote(decl->source) << "while analyzing entry point " << style::Function
+ << decl->name->symbol.Name();
return false;
}
}
@@ -1459,16 +1469,16 @@
}
}
if (!found) {
- AddError("a vertex shader must include the 'position' builtin in its return type",
- decl->source);
+ 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("a compute shader must include 'workgroup_size' in its attributes",
- decl->source);
+ AddError(decl->source) << "a compute shader must include " << style::Attribute
+ << "@workgroup_size" << style::Plain << " in its attributes";
return false;
}
}
@@ -1495,12 +1505,13 @@
// 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(
- "entry point '" + func_name +
- "' references multiple variables that use the same resource binding @group(" +
- std::to_string(bp->group) + "), @binding(" + std::to_string(bp->binding) + ")",
- var_decl->source);
- AddNote("first resource binding usage declared here", added.value->source);
+ 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;
}
}
@@ -1529,14 +1540,15 @@
return "<unknown>";
};
- AddError(std::string(constraint) + " requires " + stage_name(latest_stage) +
- ", but expression is " + stage_name(expr->Stage()),
- expr->Declaration()->source);
+ AddError(expr->Declaration()->source)
+ << constraint << " requires " << stage_name(latest_stage) << ", but expression is "
+ << stage_name(expr->Stage());
if (auto* stmt = expr->Stmt()) {
if (auto* decl = As<ast::VariableDeclStatement>(stmt->Declaration())) {
if (decl->variable->Is<ast::Const>()) {
- AddNote("consider changing 'const' to 'let'", decl->source);
+ AddNote(decl->source) << "consider changing " << style::Keyword << "const"
+ << style::Plain << " to " << style::Keyword << "let";
}
}
}
@@ -1548,9 +1560,12 @@
bool Validator::Statements(VectorRef<const ast::Statement*> stmts) const {
for (auto* stmt : stmts) {
if (!sem_.Get(stmt)->IsReachable()) {
- if (!AddDiagnostic(wgsl::ChromiumDiagnosticRule::kUnreachableCode,
- "code is unreachable", stmt->source)) {
- return false;
+ if (auto* d = MaybeAddDiagnostic(wgsl::ChromiumDiagnosticRule::kUnreachableCode,
+ stmt->source)) {
+ *d << "code is unreachable";
+ if (d->severity >= diag::Severity::Error) {
+ return false;
+ }
}
break;
}
@@ -1561,14 +1576,14 @@
bool Validator::BreakStatement(const sem::Statement* stmt,
sem::Statement* current_statement) const {
if (!stmt->FindFirstParent<sem::LoopBlockStatement, sem::CaseStatement>()) {
- AddError("break statement must be in a loop or switch case", stmt->Declaration()->source);
+ AddError(stmt->Declaration()->source) << "break statement must be in a loop or switch case";
return false;
}
if (ClosestContinuing(/*stop_at_loop*/ true, /* stop_at_switch */ true, current_statement) !=
nullptr) {
- AddError(
- "`break` must not be used to exit from a continuing block. Use `break-if` instead.",
- stmt->Declaration()->source);
+ AddError(stmt->Declaration()->source)
+ << "`break` must not be used to exit from a continuing block. Use "
+ "`break-if` instead.";
return false;
}
return true;
@@ -1578,16 +1593,16 @@
sem::Statement* current_statement) const {
if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ true, /* stop_at_switch */ false,
current_statement)) {
- AddError("continuing blocks must not contain a continue statement",
- stmt->Declaration()->source);
+ AddError(stmt->Declaration()->source)
+ << "continuing blocks must not contain a continue statement";
if (continuing != stmt->Declaration() && continuing != stmt->Parent()->Declaration()) {
- AddNote("see continuing block here", continuing->source);
+ AddNote(continuing->source) << "see continuing block here";
}
return false;
}
if (!stmt->FindFirstParent<sem::LoopBlockStatement>()) {
- AddError("continue statement must be in a loop", stmt->Declaration()->source);
+ AddError(stmt->Declaration()->source) << "continue statement must be in a loop";
return false;
}
@@ -1608,23 +1623,24 @@
Switch(
call->Target(), //
[&](const sem::Function* fn) {
- AddError("ignoring return value of function '" +
- fn->Declaration()->name->symbol.Name() + "' annotated with @must_use",
- call->Declaration()->source);
+ AddError(call->Declaration()->source)
+ << "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("ignoring return value of builtin '" + tint::ToString(b->Fn()) + "'",
- call->Declaration()->source);
+ AddError(call->Declaration()->source)
+ << "ignoring return value of builtin " << style::Function << b->Fn();
},
[&](const sem::ValueConversion*) {
- AddError("value conversion evaluated but not used", call->Declaration()->source);
+ AddError(call->Declaration()->source) << "value conversion evaluated but not used";
},
[&](const sem::ValueConstructor*) {
- AddError("value constructor evaluated but not used", call->Declaration()->source);
+ AddError(call->Declaration()->source) << "value constructor evaluated but not used";
},
[&](Default) {
- AddError("return value of call not used", call->Declaration()->source);
+ AddError(call->Declaration()->source) << "return value of call not used";
});
return false;
}
@@ -1634,7 +1650,7 @@
bool Validator::LoopStatement(const sem::LoopStatement* stmt) const {
if (stmt->Behaviors().Empty()) {
- AddError("loop does not exit", stmt->Declaration()->source.Begin());
+ AddError(stmt->Declaration()->source.Begin()) << "loop does not exit";
return false;
}
return true;
@@ -1642,14 +1658,14 @@
bool Validator::ForLoopStatement(const sem::ForLoopStatement* stmt) const {
if (stmt->Behaviors().Empty()) {
- AddError("for-loop does not exit", stmt->Declaration()->source.Begin());
+ AddError(stmt->Declaration()->source.Begin()) << "for-loop does not exit";
return false;
}
if (auto* cond = stmt->Condition()) {
auto* cond_ty = cond->Type()->UnwrapRef();
if (!cond_ty->Is<core::type::Bool>()) {
- AddError("for-loop condition must be bool, got " + sem_.TypeNameOf(cond_ty),
- stmt->Condition()->Declaration()->source);
+ AddError(stmt->Condition()->Declaration()->source)
+ << "for-loop condition must be bool, got " << sem_.TypeNameOf(cond_ty);
return false;
}
}
@@ -1658,14 +1674,14 @@
bool Validator::WhileStatement(const sem::WhileStatement* stmt) const {
if (stmt->Behaviors().Empty()) {
- AddError("while does not exit", stmt->Declaration()->source.Begin());
+ AddError(stmt->Declaration()->source.Begin()) << "while does not exit";
return false;
}
if (auto* cond = stmt->Condition()) {
auto* cond_ty = cond->Type()->UnwrapRef();
if (!cond_ty->Is<core::type::Bool>()) {
- AddError("while condition must be bool, got " + sem_.TypeNameOf(cond_ty),
- stmt->Condition()->Declaration()->source);
+ AddError(stmt->Condition()->Declaration()->source)
+ << "while condition must be bool, got " << sem_.TypeNameOf(cond_ty);
return false;
}
}
@@ -1676,8 +1692,8 @@
sem::Statement* current_statement) const {
auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
if (!cond_ty->Is<core::type::Bool>()) {
- AddError("break-if statement condition must be bool, got " + sem_.TypeNameOf(cond_ty),
- stmt->Condition()->Declaration()->source);
+ AddError(stmt->Condition()->Declaration()->source)
+ << "break-if statement condition must be bool, got " << sem_.TypeNameOf(cond_ty);
return false;
}
@@ -1687,24 +1703,24 @@
}
if (auto* continuing = s->As<sem::LoopContinuingBlockStatement>()) {
if (continuing->Declaration()->statements.Back() != stmt->Declaration()) {
- AddError("break-if must be the last statement in a continuing block",
- stmt->Declaration()->source);
- AddNote("see continuing block here", s->Declaration()->source);
+ AddError(stmt->Declaration()->source)
+ << "break-if must be the last statement in a continuing block";
+ AddNote(s->Declaration()->source) << "see continuing block here";
return false;
}
return true;
}
}
- AddError("break-if must be in a continuing block", stmt->Declaration()->source);
+ AddError(stmt->Declaration()->source) << "break-if must be in a continuing block";
return false;
}
bool Validator::IfStatement(const sem::IfStatement* stmt) const {
auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
if (!cond_ty->Is<core::type::Bool>()) {
- AddError("if statement condition must be bool, got " + sem_.TypeNameOf(cond_ty),
- stmt->Condition()->Declaration()->source);
+ AddError(stmt->Condition()->Declaration()->source)
+ << "if statement condition must be bool, got " << sem_.TypeNameOf(cond_ty);
return false;
}
return true;
@@ -1728,9 +1744,9 @@
// If the called function does not return a value, a function call statement should be
// used instead.
auto* builtin = call->Target()->As<sem::BuiltinFn>();
- auto name = tint::ToString(builtin->Fn());
- AddError("builtin function '" + name + "' does not return a value",
- call->Declaration()->source);
+ AddError(call->Declaration()->source)
+ << "builtin function " << style::Function << builtin->Fn() << style::Plain
+ << " does not return a value";
return false;
}
}
@@ -1753,35 +1769,32 @@
return true;
}
auto index = static_cast<size_t>(signed_index);
- std::string name{core::ToString(usage)};
auto* arg = call->Arguments()[index];
if (auto values = arg->ConstantValue()) {
if (auto* vector = values->Type()->As<core::type::Vector>()) {
for (size_t i = 0; i < vector->Width(); i++) {
auto value = values->Index(i)->ValueAs<AInt>();
if (value < min || value > max) {
- AddError("each component of the " + name + " argument must be at least " +
- std::to_string(min) + " and at most " + std::to_string(max) +
- ". " + name + " component " + std::to_string(i) + " is " +
- std::to_string(value),
- arg->Declaration()->source);
+ AddError(arg->Declaration()->source)
+ << "each component of the " << usage << " argument must be at least "
+ << min << " and at most " << max << ". " << usage << " component " << i
+ << " is " << value;
return false;
}
}
} else {
auto value = values->ValueAs<AInt>();
if (value < min || value > max) {
- AddError("the " + name + " argument must be at least " + std::to_string(min) +
- " and at most " + std::to_string(max) + ". " + name + " is " +
- std::to_string(value),
- arg->Declaration()->source);
+ AddError(arg->Declaration()->source)
+ << "the " << usage << " argument must be at least " << min
+ << " and at most " << max << ". " << usage << " is " << value;
return false;
}
}
return true;
}
- AddError("the " + name + " argument must be a const-expression",
- arg->Declaration()->source);
+ AddError(arg->Declaration()->source)
+ << "the " << usage << " argument must be a const-expression";
return false;
};
@@ -1802,9 +1815,9 @@
auto* ty = ptr->StoreType();
if (ty->Is<core::type::Atomic>() || atomic_composite_info_.Contains(ty)) {
- AddError(
- "workgroupUniformLoad must not be called with an argument that contains an atomic type",
- arg->Declaration()->source);
+ AddError(arg->Declaration()->source)
+ << "workgroupUniformLoad must not be called with an argument that "
+ "contains an atomic type";
return false;
}
@@ -1820,8 +1833,8 @@
TINT_ASSERT(call->Arguments().Length() == 2);
auto* laneArg = call->Arguments()[1];
if (!laneArg->ConstantValue()) {
- AddError("the sourceLaneIndex argument of subgroupBroadcast must be a const-expression",
- laneArg->Declaration()->source);
+ AddError(laneArg->Declaration()->source)
+ << "the sourceLaneIndex argument of subgroupBroadcast must be a const-expression";
return false;
}
@@ -1837,9 +1850,9 @@
const auto extension = builtin->RequiredExtension();
if (extension != wgsl::Extension::kUndefined) {
if (!enabled_extensions_.Contains(extension)) {
- AddError("cannot call built-in function '" + std::string(builtin->str()) +
- "' without extension " + tint::ToString(extension),
- call->Declaration()->source);
+ AddError(call->Declaration()->source)
+ << "cannot call built-in function " << style::Function << builtin->Fn()
+ << style::Plain << " without extension " << extension;
return false;
}
}
@@ -1847,10 +1860,10 @@
const auto feature = builtin->RequiredLanguageFeature();
if (feature != wgsl::LanguageFeature::kUndefined) {
if (!allowed_features_.features.count(feature)) {
- AddError("built-in function '" + std::string(builtin->str()) + "' requires the " +
- std::string(wgsl::ToString(feature)) +
- " language feature, which is not allowed in the current environment",
- call->Declaration()->source);
+ AddError(call->Declaration()->source)
+ << "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;
}
}
@@ -1861,7 +1874,8 @@
bool Validator::CheckF16Enabled(const Source& source) const {
// Validate if f16 type is allowed.
if (!enabled_extensions_.Contains(wgsl::Extension::kF16)) {
- AddError("f16 type used without 'f16' extension enabled", source);
+ AddError(source) << style::Type << "f16" << style::Plain << " type used without "
+ << style::Code << "f16" << style::Plain << " extension enabled";
return false;
}
return true;
@@ -1874,24 +1888,25 @@
auto name = sym.Name();
if (!current_statement) { // Function call at module-scope.
- AddError("functions cannot be called at module-scope", decl->source);
+ AddError(decl->source) << "functions cannot be called at module-scope";
return false;
}
if (target->Declaration()->IsEntryPoint()) {
// https://www.w3.org/TR/WGSL/#function-restriction
// An entry point must never be the target of a function call.
- AddError("entry point functions cannot be the target of a function call", decl->source);
+ AddError(decl->source) << "entry point functions cannot be the target of a function call";
return false;
}
if (decl->args.Length() != target->Parameters().Length()) {
bool more = decl->args.Length() > target->Parameters().Length();
- AddError("too " + (more ? std::string("many") : std::string("few")) +
- " arguments in call to '" + name + "', expected " +
- std::to_string(target->Parameters().Length()) + ", got " +
- std::to_string(call->Arguments().Length()),
- decl->source);
+ AddError(decl->source) << "too "
+ << (more ? std::string("many") : std::string("few")) +
+ " arguments in call to "
+ << style::Function << name << style::Plain << ", expected "
+ << target->Parameters().Length() << ", got "
+ << call->Arguments().Length();
return false;
}
@@ -1902,10 +1917,10 @@
auto* arg_type = sem_.TypeOf(arg_expr)->UnwrapRef();
if (param_type != arg_type) {
- AddError("type mismatch for argument " + std::to_string(i + 1) + " in call to '" +
- name + "', expected '" + sem_.TypeNameOf(param_type) + "', got '" +
- sem_.TypeNameOf(arg_type) + "'",
- arg_expr->source);
+ 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;
}
@@ -1931,10 +1946,8 @@
if (root_store_type != arg_store_type &&
IsValidationEnabled(param->Declaration()->attributes,
ast::DisabledValidation::kIgnoreInvalidPointerArgument)) {
- AddError(
- "arguments of pointer type must not point to a subset of the originating "
- "variable",
- arg_expr->source);
+ AddError(arg_expr->source) << "arguments of pointer type must not point to a "
+ "subset of the originating variable";
return false;
}
}
@@ -1951,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("function '" + name + "' does not return a value", decl->source);
+ AddError(decl->source) << "function " << style::Function << name << style::Plain
+ << " does not return a value";
return false;
}
}
@@ -1962,28 +1976,26 @@
bool Validator::StructureInitializer(const ast::CallExpression* ctor,
const core::type::Struct* struct_type) const {
if (!struct_type->IsConstructible()) {
- AddError("structure constructor has non-constructible type", ctor->source);
+ AddError(ctor->source) << "structure constructor has non-constructible type";
return false;
}
if (ctor->args.Length() > 0) {
if (ctor->args.Length() != struct_type->Members().Length()) {
std::string fm = ctor->args.Length() < struct_type->Members().Length() ? "few" : "many";
- AddError("structure constructor has too " + fm + " inputs: expected " +
- std::to_string(struct_type->Members().Length()) + ", found " +
- std::to_string(ctor->args.Length()),
- ctor->source);
+ AddError(ctor->source)
+ << "structure constructor has too " << fm << " inputs: expected "
+ << struct_type->Members().Length() << ", found " << ctor->args.Length();
return false;
}
for (auto* member : struct_type->Members()) {
auto* value = ctor->args[member->Index()];
auto* value_ty = sem_.TypeOf(value);
if (member->Type() != value_ty->UnwrapRef()) {
- AddError(
- "type in structure constructor does not match struct member type: expected '" +
- sem_.TypeNameOf(member->Type()) + "', found '" + sem_.TypeNameOf(value_ty) +
- "'",
- value->source);
+ AddError(value->source)
+ << "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;
}
}
@@ -1999,27 +2011,26 @@
auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
if (core::type::Type::ConversionRank(value_ty, elem_ty) ==
core::type::Type::kNoConversion) {
- AddError("'" + sem_.TypeNameOf(value_ty) +
- "' cannot be used to construct an array of '" + sem_.TypeNameOf(elem_ty) +
- "'",
- value->source);
+ 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;
}
}
auto* c = array_type->Count();
if (c->Is<core::type::RuntimeArrayCount>()) {
- AddError("cannot construct a runtime-sized array", ctor->source);
+ AddError(ctor->source) << "cannot construct a runtime-sized array";
return false;
}
if (c->IsAnyOf<sem::NamedOverrideArrayCount, sem::UnnamedOverrideArrayCount>()) {
- AddError("cannot construct an array that has an override-expression count", ctor->source);
+ AddError(ctor->source) << "cannot construct an array that has an override-expression count";
return false;
}
if (!elem_ty->IsConstructible()) {
- AddError("array constructor has non-constructible element type", ctor->source);
+ AddError(ctor->source) << "array constructor has non-constructible element type";
return false;
}
@@ -2031,9 +2042,8 @@
const auto count = c->As<core::type::ConstantArrayCount>()->value;
if (!values.IsEmpty() && (values.Length() != count)) {
std::string fm = values.Length() < count ? "few" : "many";
- AddError("array constructor has too " + fm + " elements: expected " +
- std::to_string(count) + ", found " + std::to_string(values.Length()),
- ctor->source);
+ AddError(ctor->source) << "array constructor has too " << fm << " elements: expected "
+ << count << ", found " << values.Length();
return false;
}
return true;
@@ -2041,7 +2051,10 @@
bool Validator::Vector(const core::type::Type* el_ty, const Source& source) const {
if (!el_ty->Is<core::type::Scalar>()) {
- AddError("vector element type must be 'bool', 'f32', 'f16', 'i32' or 'u32'", source);
+ 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;
@@ -2049,7 +2062,8 @@
bool Validator::Matrix(const core::type::Type* el_ty, const Source& source) const {
if (!el_ty->is_float_scalar()) {
- AddError("matrix element type must be 'f32' or 'f16'", source);
+ AddError(source) << "matrix element type must be " << style::Type << "f32" << style::Plain
+ << " or " << style::Type << "f16";
return false;
}
return true;
@@ -2059,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("called by function '" + f->Declaration()->name->symbol.Name() + "'",
- f->Declaration()->source);
+ AddNote(f->Declaration()->source) << "called by function " << style::Function
+ << f->Declaration()->name->symbol.Name();
});
- AddNote(
- "called by entry point '" + entry_point->Declaration()->name->symbol.Name() + "'",
- entry_point->Declaration()->source);
+ AddNote(entry_point->Declaration()->source)
+ << "called by entry point " << style::Function
+ << entry_point->Declaration()->name->symbol.Name();
}
};
@@ -2077,11 +2091,9 @@
break;
}
}
- StringStream msg;
- msg << "var with '" << var->AddressSpace() << "' address space cannot be used by "
- << stage << " pipeline stage";
- AddError(msg.str(), source);
- AddNote("variable is declared here", var->Declaration()->source);
+ 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;
};
@@ -2105,10 +2117,8 @@
for (auto* builtin : func->DirectlyCalledBuiltins()) {
if (!builtin->SupportedStages().Contains(stage)) {
auto* call = func->FindDirectCallTo(builtin);
- StringStream err;
- err << "built-in cannot be used by " << stage << " pipeline stage";
- AddError(err.str(),
- call ? call->Declaration()->source : func->Declaration()->source);
+ AddError(call ? call->Declaration()->source : func->Declaration()->source)
+ << "built-in cannot be used by " << stage << " pipeline stage";
backtrace(func, entry_point);
return false;
}
@@ -2119,9 +2129,8 @@
auto check_no_discards = [&](const sem::Function* func, const sem::Function* entry_point) {
if (auto* discard = func->DiscardStatement()) {
auto stage = entry_point->Declaration()->PipelineStage();
- StringStream err;
- err << "discard statement cannot be used in " << stage << " pipeline stage";
- AddError(err.str(), discard->Declaration()->source);
+ AddError(discard->Declaration()->source)
+ << "discard statement cannot be used in " << stage << " pipeline stage";
backtrace(func, entry_point);
return false;
}
@@ -2176,13 +2185,13 @@
auto* el_ty = arr->ElemType();
if (!IsPlain(el_ty)) {
- AddError(sem_.TypeNameOf(el_ty) + " cannot be used as an element type of an array",
- el_source);
+ AddError(el_source) << sem_.TypeNameOf(el_ty)
+ << " cannot be used as an element type of an array";
return false;
}
if (!IsFixedFootprint(el_ty)) {
- AddError("an array element type cannot contain a runtime-sized array", el_source);
+ AddError(el_source) << "an array element type cannot contain a runtime-sized array";
return false;
}
@@ -2204,10 +2213,9 @@
// Arrays decorated with the stride attribute must have a stride that is
// at least the size of the element type, and be a multiple of the
// element type's alignment value.
- AddError(
- "arrays decorated with the stride attribute must have a stride that is at least the "
- "size of the element type, and be a multiple of the element type's alignment value",
- attr->source);
+ AddError(attr->source)
+ << "arrays decorated with the stride attribute must have a stride that is at least the "
+ "size of the element type, and be a multiple of the element type's alignment value";
return false;
}
return true;
@@ -2219,7 +2227,7 @@
bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) const {
if (str->Members().IsEmpty()) {
- AddError("structures must have at least one member", str->Declaration()->source);
+ AddError(str->Declaration()->source) << "structures must have at least one member";
return false;
}
@@ -2229,8 +2237,8 @@
if (auto* r = member->Type()->As<sem::Array>()) {
if (r->Count()->Is<core::type::RuntimeArrayCount>()) {
if (member != str->Members().Back()) {
- AddError("runtime arrays may only appear as the last member of a struct",
- member->Declaration()->source);
+ AddError(member->Declaration()->source)
+ << "runtime arrays may only appear as the last member of a struct";
return false;
}
}
@@ -2240,9 +2248,8 @@
return false;
}
} else if (!IsFixedFootprint(member->Type())) {
- AddError(
- "a struct that contains a runtime array cannot be nested inside another struct",
- member->Declaration()->source);
+ AddError(member->Declaration()->source)
+ << "a struct that contains a runtime array cannot be nested inside another struct";
return false;
}
@@ -2291,10 +2298,10 @@
},
[&](const ast::StructMemberSizeAttribute*) {
if (!member->Type()->HasCreationFixedFootprint()) {
- AddError(
- "@size can only be applied to members where the member's type size can "
- "be fully determined at shader creation time",
- attr->source);
+ AddError(attr->source)
+ << 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;
@@ -2306,8 +2313,9 @@
}
if (invariant_attribute && !has_position) {
- AddError("@invariant must be applied to a position builtin",
- invariant_attribute->source);
+ AddError(invariant_attribute->source)
+ << style::Attribute << "@invariant" << style::Plain
+ << " must be applied to a position builtin";
return false;
}
@@ -2316,14 +2324,18 @@
// restrict targets with index attributes to location 0 for easy translation in the
// backend writers.
if (member->Attributes().location.value_or(1) != 0) {
- AddError("@blend_src can only be used with @location(0)",
- blend_src_attribute->source);
+ AddError(blend_src_attribute->source)
+ << 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 can only be used with @location", interpolate_attribute->source);
+ AddError(interpolate_attribute->source)
+ << style::Attribute << "@interpolate" << style::Plain << " can only be used with "
+ << style::Attribute << "@location";
return false;
}
@@ -2333,13 +2345,14 @@
std::optional<uint32_t> blend_src = member->Attributes().blend_src;
if (!locations_and_blend_srcs.Add(std::make_pair(location, blend_src))) {
- StringStream err;
- err << "@location(" << location << ") ";
+ auto& err = AddError(location_attribute->source)
+ << 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";
- AddError(err.str(), location_attribute->source);
+ err << style::Plain << " appears multiple times";
return false;
}
}
@@ -2347,9 +2360,9 @@
if (color_attribute) {
uint32_t color = member->Attributes().color.value();
if (!colors.Add(color)) {
- StringStream err;
- err << "@color(" << color << ") appears multiple times";
- AddError(err.str(), color_attribute->source);
+ AddError(color_attribute->source)
+ << style::Attribute << "@color" << style::Code << "(" << style::Literal << color
+ << style::Code << ")" << style::Plain << " appears multiple times";
return false;
}
}
@@ -2363,17 +2376,18 @@
ast::PipelineStage stage,
const Source& source) const {
if (stage == ast::PipelineStage::kCompute) {
- AddError(AttrToStr(attr) + " cannot be used by compute shaders", attr->source);
+ 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("cannot apply @location to declaration of type '" + invalid_type + "'", source);
- AddNote(
- "@location must only be applied to declarations of numeric scalar or numeric vector "
- "type",
- attr->source);
+ 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;
}
@@ -2386,9 +2400,9 @@
const Source& source,
const std::optional<bool> is_input) const {
if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumExperimentalFramebufferFetch)) {
- AddError(
- "use of @color requires enabling extension 'chromium_experimental_framebuffer_fetch'",
- attr->source);
+ AddError(attr->source) << "use of " << style::Attribute << "@color" << style::Plain
+ << " requires enabling extension " << style::Code
+ << "chromium_experimental_framebuffer_fetch";
return false;
}
@@ -2396,16 +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("@color can only be used for fragment shader input", attr->source);
+ 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("cannot apply @color to declaration of type '" + invalid_type + "'", source);
- AddNote(
- "@color must only be applied to declarations of numeric scalar or numeric vector type",
- attr->source);
+ 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;
}
@@ -2416,10 +2432,9 @@
ast::PipelineStage stage,
const std::optional<bool> is_input) const {
if (!enabled_extensions_.Contains(wgsl::Extension::kChromiumInternalDualSourceBlending)) {
- AddError(
- "use of @blend_src requires enabling extension "
- "'chromium_internal_dual_source_blending'",
- attr->source);
+ AddError(attr->source) << "use of " << style::Attribute << "@blend_src" << style::Plain
+ << " requires enabling extension " << style::Code
+ << "chromium_internal_dual_source_blending";
return false;
}
@@ -2427,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(AttrToStr(attr) + " can only be used for fragment shader output", attr->source);
+ AddError(attr->source) << style::Attribute << "@" << attr->Name() << style::Plain
+ << " can only be used for fragment shader output";
return false;
}
@@ -2439,18 +2455,19 @@
const core::type::Type* ret_type,
sem::Statement* current_statement) const {
if (func_type->UnwrapRef() != ret_type) {
- AddError("return statement type must match its function return type, returned '" +
- sem_.TypeNameOf(ret_type) + "', expected '" + sem_.TypeNameOf(func_type) + "'",
- ret->source);
+ AddError(ret->source)
+ << "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;
}
auto* sem = sem_.Get(ret);
if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false, /* stop_at_switch */ false,
current_statement)) {
- AddError("continuing blocks must not contain a return statement", ret->source);
+ AddError(ret->source) << "continuing blocks must not contain a return statement";
if (continuing != sem->Declaration() && continuing != sem->Parent()->Declaration()) {
- AddNote("see continuing block here", continuing->source);
+ AddNote(continuing->source) << "see continuing block here";
}
return false;
}
@@ -2460,16 +2477,15 @@
bool Validator::SwitchStatement(const ast::SwitchStatement* s) {
if (s->body.Length() > kMaxSwitchCaseSelectors) {
- AddError("switch statement has " + std::to_string(s->body.Length()) +
- " case selectors, max is " + std::to_string(kMaxSwitchCaseSelectors),
- s->source);
+ AddError(s->source) << "switch statement has " << s->body.Length()
+ << " case selectors, max is " << kMaxSwitchCaseSelectors;
return false;
}
auto* cond_ty = sem_.TypeOf(s->condition);
if (!cond_ty->is_integer_scalar()) {
- AddError("switch statement selector expression must be of a scalar integer type",
- s->condition->source);
+ AddError(s->condition->source)
+ << "switch statement selector expression must be of a scalar integer type";
return false;
}
@@ -2482,10 +2498,10 @@
if (selector->IsDefault()) {
if (default_selector != nullptr) {
// More than one default clause
- AddError("switch statement must have exactly one default clause",
- selector->Declaration()->source);
+ AddError(selector->Declaration()->source)
+ << "switch statement must have exactly one default clause";
- AddNote("previous default case", default_selector->Declaration()->source);
+ AddNote(default_selector->Declaration()->source) << "previous default case";
return false;
}
default_selector = selector;
@@ -2494,21 +2510,22 @@
auto* decl_ty = selector->Value()->Type();
if (cond_ty != decl_ty) {
- AddError(
- "the case selector values must have the same type as the selector expression.",
- selector->Declaration()->source);
+ AddError(selector->Declaration()->source)
+ << "the case selector values must have the same type as the "
+ "selector expression.";
return false;
}
auto value = selector->Value()->ValueAs<u32>();
if (auto added = selectors.Add(value, selector->Declaration()->source); !added) {
- AddError("duplicate switch case '" +
- (decl_ty->IsAnyOf<core::type::I32, core::type::AbstractNumeric>()
- ? std::to_string(i32(value))
- : std::to_string(value)) +
- "'",
- selector->Declaration()->source);
- AddNote("previous case declared here", added.value);
+ auto& err = AddError(selector->Declaration()->source)
+ << "duplicate switch case " << style::Literal;
+ if (decl_ty->IsAnyOf<core::type::I32, core::type::AbstractNumeric>()) {
+ err << i32(value);
+ } else {
+ err << value;
+ }
+ AddNote(added.value) << "previous case declared here";
return false;
}
}
@@ -2516,7 +2533,7 @@
if (default_selector == nullptr) {
// No default clause
- AddError("switch statement must have a default clause", s->source);
+ AddError(s->source) << "switch statement must have a default clause";
return false;
}
@@ -2543,10 +2560,11 @@
if (!ty->IsConstructible() &&
!ty->IsAnyOf<core::type::Pointer, core::type::Texture, core::type::Sampler,
core::type::AbstractNumeric>()) {
- AddError("cannot assign '" + sem_.TypeNameOf(rhs_ty) +
- "' to '_'. '_' can only be assigned a constructible, pointer, texture or "
- "sampler type",
- rhs->source);
+ 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.
@@ -2559,7 +2577,7 @@
auto* lhs_ref = lhs_ty->As<core::type::Reference>();
if (!lhs_ref) {
// LHS is not a reference, so it has no storage.
- AddError("cannot assign to " + sem_.Describe(lhs_sem), lhs->source);
+ AddError(lhs->source) << "cannot assign to " << sem_.Describe(lhs_sem);
auto* expr = lhs;
while (expr) {
@@ -2571,22 +2589,25 @@
Switch(
user->Variable()->Declaration(), //
[&](const ast::Let* v) {
- AddNote("'let' variables are immutable",
- user->Declaration()->source);
+ AddNote(user->Declaration()->source)
+ << style::Variable << "let" << style::Plain
+ << " variables are immutable";
sem_.NoteDeclarationSource(v);
},
[&](const ast::Const* v) {
- AddNote("'const' variables are immutable",
- user->Declaration()->source);
+ AddNote(user->Declaration()->source)
+ << style::Variable << "const" << style::Plain
+ << " variables are immutable";
sem_.NoteDeclarationSource(v);
},
[&](const ast::Override* v) {
- AddNote("'override' variables are immutable",
- user->Declaration()->source);
+ AddNote(user->Declaration()->source)
+ << style::Variable << "override" << style::Plain
+ << " variables are immutable";
sem_.NoteDeclarationSource(v);
},
[&](const ast::Parameter* v) {
- AddNote("parameters are immutable", user->Declaration()->source);
+ AddNote(user->Declaration()->source) << "parameters are immutable";
sem_.NoteDeclarationSource(v);
});
}
@@ -2602,18 +2623,17 @@
// Value type has to match storage type
if (storage_ty != value_type) {
- AddError(
- "cannot assign '" + sem_.TypeNameOf(rhs_ty) + "' to '" + sem_.TypeNameOf(lhs_ty) + "'",
- a->source);
+ AddError(a->source) << "cannot assign " << style::Type << sem_.TypeNameOf(rhs_ty)
+ << style::Plain << " to " << style::Type << sem_.TypeNameOf(lhs_ty);
return false;
}
if (!storage_ty->IsConstructible()) {
- AddError("storage type of assignment must be constructible", a->source);
+ AddError(a->source) << "storage type of assignment must be constructible";
return false;
}
if (lhs_ref->Access() == core::Access::kRead) {
- AddError("cannot store into a read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'",
- a->source);
+ AddError(a->source) << "cannot store into a read-only type " << style::Type
+ << sem_.RawTypeNameOf(lhs_ty);
return false;
}
return true;
@@ -2626,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(err, lhs->source);
- AddNote("'" + v->name->symbol.Name() + "' is declared here:", v->source);
+ [&](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;
}
}
@@ -2642,18 +2670,20 @@
auto* lhs_ref = lhs_ty->As<core::type::Reference>();
if (!lhs_ref) {
// LHS is not a reference, so it has no storage.
- AddError("cannot modify value of type '" + sem_.TypeNameOf(lhs_ty) + "'", lhs->source);
+ AddError(lhs->source) << "cannot modify value of type " << style::Type
+ << sem_.TypeNameOf(lhs_ty);
return false;
}
if (!lhs_ref->StoreType()->is_integer_scalar()) {
const std::string kind = inc->increment ? "increment" : "decrement";
- AddError(kind + " statement can only be applied to an integer scalar", lhs->source);
+ AddError(lhs->source) << kind << " statement can only be applied to an integer scalar";
return false;
}
if (lhs_ref->Access() == core::Access::kRead) {
- AddError("cannot modify read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'", inc->source);
+ AddError(inc->source) << "cannot modify read-only type " << style::Type
+ << sem_.RawTypeNameOf(lhs_ty);
return false;
}
return true;
@@ -2669,8 +2699,8 @@
} else {
auto added = seen.Add(&d->TypeInfo(), d->source);
if (!added && !d->Is<ast::InternalAttribute>()) {
- AddError("duplicate " + d->Name() + " attribute", d->source);
- AddNote("first attribute declared here", added.value);
+ AddError(d->source) << "duplicate " << d->Name() << " attribute";
+ AddNote(added.value) << "first attribute declared here";
return false;
}
}
@@ -2689,17 +2719,10 @@
auto diag_added = diagnostics.Add(std::make_pair(category, name), dc);
if (!diag_added && diag_added.value->severity != dc->severity) {
- {
- StringStream ss;
- ss << "conflicting diagnostic " << use;
- AddError(ss.str(), dc->rule_name->source);
- }
- {
- StringStream ss;
- ss << "severity of '" << dc->rule_name->String() << "' set to '" << dc->severity
- << "' here";
- AddNote(ss.str(), diag_added.value->rule_name->source);
- }
+ AddError(dc->rule_name->source) << "conflicting diagnostic " << use;
+ AddNote(diag_added.value->rule_name->source)
+ << "severity of " << style::Code << dc->rule_name->String() << style::Plain
+ << " set to " << style::Code << dc->severity << style::Plain << " here";
return false;
}
}
@@ -2733,10 +2756,11 @@
}
void Validator::RaiseArrayWithOverrideCountError(const Source& source) const {
- AddError(
- "array with an 'override' element count can only be used as the store type of a "
- "'var<workgroup>'",
- source);
+ 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 {
@@ -2759,18 +2783,22 @@
for (auto* member : str->Members()) {
using Allowed = std::tuple<core::type::I32, core::type::U32, core::type::F32>;
if (TINT_UNLIKELY(!member->Type()->TypeInfo().IsAnyOfTuple<Allowed>())) {
- AddError(
- "struct members used in the 'pixel_local' address space can only be of "
- "the type 'i32', 'u32' or 'f32'",
- member->Declaration()->source);
- AddNote("struct '" + str->Name().Name() +
- "' used in the 'pixel_local' address space here",
- source);
+ AddError(member->Declaration()->source)
+ << 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("'pixel_local' variable only support struct storage types", source);
+ AddError(source) << style::Enum << "pixel_local" << style::Plain
+ << " variable only support struct storage types";
return false;
}
break;
@@ -2779,18 +2807,19 @@
wgsl::Extension::kChromiumExperimentalPushConstant) &&
IsValidationEnabled(attributes,
ast::DisabledValidation::kIgnoreAddressSpace))) {
- AddError(
- "use of variable address space 'push_constant' requires enabling extension "
- "'chromium_experimental_push_constant'",
- source);
+ 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("access mode 'write' is not valid for the 'storage' address space",
- source);
+ AddError(source) << "access mode " << style::Enum << "write" << style::Plain
+ << " is not valid for the " << style::Enum << "storage"
+ << style::Plain << " address space";
return false;
}
break;
@@ -2798,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(err, source);
- AddNote("atomic sub-type of '" + sem_.TypeNameOf(store_ty) + "' is declared here",
- **atomic_use);
+ if (TINT_UNLIKELY(atomic_error())) {
+ AddNote(**atomic_use)
+ << "atomic sub-type of " << style::Type << sem_.TypeNameOf(store_ty)
+ << style::Plain << " is declared here";
return false;
}
}
@@ -2825,8 +2860,7 @@
return Switch(
store_ty, //
[&](const core::type::Atomic*) {
- if (auto* err = atomic_error()) {
- AddError(err, source);
+ if (TINT_UNLIKELY(atomic_error())) {
return false;
}
return true;
@@ -2855,29 +2889,30 @@
continue;
}
- std::string s{core::ToString(space)};
-
- AddError("entry point '" + ep->Declaration()->name->symbol.Name() +
- "' uses two different '" + s + "' variables.",
- ep->Declaration()->source);
- AddNote("first '" + s + "' variable declaration is here", var->Declaration()->source);
+ AddError(ep->Declaration()->source)
+ << "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("called by function '" + f->Declaration()->name->symbol.Name() + "'",
- f->Declaration()->source);
+ AddNote(f->Declaration()->source) << "called by function " << style::Function
+ << f->Declaration()->name->symbol.Name();
});
- AddNote("called by entry point '" + ep->Declaration()->name->symbol.Name() + "'",
- ep->Declaration()->source);
+ AddNote(ep->Declaration()->source) << "called by entry point " << style::Function
+ << ep->Declaration()->name->symbol.Name();
}
- AddNote("second '" + s + "' variable declaration is here",
- seen_var->Declaration()->source);
+ AddNote(seen_var->Declaration()->source)
+ << "second " << style::Enum << space << style::Plain
+ << " variable declaration is here";
if (seen_func != ep) {
TraverseCallChain(ep, seen_func, [&](const sem::Function* f) {
- AddNote("called by function '" + f->Declaration()->name->symbol.Name() + "'",
- f->Declaration()->source);
+ AddNote(f->Declaration()->source) << "called by function " << style::Function
+ << f->Declaration()->name->symbol.Name();
});
- AddNote("called by entry point '" + ep->Declaration()->name->symbol.Name() + "'",
- ep->Declaration()->source);
+ 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/validator.h b/src/tint/lang/wgsl/resolver/validator.h
index a33b702..0fa3bd9 100644
--- a/src/tint/lang/wgsl/resolver/validator.h
+++ b/src/tint/lang/wgsl/resolver/validator.h
@@ -42,6 +42,7 @@
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/diagnostic/source.h"
#include "src/tint/utils/math/hash.h"
+#include "src/tint/utils/text/styled_text.h"
// Forward declarations
namespace tint::ast {
@@ -125,29 +126,23 @@
Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts);
~Validator();
- /// Adds the given error message to the diagnostics
- /// @param msg the error message
+ /// @returns an error diagnostic
/// @param source the error source
- void AddError(const std::string& msg, const Source& source) const;
+ diag::Diagnostic& AddError(const Source& source) const;
- /// Adds the given warning message to the diagnostics
- /// @param msg the warning message
+ /// @returns an warning diagnostic
/// @param source the warning source
- void AddWarning(const std::string& msg, const Source& source) const;
+ diag::Diagnostic& AddWarning(const Source& source) const;
- /// Adds the given note message to the diagnostics
- /// @param msg the note message
+ /// @returns an note diagnostic
/// @param source the note source
- void AddNote(const std::string& msg, const Source& source) const;
+ diag::Diagnostic& AddNote(const Source& source) const;
- /// Adds the given message to the diagnostics with current severity for the given rule.
+ /// Adds a diagnostic with current severity for the given rule.
/// @param rule the diagnostic trigger rule
- /// @param msg the diagnostic message
/// @param source the diagnostic source
- /// @returns false if the diagnostic is an error for the given trigger rule
- bool AddDiagnostic(wgsl::DiagnosticRule rule,
- const std::string& msg,
- const Source& source) const;
+ /// @returns the diagnostic, if the diagnostic level isn't disabled
+ diag::Diagnostic* MaybeAddDiagnostic(wgsl::DiagnosticRule rule, const Source& source) const;
/// @returns the diagnostic filter stack
DiagnosticFilterStack& DiagnosticFilters() { return diagnostic_filters_; }
diff --git a/src/tint/lang/wgsl/resolver/value_constructor_validation_test.cc b/src/tint/lang/wgsl/resolver/value_constructor_validation_test.cc
index 027b471..0fb486e 100644
--- a/src/tint/lang/wgsl/resolver/value_constructor_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/value_constructor_validation_test.cc
@@ -478,7 +478,8 @@
WrapInFunction(a);
ASSERT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for f32(f32, f32)"));
+ EXPECT_THAT(r()->error(),
+ HasSubstr("12:34 error: no matching constructor for 'f32(f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, ConversionConstructorInvalid_InvalidConstructor) {
@@ -487,7 +488,7 @@
ASSERT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for f32(array<f32, 4>)"));
+ HasSubstr("12:34 error: no matching constructor for 'f32(array<f32, 4>)"));
}
} // namespace ConversionConstructTest
@@ -1062,7 +1063,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(i32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(i32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2F16_Error_ScalarArgumentTypeMismatch) {
@@ -1072,7 +1073,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f16>(f16, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f16>(f16, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2U32_Error_ScalarArgumentTypeMismatch) {
@@ -1080,7 +1081,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<u32>(u32, i32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<u32>(u32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2I32_Error_ScalarArgumentTypeMismatch) {
@@ -1088,7 +1089,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<i32>(u32, i32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<i32>(u32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2Bool_Error_ScalarArgumentTypeMismatch) {
@@ -1096,7 +1097,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<bool>(bool, i32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<bool>(bool, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
@@ -1104,7 +1105,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec3<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(vec3<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
@@ -1112,7 +1113,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec4<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(vec4<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsScalar) {
@@ -1120,7 +1121,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(f32, f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(f32, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsVector) {
@@ -1129,7 +1130,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec2<f32>, vec2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(vec2<f32>, vec2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsVectorAndScalar) {
@@ -1137,7 +1138,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(vec2<f32>, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(vec2<f32>, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_InvalidArgumentType) {
@@ -1145,7 +1146,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(mat2x2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(mat2x2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_ZeroValue) {
@@ -1319,7 +1320,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32, i32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(f32, f32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3F16_Error_ScalarArgumentTypeMismatch) {
@@ -1329,7 +1330,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f16>(f16, f16, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f16>(f16, f16, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3U32_Error_ScalarArgumentTypeMismatch) {
@@ -1337,7 +1338,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<u32>(u32, i32, u32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<u32>(u32, i32, u32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3I32_Error_ScalarArgumentTypeMismatch) {
@@ -1345,15 +1346,16 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<i32>(i32, u32, i32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<i32>(i32, u32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3Bool_Error_ScalarArgumentTypeMismatch) {
WrapInFunction(Call<vec3<bool>>(Source{{12, 34}}, false, 1_i, true));
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<bool>(bool, i32, bool)"));
+ EXPECT_THAT(
+ r()->error(),
+ HasSubstr("12:34 error: no matching constructor for 'vec3<bool>(bool, i32, bool)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
@@ -1361,7 +1363,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec4<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(vec4<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooFewArgumentsScalar) {
@@ -1369,7 +1371,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsScalar) {
@@ -1378,7 +1380,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32, f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(f32, f32, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooFewArgumentsVec2) {
@@ -1386,7 +1388,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(vec2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2) {
@@ -1395,7 +1397,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>, vec2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(vec2<f32>, vec2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2AndScalar) {
@@ -1404,7 +1406,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec2<f32>, f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(vec2<f32>, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec3) {
@@ -1412,7 +1414,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(vec3<f32>, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(vec3<f32>, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_InvalidArgumentType) {
@@ -1420,7 +1422,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(mat2x2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(mat2x2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_ZeroValue) {
@@ -1642,7 +1644,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, i32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(f32, f32, i32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4F16_Error_ScalarArgumentTypeMismatch) {
@@ -1653,7 +1655,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f16>(f16, f16, f32, f16)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f16>(f16, f16, f32, f16)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4U32_Error_ScalarArgumentTypeMismatch) {
@@ -1662,7 +1664,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<u32>(u32, u32, i32, u32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<u32>(u32, u32, i32, u32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4I32_Error_ScalarArgumentTypeMismatch) {
@@ -1671,7 +1673,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<i32>(i32, i32, u32, i32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<i32>(i32, i32, u32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4Bool_Error_ScalarArgumentTypeMismatch) {
@@ -1680,7 +1682,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<bool>(bool, bool, i32, bool)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<bool>(bool, bool, i32, bool)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsScalar) {
@@ -1688,7 +1690,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(f32, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsScalar) {
@@ -1697,7 +1699,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(f32, f32, f32, f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(f32, f32, f32, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsVec2AndScalar) {
@@ -1705,7 +1707,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(vec2<f32>, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndScalars) {
@@ -1714,7 +1716,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, f32, f32, f32)"));
+ HasSubstr(
+ "12:34 error: no matching constructor for 'vec4<f32>(vec2<f32>, f32, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
@@ -1723,7 +1726,8 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec2<f32>, f32)"));
+ HasSubstr(
+ "12:34 error: no matching constructor for 'vec4<f32>(vec2<f32>, vec2<f32>, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
@@ -1731,10 +1735,8 @@
Call<vec4<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), Call<vec2<f32>>(), Call<vec2<f32>>()));
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(
- r()->error(),
- HasSubstr(
- "12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec2<f32>, vec2<f32>)"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for "
+ "'vec4<f32>(vec2<f32>, vec2<f32>, vec2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsVec3) {
@@ -1742,7 +1744,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(vec3<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndScalars) {
@@ -1751,7 +1753,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(vec3<f32>, f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec2) {
@@ -1760,7 +1762,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, vec2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(vec3<f32>, vec2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndVec3) {
@@ -1769,7 +1771,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec2<f32>, vec3<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(vec2<f32>, vec3<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec3) {
@@ -1778,7 +1780,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(vec3<f32>, vec3<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(vec3<f32>, vec3<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_InvalidArgumentType) {
@@ -1786,7 +1788,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec4<f32>(mat2x2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec4<f32>(mat2x2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ZeroValue) {
@@ -1966,7 +1968,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<f32>(f32, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<f32>(f32, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, NestedVectorConstructors_Success) {
@@ -1989,7 +1991,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for vec2<f32>(u32)"));
+ EXPECT_THAT(r()->error(),
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(u32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vector_Alias_Argument_Success) {
@@ -2012,7 +2015,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec2<f32>(f32, u32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec2<f32>(f32, u32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vector_ElementTypeAlias_Success) {
@@ -2035,7 +2038,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("12:34 error: no matching constructor for vec3<u32>(vec2<f32>, f32)"));
+ HasSubstr("12:34 error: no matching constructor for 'vec3<u32>(vec2<f32>, f32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, Vector_ArgumentElementTypeAlias_Success) {
@@ -2339,7 +2342,7 @@
Expr(Source{{1, 3}}, 2_u)));
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("1:1 error: no matching constructor for vec2(i32, u32)"));
+ EXPECT_THAT(r()->error(), HasSubstr("1:1 error: no matching constructor for 'vec2(i32, u32)'"));
}
TEST_F(ResolverValueConstructorValidationTest, CannotInferVec3ElementTypeFromScalarsMismatch) {
@@ -2350,7 +2353,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("1:1 error: no matching constructor for vec3(i32, u32, i32)"));
+ HasSubstr("1:1 error: no matching constructor for 'vec3(i32, u32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest,
@@ -2361,7 +2364,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("1:1 error: no matching constructor for vec3(i32, vec2<f32>)"));
+ HasSubstr("1:1 error: no matching constructor for 'vec3(i32, vec2<f32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, CannotInferVec4ElementTypeFromScalarsMismatch) {
@@ -2373,7 +2376,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("1:1 error: no matching constructor for vec4(i32, i32, f32, i32)"));
+ HasSubstr("1:1 error: no matching constructor for 'vec4(i32, i32, f32, i32)'"));
}
TEST_F(ResolverValueConstructorValidationTest,
@@ -2384,7 +2387,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("1:1 error: no matching constructor for vec4(i32, vec3<u32>)"));
+ HasSubstr("1:1 error: no matching constructor for 'vec4(i32, vec3<u32>)'"));
}
TEST_F(ResolverValueConstructorValidationTest, CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
@@ -2394,7 +2397,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(),
- HasSubstr("1:1 error: no matching constructor for vec4(vec2<i32>, vec2<u32>)"));
+ HasSubstr("1:1 error: no matching constructor for 'vec4(vec2<i32>, vec2<u32>)'"));
}
} // namespace VectorConstructor
@@ -2458,8 +2461,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooFewArguments) {
@@ -2486,8 +2489,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyArguments) {
@@ -2515,8 +2518,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooManyArguments) {
@@ -2543,8 +2546,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ColumnConstructor_Error_InvalidArgumentType) {
@@ -2571,8 +2574,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ElementConstructor_Error_InvalidArgumentType) {
@@ -2598,8 +2601,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewRowsInVectorArgument) {
@@ -2636,8 +2639,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyRowsInVectorArgument) {
@@ -2673,8 +2676,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ZeroValue_Success) {
@@ -2759,8 +2762,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ElementTypeAlias_Success) {
@@ -2794,7 +2797,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(
r()->error(),
- HasSubstr("12:34 error: no matching constructor for mat2x2<f32>(vec2<u32>, vec2<f32>)"));
+ HasSubstr("12:34 error: no matching constructor for 'mat2x2<f32>(vec2<u32>, vec2<f32>)'"));
}
TEST_P(MatrixConstructorTest, ArgumentTypeAlias_Success) {
@@ -2840,8 +2843,8 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
- MatrixStr(param) + "(" + args_tys.str() + ")"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for '" +
+ MatrixStr(param) + "(" + args_tys.str() + ")'"));
}
TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Success) {
@@ -2903,7 +2906,7 @@
Enable(wgsl::Extension::kF16);
StringStream err;
- err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
+ err << "12:34 error: no matching constructor for 'mat" << param.columns << "x" << param.rows
<< "(";
Vector<const ast::Expression*, 8> args;
@@ -2934,7 +2937,7 @@
Enable(wgsl::Extension::kF16);
StringStream err;
- err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
+ err << "12:34 error: no matching constructor for 'mat" << param.columns << "x" << param.rows
<< "(";
Vector<const ast::Expression*, 16> args;
@@ -2951,7 +2954,7 @@
}
}
- err << ")";
+ err << ")'";
auto matrix_type = ty.mat<Infer>(param.columns, param.rows);
WrapInFunction(Call(Source{{12, 34}}, matrix_type, std::move(args)));
diff --git a/src/tint/lang/wgsl/resolver/variable_test.cc b/src/tint/lang/wgsl/resolver/variable_test.cc
index d3d9f10..6f70683 100644
--- a/src/tint/lang/wgsl/resolver/variable_test.cc
+++ b/src/tint/lang/wgsl/resolver/variable_test.cc
@@ -1312,7 +1312,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: variable 'a' does not take template arguments
-56:78 note: var 'a' declared here)");
+56:78 note: 'var a' declared here)");
}
TEST_F(ResolverVariableTest, GlobalConst_UseTemplatedIdent) {
@@ -1330,7 +1330,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: variable 'a' does not take template arguments
-56:78 note: const 'a' declared here)");
+56:78 note: 'const a' declared here)");
}
TEST_F(ResolverVariableTest, GlobalOverride_UseTemplatedIdent) {
@@ -1348,7 +1348,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: variable 'a' does not take template arguments
-56:78 note: override 'a' declared here)");
+56:78 note: 'override a' declared here)");
}
TEST_F(ResolverVariableTest, Param_UseTemplatedIdent) {
@@ -1380,7 +1380,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: variable 'a' does not take template arguments
-56:78 note: var 'a' declared here)");
+56:78 note: 'var a' declared here)");
}
TEST_F(ResolverVariableTest, Let_UseTemplatedIdent) {
@@ -1397,7 +1397,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: variable 'a' does not take template arguments
-56:78 note: let 'a' declared here)");
+56:78 note: 'let a' declared here)");
}
} // namespace
diff --git a/src/tint/lang/wgsl/resolver/variable_validation_test.cc b/src/tint/lang/wgsl/resolver/variable_validation_test.cc
index f333b64..89179ce 100644
--- a/src/tint/lang/wgsl/resolver/variable_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/variable_validation_test.cc
@@ -101,8 +101,8 @@
GlobalVar("b", ty.i32(), core::AddressSpace::kPrivate, Expr(Source{{56, 78}}, "a"));
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(56:78 error: var 'a' cannot be referenced at module-scope
-12:34 note: var 'a' declared here)");
+ EXPECT_EQ(r()->error(), R"(56:78 error: 'var a' cannot be referenced at module-scope
+12:34 note: 'var a' declared here)");
}
TEST_F(ResolverVariableValidationTest, OverrideNoInitializerNoType) {
@@ -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) {
diff --git a/src/tint/lang/wgsl/wgsl.def b/src/tint/lang/wgsl/wgsl.def
index c99f413..b851cdb 100644
--- a/src/tint/lang/wgsl/wgsl.def
+++ b/src/tint/lang/wgsl/wgsl.def
@@ -76,6 +76,8 @@
chromium_experimental_push_constant
// A Chromium-specific extension that adds basic subgroup functionality.
chromium_experimental_subgroups
+ // A Chromium-specific extension that enables features for graphite
+ chromium_internal_graphite
// A Chromium-specific extension that relaxes memory layout requirements for uniform storage.
chromium_internal_relaxed_uniform_layout
// A Chromium-specific extension that enables dual source blending.
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
index 622f73f..8ad212a 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
@@ -338,7 +338,7 @@
void ASTPrinter::EmitImageFormat(StringStream& out, const core::TexelFormat fmt) {
switch (fmt) {
case core::TexelFormat::kUndefined:
- diagnostics_.AddError(diag::System::Writer, "unknown image format");
+ diagnostics_.AddError(diag::System::Writer, Source{}) << "unknown image format";
break;
default:
out << fmt;
diff --git a/src/tint/utils/cli/cli.cc b/src/tint/utils/cli/cli.cc
index b6dc911..6b00638 100644
--- a/src/tint/utils/cli/cli.cc
+++ b/src/tint/utils/cli/cli.cc
@@ -174,8 +174,8 @@
return Failure{err};
}
} else if (!parse_options.ignore_unknown) {
- StringStream err;
- err << "unknown flag: " << arg << std::endl;
+ StyledText err;
+ err << "unknown flag: " << arg << "\n";
auto names = options_by_name.Keys();
auto alternatives =
Transform(names, [&](const std::string& s) { return std::string_view(s); });
@@ -183,7 +183,7 @@
opts.prefix = "--";
opts.list_possible_values = false;
SuggestAlternatives(arg, alternatives.Slice(), err, opts);
- return Failure{err.str()};
+ return Failure{err.Plain()};
}
}
diff --git a/src/tint/utils/diagnostic/BUILD.bazel b/src/tint/utils/diagnostic/BUILD.bazel
index 5cd5f48..568132a 100644
--- a/src/tint/utils/diagnostic/BUILD.bazel
+++ b/src/tint/utils/diagnostic/BUILD.bazel
@@ -41,28 +41,11 @@
srcs = [
"diagnostic.cc",
"formatter.cc",
- "printer.cc",
"source.cc",
- ] + select({
- ":_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_": [
- "printer_other.cc",
- ],
- "//conditions:default": [],
- }) + select({
- ":tint_build_is_linux_or_tint_build_is_mac": [
- "printer_posix.cc",
- ],
- "//conditions:default": [],
- }) + select({
- ":tint_build_is_win": [
- "printer_windows.cc",
- ],
- "//conditions:default": [],
- }),
+ ],
hdrs = [
"diagnostic.h",
"formatter.h",
- "printer.h",
"source.h",
],
deps = [
@@ -84,7 +67,6 @@
srcs = [
"diagnostic_test.cc",
"formatter_test.cc",
- "printer_test.cc",
"source_test.cc",
],
deps = [
@@ -103,50 +85,3 @@
visibility = ["//visibility:public"],
)
-alias(
- name = "tint_build_is_linux",
- actual = "//src/tint:tint_build_is_linux_true",
-)
-
-alias(
- name = "_not_tint_build_is_linux_",
- actual = "//src/tint:tint_build_is_linux_false",
-)
-
-alias(
- name = "tint_build_is_mac",
- actual = "//src/tint:tint_build_is_mac_true",
-)
-
-alias(
- name = "_not_tint_build_is_mac_",
- actual = "//src/tint:tint_build_is_mac_false",
-)
-
-alias(
- name = "tint_build_is_win",
- actual = "//src/tint:tint_build_is_win_true",
-)
-
-alias(
- name = "_not_tint_build_is_win_",
- actual = "//src/tint:tint_build_is_win_false",
-)
-
-selects.config_setting_group(
- name = "tint_build_is_linux_or_tint_build_is_mac",
- match_any = [
- "tint_build_is_linux",
- "tint_build_is_mac",
- ],
-)
-
-selects.config_setting_group(
- name = "_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_",
- match_all = [
- ":_not_tint_build_is_linux_",
- ":_not_tint_build_is_mac_",
- ":_not_tint_build_is_win_",
- ],
-)
-
diff --git a/src/tint/utils/diagnostic/BUILD.cmake b/src/tint/utils/diagnostic/BUILD.cmake
index 37b0742..c0c2bc6 100644
--- a/src/tint/utils/diagnostic/BUILD.cmake
+++ b/src/tint/utils/diagnostic/BUILD.cmake
@@ -43,8 +43,6 @@
utils/diagnostic/diagnostic.h
utils/diagnostic/formatter.cc
utils/diagnostic/formatter.h
- utils/diagnostic/printer.cc
- utils/diagnostic/printer.h
utils/diagnostic/source.cc
utils/diagnostic/source.h
)
@@ -60,24 +58,6 @@
tint_utils_traits
)
-if((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
- tint_target_add_sources(tint_utils_diagnostic lib
- "utils/diagnostic/printer_other.cc"
- )
-endif((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
-
-if(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
- tint_target_add_sources(tint_utils_diagnostic lib
- "utils/diagnostic/printer_posix.cc"
- )
-endif(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
-
-if(TINT_BUILD_IS_WIN)
- tint_target_add_sources(tint_utils_diagnostic lib
- "utils/diagnostic/printer_windows.cc"
- )
-endif(TINT_BUILD_IS_WIN)
-
################################################################################
# Target: tint_utils_diagnostic_test
# Kind: test
@@ -85,7 +65,6 @@
tint_add_target(tint_utils_diagnostic_test test
utils/diagnostic/diagnostic_test.cc
utils/diagnostic/formatter_test.cc
- utils/diagnostic/printer_test.cc
utils/diagnostic/source_test.cc
)
diff --git a/src/tint/utils/diagnostic/BUILD.gn b/src/tint/utils/diagnostic/BUILD.gn
index 4bc6b72..ccb2594 100644
--- a/src/tint/utils/diagnostic/BUILD.gn
+++ b/src/tint/utils/diagnostic/BUILD.gn
@@ -48,8 +48,6 @@
"diagnostic.h",
"formatter.cc",
"formatter.h",
- "printer.cc",
- "printer.h",
"source.cc",
"source.h",
]
@@ -63,25 +61,12 @@
"${tint_src_dir}/utils/text",
"${tint_src_dir}/utils/traits",
]
-
- if (!tint_build_is_linux && !tint_build_is_mac && !tint_build_is_win) {
- sources += [ "printer_other.cc" ]
- }
-
- if (tint_build_is_linux || tint_build_is_mac) {
- sources += [ "printer_posix.cc" ]
- }
-
- if (tint_build_is_win) {
- sources += [ "printer_windows.cc" ]
- }
}
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
sources = [
"diagnostic_test.cc",
"formatter_test.cc",
- "printer_test.cc",
"source_test.cc",
]
deps = [
diff --git a/src/tint/utils/diagnostic/diagnostic.cc b/src/tint/utils/diagnostic/diagnostic.cc
index 404d9fa..2a21caa 100644
--- a/src/tint/utils/diagnostic/diagnostic.cc
+++ b/src/tint/utils/diagnostic/diagnostic.cc
@@ -30,6 +30,7 @@
#include <unordered_map>
#include "src/tint/utils/diagnostic/formatter.h"
+#include "src/tint/utils/text/styled_text.h"
namespace tint::diag {
@@ -69,7 +70,7 @@
std::string List::Str() const {
diag::Formatter::Style style;
style.print_newline_at_end = false;
- return Formatter{style}.Format(*this);
+ return Formatter{style}.Format(*this).Plain();
}
} // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/diagnostic.h b/src/tint/utils/diagnostic/diagnostic.h
index ac5c42a..69f77d2 100644
--- a/src/tint/utils/diagnostic/diagnostic.h
+++ b/src/tint/utils/diagnostic/diagnostic.h
@@ -35,6 +35,7 @@
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/diagnostic/source.h"
+#include "src/tint/utils/text/styled_text.h"
#include "src/tint/utils/traits/traits.h"
namespace tint::diag {
@@ -85,12 +86,19 @@
/// @return this diagnostic
Diagnostic& operator=(const Diagnostic&);
+ /// Appends @p msg to the diagnostic's message
+ template <typename T>
+ Diagnostic& operator<<(T&& msg) {
+ message << std::forward<T>(msg);
+ return *this;
+ }
+
/// severity is the severity of the diagnostic message.
Severity severity = Severity::Error;
/// source is the location of the diagnostic.
Source source;
/// message is the text associated with the diagnostic.
- std::string message;
+ StyledText message;
/// system is the Tint system that raised the diagnostic.
System system;
/// A shared pointer to a Source::File. Only used if the diagnostic Source
@@ -171,80 +179,56 @@
/// Adds the note message with the given Source to the end of this list.
/// @param system the system raising the note message
- /// @param note_msg the note message
/// @param source the source of the note diagnostic
/// @returns a reference to the new diagnostic.
/// @note The returned reference must not be used after the list is mutated again.
- diag::Diagnostic& AddNote(System system, std::string_view note_msg, const Source& source) {
+ diag::Diagnostic& AddNote(System system, const Source& source) {
diag::Diagnostic note{};
note.severity = diag::Severity::Note;
note.system = system;
note.source = source;
- note.message = note_msg;
return Add(std::move(note));
}
/// Adds the warning message with the given Source to the end of this list.
/// @param system the system raising the warning message
- /// @param warning_msg the warning message
/// @param source the source of the warning diagnostic
/// @returns a reference to the new diagnostic.
/// @note The returned reference must not be used after the list is mutated again.
- diag::Diagnostic& AddWarning(System system,
- std::string_view warning_msg,
- const Source& source) {
+ diag::Diagnostic& AddWarning(System system, const Source& source) {
diag::Diagnostic warning{};
warning.severity = diag::Severity::Warning;
warning.system = system;
warning.source = source;
- warning.message = warning_msg;
return Add(std::move(warning));
}
- /// Adds the error message without a source to the end of this list.
- /// @param system the system raising the error message
- /// @param err_msg the error message
- /// @returns a reference to the new diagnostic.
- /// @note The returned reference must not be used after the list is mutated again.
- diag::Diagnostic& AddError(System system, std::string_view err_msg) {
- diag::Diagnostic error{};
- error.severity = diag::Severity::Error;
- error.system = system;
- error.message = err_msg;
- return Add(std::move(error));
- }
-
/// Adds the error message with the given Source to the end of this list.
/// @param system the system raising the error message
- /// @param err_msg the error message
/// @param source the source of the error diagnostic
/// @returns a reference to the new diagnostic.
/// @note The returned reference must not be used after the list is mutated again.
- diag::Diagnostic& AddError(System system, std::string_view err_msg, const Source& source) {
+ diag::Diagnostic& AddError(System system, const Source& source) {
diag::Diagnostic error{};
error.severity = diag::Severity::Error;
error.system = system;
error.source = source;
- error.message = err_msg;
return Add(std::move(error));
}
/// Adds an internal compiler error message to the end of this list.
/// @param system the system raising the error message
- /// @param err_msg the error message
/// @param source the source of the internal compiler error
/// @param file the Source::File owned by this diagnostic
/// @returns a reference to the new diagnostic.
/// @note The returned reference must not be used after the list is mutated again.
diag::Diagnostic& AddIce(System system,
- std::string_view err_msg,
const Source& source,
std::shared_ptr<Source::File> file) {
diag::Diagnostic ice{};
ice.severity = diag::Severity::InternalCompilerError;
ice.system = system;
ice.source = source;
- ice.message = err_msg;
ice.owned_file = std::move(file);
return Add(std::move(ice));
}
diff --git a/src/tint/utils/diagnostic/formatter.cc b/src/tint/utils/diagnostic/formatter.cc
index a256a8a..664c4f8 100644
--- a/src/tint/utils/diagnostic/formatter.cc
+++ b/src/tint/utils/diagnostic/formatter.cc
@@ -33,13 +33,16 @@
#include <vector>
#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/diagnostic/printer.h"
+#include "src/tint/utils/macros/defer.h"
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/text_style.h"
namespace tint::diag {
namespace {
-const char* to_str(Severity severity) {
+const char* ToString(Severity severity) {
switch (severity) {
case Severity::Note:
return "note";
@@ -55,7 +58,7 @@
return "";
}
-std::string to_str(const Source::Location& location) {
+std::string ToString(const Source::Location& location) {
StringStream ss;
if (location.line > 0) {
ss << location.line;
@@ -68,138 +71,84 @@
} // namespace
-/// State holds the internal formatter state for a format() call.
-struct Formatter::State {
- /// Constructs a State associated with the given printer.
- /// @param p the printer to write formatted messages to.
- explicit State(Printer* p) : printer(p) {}
- ~State() { flush(); }
-
- /// SetStyle sets the current style to new_style, flushing any pending messages to the printer
- /// if the style changed.
- /// @param new_style the new style to apply for future written messages.
- void SetStyle(const diag::Style& new_style) {
- if (style.color != new_style.color || style.bold != new_style.bold) {
- flush();
- style = new_style;
- }
- }
-
- /// flush writes any pending messages to the printer, clearing the buffer.
- void flush() {
- auto str = stream.str();
- if (str.length() > 0) {
- printer->Write(str, style);
- StringStream reset;
- stream.swap(reset);
- }
- }
-
- /// operator<< queues msg to be written to the printer.
- /// @param msg the value or string to write to the printer
- /// @returns this State so that calls can be chained
- template <typename T>
- State& operator<<(T&& msg) {
- stream << std::forward<T>(msg);
- return *this;
- }
-
- /// Newline queues a newline to be written to the printer.
- void Newline() { stream << std::endl; }
-
- /// repeat queues the character c to be written to the printer n times.
- /// @param c the character to print `n` times
- /// @param n the number of times to print character `c`
- void repeat(char c, size_t n) { stream.repeat(c, n); }
-
- private:
- Printer* printer;
- diag::Style style;
- StringStream stream;
-};
-
Formatter::Formatter() {}
Formatter::Formatter(const Style& style) : style_(style) {}
-void Formatter::Format(const List& list, Printer* printer) const {
- State state{printer};
+StyledText Formatter::Format(const List& list) const {
+ StyledText text;
bool first = true;
for (auto diag : list) {
- state.SetStyle({});
if (!first) {
- state.Newline();
+ text << "\n";
}
- Format(diag, state);
+ Format(diag, text);
first = false;
}
if (style_.print_newline_at_end) {
- state.Newline();
+ text << "\n";
}
+
+ return text;
}
-void Formatter::Format(const Diagnostic& diag, State& state) const {
+void Formatter::Format(const Diagnostic& diag, StyledText& text) const {
auto const& src = diag.source;
auto const& rng = src.range;
- state.SetStyle({Color::kDefault, true});
+ text << style::Plain;
+ TINT_DEFER(text << style::Plain);
- struct TextAndColor {
+ struct TextAndStyle {
std::string text;
- Color color;
- bool bold = false;
+ TextStyle style = {};
};
- std::vector<TextAndColor> prefix;
- prefix.reserve(6);
+ Vector<TextAndStyle, 6> prefix;
if (style_.print_file && src.file != nullptr) {
if (rng.begin.line > 0) {
- prefix.emplace_back(
- TextAndColor{src.file->path + ":" + to_str(rng.begin), Color::kDefault});
+ prefix.Push(TextAndStyle{src.file->path + ":" + ToString(rng.begin)});
} else {
- prefix.emplace_back(TextAndColor{src.file->path, Color::kDefault});
+ prefix.Push(TextAndStyle{src.file->path});
}
} else if (rng.begin.line > 0) {
- prefix.emplace_back(TextAndColor{to_str(rng.begin), Color::kDefault});
+ prefix.Push(TextAndStyle{ToString(rng.begin)});
}
- Color severity_color = Color::kDefault;
- switch (diag.severity) {
- case Severity::Note:
- break;
- case Severity::Warning:
- severity_color = Color::kYellow;
- break;
- case Severity::Error:
- severity_color = Color::kRed;
- break;
- case Severity::Fatal:
- case Severity::InternalCompilerError:
- severity_color = Color::kMagenta;
- break;
- }
if (style_.print_severity) {
- prefix.emplace_back(TextAndColor{to_str(diag.severity), severity_color, true});
- }
-
- for (size_t i = 0; i < prefix.size(); i++) {
- if (i > 0) {
- state << " ";
+ TextStyle style;
+ switch (diag.severity) {
+ case Severity::Note:
+ break;
+ case Severity::Warning:
+ style = style::Warning + style::Bold;
+ break;
+ case Severity::Error:
+ style = style::Error + style::Bold;
+ break;
+ case Severity::Fatal:
+ case Severity::InternalCompilerError:
+ style = style::Fatal + style::Bold;
+ break;
}
- state.SetStyle({prefix[i].color, prefix[i].bold});
- state << prefix[i].text;
+ prefix.Push(TextAndStyle{ToString(diag.severity), style});
}
- state.SetStyle({Color::kDefault, true});
- if (!prefix.empty()) {
- state << ": ";
+ for (size_t i = 0; i < prefix.Length(); i++) {
+ if (i > 0) {
+ text << " ";
+ }
+ text << prefix[i].style << prefix[i].text;
}
- state << diag.message;
+
+ if (!prefix.IsEmpty()) {
+ text << style::Plain << ": ";
+ }
+ text << style::Bold << diag.message;
if (style_.print_line && src.file && rng.begin.line > 0) {
- state.Newline();
- state.SetStyle({Color::kDefault, false});
+ text << style::Plain << "\n";
for (size_t line_num = rng.begin.line;
(line_num <= rng.end.line) && (line_num <= src.file->content.lines.size());
@@ -210,16 +159,16 @@
bool is_ascii = true;
for (auto c : line) {
if (c == '\t') {
- state.repeat(' ', style_.tab_width);
+ text.Repeat(' ', style_.tab_width);
} else {
- state << c;
+ text << c;
}
if (c & 0x80) {
is_ascii = false;
}
}
- state.Newline();
+ text << style::Plain << "\n";
// If the line contains non-ascii characters, then we cannot assume that
// a single utf8 code unit represents a single glyph, so don't attempt to
@@ -228,7 +177,7 @@
continue;
}
- state.SetStyle({Color::kCyan, false});
+ text << style::Squiggle;
// Count the number of glyphs in the line span.
// start and end use 1-based indexing.
@@ -244,33 +193,24 @@
if (line_num == rng.begin.line && line_num == rng.end.line) {
// Single line
- state.repeat(' ', num_glyphs(1, rng.begin.column));
- state.repeat('^',
- std::max<size_t>(num_glyphs(rng.begin.column, rng.end.column), 1));
+ text.Repeat(' ', num_glyphs(1, rng.begin.column));
+ text.Repeat('^', std::max<size_t>(num_glyphs(rng.begin.column, rng.end.column), 1));
} else if (line_num == rng.begin.line) {
// Start of multi-line
- state.repeat(' ', num_glyphs(1, rng.begin.column));
- state.repeat('^', num_glyphs(rng.begin.column, line_len + 1));
+ text.Repeat(' ', num_glyphs(1, rng.begin.column));
+ text.Repeat('^', num_glyphs(rng.begin.column, line_len + 1));
} else if (line_num == rng.end.line) {
// End of multi-line
- state.repeat('^', num_glyphs(1, rng.end.column));
+ text.Repeat('^', num_glyphs(1, rng.end.column));
} else {
// Middle of multi-line
- state.repeat('^', num_glyphs(1, line_len + 1));
+ text.Repeat('^', num_glyphs(1, line_len + 1));
}
- state.Newline();
+ text << style::Plain << "\n";
}
-
- state.SetStyle({});
}
}
-std::string Formatter::Format(const List& list) const {
- StringPrinter printer;
- Format(list, &printer);
- return printer.str();
-}
-
Formatter::~Formatter() = default;
} // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/formatter.h b/src/tint/utils/diagnostic/formatter.h
index 63da5e2..b744ff6 100644
--- a/src/tint/utils/diagnostic/formatter.h
+++ b/src/tint/utils/diagnostic/formatter.h
@@ -30,12 +30,17 @@
#include <string>
+// Forward declaration
+namespace tint {
+class StyledTextPrinter;
+class StyledText;
+} // namespace tint
namespace tint::diag {
-
class Diagnostic;
class List;
-class Printer;
+} // namespace tint::diag
+namespace tint::diag {
/// Formatter are used to print a list of diagnostics messages.
class Formatter {
public:
@@ -62,18 +67,14 @@
~Formatter();
- /// @param list the list of diagnostic messages to format
- /// @param printer the printer used to display the formatted diagnostics
- void Format(const List& list, Printer* printer) const;
-
/// @return the list of diagnostics `list` formatted to a string.
/// @param list the list of diagnostic messages to format
- std::string Format(const List& list) const;
+ StyledText Format(const List& list) const;
private:
struct State;
- void Format(const Diagnostic& diag, State& state) const;
+ void Format(const Diagnostic& diag, StyledText& text) const;
const Style style_;
};
diff --git a/src/tint/utils/diagnostic/formatter_test.cc b/src/tint/utils/diagnostic/formatter_test.cc
index 44e63dc..6d77367 100644
--- a/src/tint/utils/diagnostic/formatter_test.cc
+++ b/src/tint/utils/diagnostic/formatter_test.cc
@@ -31,6 +31,7 @@
#include "gtest/gtest.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/text/styled_text.h"
namespace tint::diag {
namespace {
@@ -106,7 +107,7 @@
TEST_F(DiagFormatterTest, Simple) {
Formatter fmt{{false, false, false, false}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(1:14: purr
2:14: grrr
3:16: hiss)";
@@ -115,7 +116,7 @@
TEST_F(DiagFormatterTest, SimpleNewlineAtEnd) {
Formatter fmt{{false, false, false, true}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(1:14: purr
2:14: grrr
3:16: hiss
@@ -126,14 +127,14 @@
TEST_F(DiagFormatterTest, SimpleNoSource) {
Formatter fmt{{false, false, false, false}};
auto diag = Diag(Severity::Note, Source{}, "no source!", System::Test);
- auto got = fmt.Format(List{diag});
+ auto got = fmt.Format(List{diag}).Plain();
auto* expect = "no source!";
ASSERT_EQ(expect, got);
}
TEST_F(DiagFormatterTest, WithFile) {
Formatter fmt{{true, false, false, false}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(file.name:1:14: purr
file.name:2:14: grrr
file.name:3:16: hiss)";
@@ -142,7 +143,7 @@
TEST_F(DiagFormatterTest, WithSeverity) {
Formatter fmt{{false, true, false, false}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(1:14 note: purr
2:14 warning: grrr
3:16 error: hiss)";
@@ -151,7 +152,7 @@
TEST_F(DiagFormatterTest, WithLine) {
Formatter fmt{{false, false, true, false}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(1:14: purr
the cat says meow
^
@@ -169,7 +170,7 @@
TEST_F(DiagFormatterTest, UnicodeWithLine) {
Formatter fmt{{false, false, true, false}};
- auto got = fmt.Format(List{utf8_diag_note, utf8_diag_warn, utf8_diag_err});
+ auto got = fmt.Format(List{utf8_diag_note, utf8_diag_warn, utf8_diag_err}).Plain();
auto* expect =
"1:15: purr\n"
"the \xf0\x9f\x90\xb1 says meow\n"
@@ -184,7 +185,7 @@
TEST_F(DiagFormatterTest, BasicWithFileSeverityLine) {
Formatter fmt{{true, true, true, false}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(file.name:1:14 note: purr
the cat says meow
^
@@ -204,7 +205,7 @@
auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
"multiline", System::Test);
Formatter fmt{{false, false, true, false}};
- auto got = fmt.Format(List{multiline});
+ auto got = fmt.Format(List{multiline}).Plain();
auto* expect = R"(2:9: multiline
the dog says woof
^^^^^^^^^^
@@ -220,7 +221,7 @@
auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &utf8_file},
"multiline", System::Test);
Formatter fmt{{false, false, true, false}};
- auto got = fmt.Format(List{multiline});
+ auto got = fmt.Format(List{multiline}).Plain();
auto* expect =
"2:9: multiline\n"
"the \xf0\x9f\x90\x95 says woof\n"
@@ -231,7 +232,7 @@
TEST_F(DiagFormatterTest, BasicWithFileSeverityLineTab4) {
Formatter fmt{{true, true, true, false, 4u}};
- auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+ auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err}).Plain();
auto* expect = R"(file.name:1:14 note: purr
the cat says meow
^
@@ -251,7 +252,7 @@
auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
"multiline", System::Test);
Formatter fmt{{false, false, true, false, 4u}};
- auto got = fmt.Format(List{multiline});
+ auto got = fmt.Format(List{multiline}).Plain();
auto* expect = R"(2:9: multiline
the dog says woof
^^^^^^^^^^^^
@@ -265,7 +266,7 @@
TEST_F(DiagFormatterTest, ICE) {
Formatter fmt{{}};
- auto got = fmt.Format(List{ascii_diag_ice});
+ auto got = fmt.Format(List{ascii_diag_ice}).Plain();
auto* expect = R"(file.name:4:16 internal compiler error: unreachable
the snail says ???
^^^
@@ -276,7 +277,7 @@
TEST_F(DiagFormatterTest, Fatal) {
Formatter fmt{{}};
- auto got = fmt.Format(List{ascii_diag_fatal});
+ auto got = fmt.Format(List{ascii_diag_fatal}).Plain();
auto* expect = R"(file.name:4:16 fatal: nothing
the snail says ???
^^^
@@ -288,8 +289,8 @@
TEST_F(DiagFormatterTest, RangeOOB) {
Formatter fmt{{true, true, true, true}};
diag::List list;
- list.AddError(System::Test, "oob", Source{{{10, 20}, {30, 20}}, &ascii_file});
- auto got = fmt.Format(list);
+ list.AddError(System::Test, Source{{{10, 20}, {30, 20}}, &ascii_file}) << "oob";
+ auto got = fmt.Format(list).Plain();
auto* expect = R"(file.name:10:20 error: oob
)";
diff --git a/src/tint/utils/diagnostic/printer.h b/src/tint/utils/diagnostic/printer.h
deleted file mode 100644
index 2b361b8..0000000
--- a/src/tint/utils/diagnostic/printer.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2020 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef SRC_TINT_UTILS_DIAGNOSTIC_PRINTER_H_
-#define SRC_TINT_UTILS_DIAGNOSTIC_PRINTER_H_
-
-#include <memory>
-#include <sstream>
-#include <string>
-
-namespace tint::diag {
-
-class List;
-
-/// Color is an enumerator of colors used by Style.
-enum class Color {
- kDefault,
- kBlack,
- kRed,
- kGreen,
- kYellow,
- kBlue,
- kMagenta,
- kCyan,
- kWhite,
-};
-
-/// Style describes how a diagnostic message should be printed.
-struct Style {
- /// The foreground text color
- Color color = Color::kDefault;
- /// If true the text will be displayed with a strong weight
- bool bold = false;
-};
-
-/// Printers are used to print formatted diagnostic messages to a stream.
-class Printer {
- public:
- /// @returns a diagnostic Printer
- /// @param out the file to print to.
- /// @param use_colors if true, the printer will use colors if `out` is a terminal and supports
- /// them.
- static std::unique_ptr<Printer> Create(FILE* out, bool use_colors);
-
- virtual ~Printer();
-
- /// writes the string str to the printer with the given style.
- /// @param str the string to write to the printer
- /// @param style the style used to print `str`
- virtual void Write(const std::string& str, const Style& style) = 0;
-};
-
-/// StringPrinter is an implementation of Printer that writes to a std::string.
-class StringPrinter : public Printer {
- public:
- StringPrinter();
- ~StringPrinter() override;
-
- /// @returns the printed string.
- std::string str() const;
-
- void Write(const std::string& str, const Style&) override;
-
- private:
- std::stringstream stream;
-};
-
-} // namespace tint::diag
-
-#endif // SRC_TINT_UTILS_DIAGNOSTIC_PRINTER_H_
diff --git a/src/tint/utils/diagnostic/printer_posix.cc b/src/tint/utils/diagnostic/printer_posix.cc
deleted file mode 100644
index 156c3ce..0000000
--- a/src/tint/utils/diagnostic/printer_posix.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2020 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// GEN_BUILD:CONDITION(tint_build_is_linux || tint_build_is_mac)
-
-#include <unistd.h>
-
-#include <cstring>
-
-#include "src/tint/utils/diagnostic/printer.h"
-
-namespace tint::diag {
-namespace {
-
-bool supports_colors(FILE* f) {
- if (!isatty(fileno(f))) {
- return false;
- }
-
- const char* cterm = getenv("TERM");
- if (cterm == nullptr) {
- return false;
- }
-
- std::string term = getenv("TERM");
- if (term != "cygwin" && term != "linux" && term != "rxvt-unicode-256color" &&
- term != "rxvt-unicode" && term != "screen-256color" && term != "screen" &&
- term != "tmux-256color" && term != "tmux" && term != "xterm-256color" &&
- term != "xterm-color" && term != "xterm") {
- return false;
- }
-
- return true;
-}
-
-class PrinterPosix : public Printer {
- public:
- PrinterPosix(FILE* f, bool colors) : file(f), use_colors(colors && supports_colors(f)) {}
-
- void Write(const std::string& str, const Style& style) override {
- WriteColor(style.color, style.bold);
- fwrite(str.data(), 1, str.size(), file);
- WriteColor(Color::kDefault, false);
- }
-
- private:
- constexpr const char* ColorCode(Color color, bool bold) {
- switch (color) {
- case Color::kDefault:
- return bold ? "\u001b[1m" : "\u001b[0m";
- case Color::kBlack:
- return bold ? "\u001b[30;1m" : "\u001b[30m";
- case Color::kRed:
- return bold ? "\u001b[31;1m" : "\u001b[31m";
- case Color::kGreen:
- return bold ? "\u001b[32;1m" : "\u001b[32m";
- case Color::kYellow:
- return bold ? "\u001b[33;1m" : "\u001b[33m";
- case Color::kBlue:
- return bold ? "\u001b[34;1m" : "\u001b[34m";
- case Color::kMagenta:
- return bold ? "\u001b[35;1m" : "\u001b[35m";
- case Color::kCyan:
- return bold ? "\u001b[36;1m" : "\u001b[36m";
- case Color::kWhite:
- return bold ? "\u001b[37;1m" : "\u001b[37m";
- }
- return ""; // unreachable
- }
-
- void WriteColor(Color color, bool bold) {
- if (use_colors) {
- auto* code = ColorCode(color, bold);
- fwrite(code, 1, strlen(code), file);
- }
- }
-
- FILE* const file;
- const bool use_colors;
-};
-
-} // namespace
-
-std::unique_ptr<Printer> Printer::Create(FILE* out, bool use_colors) {
- return std::make_unique<PrinterPosix>(out, use_colors);
-}
-
-} // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/printer_test.cc b/src/tint/utils/diagnostic/printer_test.cc
deleted file mode 100644
index aeb1fa2..0000000
--- a/src/tint/utils/diagnostic/printer_test.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2020 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "src/tint/utils/diagnostic/printer.h"
-
-#include "gtest/gtest.h"
-
-namespace tint::diag {
-namespace {
-
-// Actually verifying that the expected colors are printed is exceptionally
-// difficult as:
-// a) The color emission varies by OS.
-// b) The logic checks to see if the printer is writing to a terminal, making
-// mocking hard.
-// c) Actually probing what gets written to a FILE* is notoriously tricky.
-//
-// The least we can do is to exersice the code - which is what we do here.
-// The test will print each of the colors, and can be examined with human
-// eyeballs.
-// This can be enabled or disabled with ENABLE_PRINTER_TESTS
-#define ENABLE_PRINTER_TESTS 0
-#if ENABLE_PRINTER_TESTS
-
-using PrinterTest = testing::Test;
-
-TEST_F(PrinterTest, WithColors) {
- auto printer = Printer::Create(stdout, true);
- printer->Write("Default", Style{Color::kDefault, false});
- printer->Write("Black", Style{Color::kBlack, false});
- printer->Write("Red", Style{Color::kRed, false});
- printer->Write("Green", Style{Color::kGreen, false});
- printer->Write("Yellow", Style{Color::kYellow, false});
- printer->Write("Blue", Style{Color::kBlue, false});
- printer->Write("Magenta", Style{Color::kMagenta, false});
- printer->Write("Cyan", Style{Color::kCyan, false});
- printer->Write("White", Style{Color::kWhite, false});
- printf("\n");
-}
-
-TEST_F(PrinterTest, BoldWithColors) {
- auto printer = Printer::Create(stdout, true);
- printer->Write("Default", Style{Color::kDefault, true});
- printer->Write("Black", Style{Color::kBlack, true});
- printer->Write("Red", Style{Color::kRed, true});
- printer->Write("Green", Style{Color::kGreen, true});
- printer->Write("Yellow", Style{Color::kYellow, true});
- printer->Write("Blue", Style{Color::kBlue, true});
- printer->Write("Magenta", Style{Color::kMagenta, true});
- printer->Write("Cyan", Style{Color::kCyan, true});
- printer->Write("White", Style{Color::kWhite, true});
- printf("\n");
-}
-
-TEST_F(PrinterTest, WithoutColors) {
- auto printer = Printer::Create(stdout, false);
- printer->Write("Default", Style{Color::kDefault, false});
- printer->Write("Black", Style{Color::kBlack, false});
- printer->Write("Red", Style{Color::kRed, false});
- printer->Write("Green", Style{Color::kGreen, false});
- printer->Write("Yellow", Style{Color::kYellow, false});
- printer->Write("Blue", Style{Color::kBlue, false});
- printer->Write("Magenta", Style{Color::kMagenta, false});
- printer->Write("Cyan", Style{Color::kCyan, false});
- printer->Write("White", Style{Color::kWhite, false});
- printf("\n");
-}
-
-TEST_F(PrinterTest, BoldWithoutColors) {
- auto printer = Printer::Create(stdout, false);
- printer->Write("Default", Style{Color::kDefault, true});
- printer->Write("Black", Style{Color::kBlack, true});
- printer->Write("Red", Style{Color::kRed, true});
- printer->Write("Green", Style{Color::kGreen, true});
- printer->Write("Yellow", Style{Color::kYellow, true});
- printer->Write("Blue", Style{Color::kBlue, true});
- printer->Write("Magenta", Style{Color::kMagenta, true});
- printer->Write("Cyan", Style{Color::kCyan, true});
- printer->Write("White", Style{Color::kWhite, true});
- printf("\n");
-}
-
-#endif // ENABLE_PRINTER_TESTS
-} // namespace
-} // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/printer_windows.cc b/src/tint/utils/diagnostic/printer_windows.cc
deleted file mode 100644
index 485e9a9..0000000
--- a/src/tint/utils/diagnostic/printer_windows.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2020 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// GEN_BUILD:CONDITION(tint_build_is_win)
-
-#include <cstring>
-
-#include "src/tint/utils/diagnostic/printer.h"
-
-#define WIN32_LEAN_AND_MEAN 1
-#include <Windows.h>
-
-namespace tint::diag {
-namespace {
-
-struct ConsoleInfo {
- HANDLE handle = INVALID_HANDLE_VALUE;
- WORD default_attributes = 0;
- operator bool() const { return handle != INVALID_HANDLE_VALUE; }
-};
-
-ConsoleInfo ConsoleInfoFor(FILE* file) {
- if (file == nullptr) {
- return {};
- }
-
- ConsoleInfo console{};
- if (file == stdout) {
- console.handle = GetStdHandle(STD_OUTPUT_HANDLE);
- } else if (file == stderr) {
- console.handle = GetStdHandle(STD_ERROR_HANDLE);
- } else {
- return {};
- }
-
- CONSOLE_SCREEN_BUFFER_INFO info{};
- if (GetConsoleScreenBufferInfo(console.handle, &info) == 0) {
- return {};
- }
-
- console.default_attributes = info.wAttributes;
- return console;
-}
-
-class PrinterWindows : public Printer {
- public:
- PrinterWindows(FILE* f, bool use_colors)
- : file(f), console(ConsoleInfoFor(use_colors ? f : nullptr)) {}
-
- void Write(const std::string& str, const Style& style) override {
- WriteColor(style.color, style.bold);
- fwrite(str.data(), 1, str.size(), file);
- WriteColor(Color::kDefault, false);
- }
-
- private:
- WORD Attributes(Color color, bool bold) {
- switch (color) {
- case Color::kDefault:
- return console.default_attributes;
- case Color::kBlack:
- return 0;
- case Color::kRed:
- return FOREGROUND_RED | (bold ? FOREGROUND_INTENSITY : 0);
- case Color::kGreen:
- return FOREGROUND_GREEN | (bold ? FOREGROUND_INTENSITY : 0);
- case Color::kYellow:
- return FOREGROUND_RED | FOREGROUND_GREEN | (bold ? FOREGROUND_INTENSITY : 0);
- case Color::kBlue:
- return FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
- case Color::kMagenta:
- return FOREGROUND_RED | FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
- case Color::kCyan:
- return FOREGROUND_GREEN | FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
- case Color::kWhite:
- return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
- (bold ? FOREGROUND_INTENSITY : 0);
- }
- return 0; // unreachable
- }
-
- void WriteColor(Color color, bool bold) {
- if (console) {
- SetConsoleTextAttribute(console.handle, Attributes(color, bold));
- fflush(file);
- }
- }
-
- FILE* const file;
- const ConsoleInfo console;
-};
-
-} // namespace
-
-std::unique_ptr<Printer> Printer::Create(FILE* out, bool use_colors) {
- return std::make_unique<PrinterWindows>(out, use_colors);
-}
-
-} // namespace tint::diag
diff --git a/src/tint/utils/result/result.cc b/src/tint/utils/result/result.cc
index 016e2fb..a3ecfc3 100644
--- a/src/tint/utils/result/result.cc
+++ b/src/tint/utils/result/result.cc
@@ -32,7 +32,7 @@
Failure::Failure() = default;
Failure::Failure(std::string_view err) {
- reason.AddError(diag::System::Unknown, err, Source{});
+ reason.AddError(diag::System::Unknown, Source{}) << err;
}
Failure::Failure(diag::Diagnostic diagnostic) : reason(diag::List{std::move(diagnostic)}) {}
diff --git a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
index c7a8ba5..0308082 100644
--- a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
+++ b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
@@ -285,19 +285,17 @@
{{- end }}
return Build{{$name}}(state, ty{{range .TemplateParams}}, {{.GetName}}{{end}});
},
-/* string */ [](MatchState*{{if .TemplateParams}} state{{end}}) -> std::string {
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
{{- range .TemplateParams }}
{{- template "DeclareLocalTemplateParamName" . }}
{{- end }}
{{- if .DisplayName }}
- StringStream ss;
- ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}};
- return ss.str();
+ out {{range SplitDisplayName .DisplayName}} << style::Type << {{.}}{{end}};
{{- else if .TemplateParams }}
- return "{{.Name}}<"{{template "AppendTemplateParamNames" .TemplateParams}} + ">";
+ out << style::Type << "{{.Name}}" << style::Code << "<"{{template "AppendTemplateParamNames" .TemplateParams}} << style::Code << ">";
{{- else }}
- return "{{.Name}}";
+ out << style::Type << "{{.Name}}";
{{- end }}
}
};
@@ -319,18 +317,15 @@
{{- end }}
return nullptr;
},
-/* string */ [](MatchState*) -> std::string {
- StringStream ss;
- // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
- ss
-{{- range .Types -}}
-{{- if IsFirstIn . $.Types }} << k{{PascalCase .Name}}Matcher.string(nullptr)
-{{- else if IsLastIn . $.Types }} << " or " << k{{PascalCase .Name}}Matcher.string(nullptr)
-{{- else }} << ", " << k{{PascalCase .Name}}Matcher.string(nullptr)
+{{ range .Types -}}
+{{- if IsFirstIn . $.Types }} k{{PascalCase .Name}}Matcher.print(nullptr, out);
+{{- else if IsLastIn . $.Types }} out << TextStyle{} << " or "; k{{PascalCase .Name}}Matcher.print(nullptr, out);
+{{- else }} out << TextStyle{} << ", "; k{{PascalCase .Name}}Matcher.print(nullptr, out);
{{- end -}}
-{{- end -}};
- return ss.str();
+{{- end -}}
}
};
{{ end -}}
@@ -364,15 +359,14 @@
}
},
{{- end }}
-/* string */ [](MatchState*) -> std::string {
- return "
+/* print */ [](MatchState*, StyledText& out) {
+ out
{{- range .Options -}}
-{{- if IsFirstIn . $.Options }}{{.Name}}
-{{- else if IsLastIn . $.Options }} or {{.Name}}
-{{- else }}, {{.Name}}
+{{- if IsFirstIn . $.Options }}<< style::Enum << "{{.Name}}"
+{{- else if IsLastIn . $.Options }}<< TextStyle{} << " or " << style::Enum << "{{.Name}}"
+{{- else }}<< TextStyle{} << ", " << style::Enum << "{{.Name}}"
{{- end -}}
-{{- end -}}
-";
+{{- end -}};
}
};
{{ end -}}
@@ -444,12 +438,13 @@
{{- /* ------------------------------------------------------------------ */ -}}
{{- define "DeclareLocalTemplateParamName" -}}
{{- /* ------------------------------------------------------------------ */ -}}
+ StyledText {{.Name}};
{{- if IsTemplateTypeParam . }}
- const std::string {{.Name}} = state->TypeName();
+ state->PrintType({{.Name}});
{{- else if IsTemplateNumberParam . }}
- const std::string {{.Name}} = state->NumName();
+ state->PrintNum({{.Name}});
{{- else if IsTemplateEnumParam . }}
- const std::string {{.Name}} = state->NumName();
+ state->PrintNum({{.Name}});
{{- end -}}
{{- end -}}
@@ -484,9 +479,9 @@
{{- define "AppendTemplateParamNames" -}}
{{- /* ------------------------------------------------------------------ */ -}}
{{- range $i, $ := . -}}
-{{- if $i }} + ", " + {{.Name}}
-{{- else }} + {{.Name}}
-{{- end -}}
+{{- if $i }} << style::Code << ", " << style::Type << {{.Name}}
+{{- else }} << style::Type << {{.Name}}
+{{- end -}}
{{- end -}}
{{- end -}}
diff --git a/src/tint/utils/text/BUILD.bazel b/src/tint/utils/text/BUILD.bazel
index 21ae073..0e7ee03 100644
--- a/src/tint/utils/text/BUILD.bazel
+++ b/src/tint/utils/text/BUILD.bazel
@@ -42,12 +42,35 @@
"base64.cc",
"string.cc",
"string_stream.cc",
+ "styled_text.cc",
+ "styled_text_printer.cc",
+ "styled_text_printer_ansi.cc",
+ "styled_text_theme.cc",
"unicode.cc",
- ],
+ ] + select({
+ ":_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_": [
+ "styled_text_printer_other.cc",
+ ],
+ "//conditions:default": [],
+ }) + select({
+ ":tint_build_is_linux_or_tint_build_is_mac": [
+ "styled_text_printer_posix.cc",
+ ],
+ "//conditions:default": [],
+ }) + select({
+ ":tint_build_is_win": [
+ "styled_text_printer_windows.cc",
+ ],
+ "//conditions:default": [],
+ }),
hdrs = [
"base64.h",
"string.h",
"string_stream.h",
+ "styled_text.h",
+ "styled_text_printer.h",
+ "styled_text_theme.h",
+ "text_style.h",
"unicode.h",
],
deps = [
@@ -69,6 +92,8 @@
"base64_test.cc",
"string_stream_test.cc",
"string_test.cc",
+ "styled_text_printer_test.cc",
+ "text_style_test.cc",
"unicode_test.cc",
],
deps = [
@@ -86,3 +111,50 @@
visibility = ["//visibility:public"],
)
+alias(
+ name = "tint_build_is_linux",
+ actual = "//src/tint:tint_build_is_linux_true",
+)
+
+alias(
+ name = "_not_tint_build_is_linux_",
+ actual = "//src/tint:tint_build_is_linux_false",
+)
+
+alias(
+ name = "tint_build_is_mac",
+ actual = "//src/tint:tint_build_is_mac_true",
+)
+
+alias(
+ name = "_not_tint_build_is_mac_",
+ actual = "//src/tint:tint_build_is_mac_false",
+)
+
+alias(
+ name = "tint_build_is_win",
+ actual = "//src/tint:tint_build_is_win_true",
+)
+
+alias(
+ name = "_not_tint_build_is_win_",
+ actual = "//src/tint:tint_build_is_win_false",
+)
+
+selects.config_setting_group(
+ name = "tint_build_is_linux_or_tint_build_is_mac",
+ match_any = [
+ "tint_build_is_linux",
+ "tint_build_is_mac",
+ ],
+)
+
+selects.config_setting_group(
+ name = "_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_",
+ match_all = [
+ ":_not_tint_build_is_linux_",
+ ":_not_tint_build_is_mac_",
+ ":_not_tint_build_is_win_",
+ ],
+)
+
diff --git a/src/tint/utils/text/BUILD.cmake b/src/tint/utils/text/BUILD.cmake
index f5f8c10..7b19a11 100644
--- a/src/tint/utils/text/BUILD.cmake
+++ b/src/tint/utils/text/BUILD.cmake
@@ -45,6 +45,14 @@
utils/text/string.h
utils/text/string_stream.cc
utils/text/string_stream.h
+ utils/text/styled_text.cc
+ utils/text/styled_text.h
+ utils/text/styled_text_printer.cc
+ utils/text/styled_text_printer.h
+ utils/text/styled_text_printer_ansi.cc
+ utils/text/styled_text_theme.cc
+ utils/text/styled_text_theme.h
+ utils/text/text_style.h
utils/text/unicode.cc
utils/text/unicode.h
)
@@ -59,6 +67,24 @@
tint_utils_traits
)
+if((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
+ tint_target_add_sources(tint_utils_text lib
+ "utils/text/styled_text_printer_other.cc"
+ )
+endif((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
+
+if(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
+ tint_target_add_sources(tint_utils_text lib
+ "utils/text/styled_text_printer_posix.cc"
+ )
+endif(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
+
+if(TINT_BUILD_IS_WIN)
+ tint_target_add_sources(tint_utils_text lib
+ "utils/text/styled_text_printer_windows.cc"
+ )
+endif(TINT_BUILD_IS_WIN)
+
################################################################################
# Target: tint_utils_text_test
# Kind: test
@@ -67,6 +93,8 @@
utils/text/base64_test.cc
utils/text/string_stream_test.cc
utils/text/string_test.cc
+ utils/text/styled_text_printer_test.cc
+ utils/text/text_style_test.cc
utils/text/unicode_test.cc
)
diff --git a/src/tint/utils/text/BUILD.gn b/src/tint/utils/text/BUILD.gn
index c13c8c0..8aaadd2 100644
--- a/src/tint/utils/text/BUILD.gn
+++ b/src/tint/utils/text/BUILD.gn
@@ -50,6 +50,14 @@
"string.h",
"string_stream.cc",
"string_stream.h",
+ "styled_text.cc",
+ "styled_text.h",
+ "styled_text_printer.cc",
+ "styled_text_printer.h",
+ "styled_text_printer_ansi.cc",
+ "styled_text_theme.cc",
+ "styled_text_theme.h",
+ "text_style.h",
"unicode.cc",
"unicode.h",
]
@@ -62,6 +70,18 @@
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/traits",
]
+
+ if (!tint_build_is_linux && !tint_build_is_mac && !tint_build_is_win) {
+ sources += [ "styled_text_printer_other.cc" ]
+ }
+
+ if (tint_build_is_linux || tint_build_is_mac) {
+ sources += [ "styled_text_printer_posix.cc" ]
+ }
+
+ if (tint_build_is_win) {
+ sources += [ "styled_text_printer_windows.cc" ]
+ }
}
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
@@ -69,6 +89,8 @@
"base64_test.cc",
"string_stream_test.cc",
"string_test.cc",
+ "styled_text_printer_test.cc",
+ "text_style_test.cc",
"unicode_test.cc",
]
deps = [
diff --git a/src/tint/utils/text/string.cc b/src/tint/utils/text/string.cc
index 0812dad..374176e 100644
--- a/src/tint/utils/text/string.cc
+++ b/src/tint/utils/text/string.cc
@@ -30,6 +30,7 @@
#include "src/tint/utils/containers/transform.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/text/string.h"
+#include "src/tint/utils/text/styled_text.h"
namespace tint {
@@ -64,7 +65,7 @@
void SuggestAlternatives(std::string_view got,
Slice<const std::string_view> strings,
- StringStream& ss,
+ StyledText& ss,
const SuggestAlternativeOptions& options /* = {} */) {
// If the string typed was within kSuggestionDistance of one of the possible enum values,
// suggest that. Don't bother with suggestions if the string was extremely long.
diff --git a/src/tint/utils/text/string.h b/src/tint/utils/text/string.h
index 6ae2894..6ccd38d 100644
--- a/src/tint/utils/text/string.h
+++ b/src/tint/utils/text/string.h
@@ -35,6 +35,11 @@
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/text/string_stream.h"
+/// Forward declaration
+namespace tint {
+class StyledText;
+}
+
namespace tint {
/// @param str the string to apply replacements to
@@ -124,7 +129,7 @@
/// @param options options for the suggestion
void SuggestAlternatives(std::string_view got,
Slice<const std::string_view> strings,
- StringStream& ss,
+ StyledText& ss,
const SuggestAlternativeOptions& options = {});
/// @param str the input string
diff --git a/src/tint/utils/text/string_stream.cc b/src/tint/utils/text/string_stream.cc
index 5a6bfa4..269142f 100644
--- a/src/tint/utils/text/string_stream.cc
+++ b/src/tint/utils/text/string_stream.cc
@@ -30,13 +30,28 @@
namespace tint {
StringStream::StringStream() {
+ Reset();
+}
+
+StringStream::StringStream(const StringStream& other) {
+ Reset();
+ sstream_ << other.str();
+}
+
+StringStream::~StringStream() = default;
+
+StringStream& StringStream::operator=(const StringStream& other) {
+ Reset();
+ return *this << other.str();
+}
+
+void StringStream::Reset() {
+ sstream_.clear();
sstream_.flags(sstream_.flags() | std::ios_base::showpoint | std::ios_base::fixed);
sstream_.imbue(std::locale::classic());
sstream_.precision(9);
}
-StringStream::~StringStream() = default;
-
StringStream& operator<<(StringStream& out, CodePoint code_point) {
if (code_point < 0x7f) {
// See https://en.cppreference.com/w/cpp/language/escape
diff --git a/src/tint/utils/text/string_stream.h b/src/tint/utils/text/string_stream.h
index 3de603e..ab96301 100644
--- a/src/tint/utils/text/string_stream.h
+++ b/src/tint/utils/text/string_stream.h
@@ -59,9 +59,14 @@
/// Constructor
StringStream();
+ /// Copy constructor
+ StringStream(const StringStream&);
/// Destructor
~StringStream();
+ /// Copy assignment operator
+ StringStream& operator=(const StringStream&);
+
/// @returns the format flags for the stream
std::ios_base::fmtflags flags() const { return sstream_.flags(); }
@@ -199,6 +204,7 @@
std::string str() const { return sstream_.str(); }
private:
+ void Reset();
std::stringstream sstream_;
};
diff --git a/src/tint/utils/text/string_test.cc b/src/tint/utils/text/string_test.cc
index b14aaac..da6e242 100644
--- a/src/tint/utils/text/string_test.cc
+++ b/src/tint/utils/text/string_test.cc
@@ -29,6 +29,7 @@
#include "gmock/gmock.h"
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/text/styled_text.h"
#include "src/tint/utils/containers/transform.h" // Used by ToStringList()
@@ -95,33 +96,33 @@
TEST(StringTest, SuggestAlternatives) {
{
std::string_view alternatives[] = {"hello world", "Hello World"};
- StringStream ss;
+ StyledText ss;
SuggestAlternatives("hello wordl", alternatives, ss);
- EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'?
+ EXPECT_EQ(ss.Plain(), R"(Did you mean 'hello world'?
Possible values: 'hello world', 'Hello World')");
}
{
std::string_view alternatives[] = {"foobar", "something else"};
- StringStream ss;
+ StyledText ss;
SuggestAlternatives("hello world", alternatives, ss);
- EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')");
+ EXPECT_EQ(ss.Plain(), R"(Possible values: 'foobar', 'something else')");
}
{
std::string_view alternatives[] = {"hello world", "Hello World"};
- StringStream ss;
+ StyledText ss;
SuggestAlternativeOptions opts;
opts.prefix = "$";
SuggestAlternatives("hello wordl", alternatives, ss, opts);
- EXPECT_EQ(ss.str(), R"(Did you mean '$hello world'?
+ EXPECT_EQ(ss.Plain(), R"(Did you mean '$hello world'?
Possible values: '$hello world', '$Hello World')");
}
{
std::string_view alternatives[] = {"hello world", "Hello World"};
- StringStream ss;
+ StyledText ss;
SuggestAlternativeOptions opts;
opts.list_possible_values = false;
SuggestAlternatives("hello world", alternatives, ss, opts);
- EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'?)");
+ EXPECT_EQ(ss.Plain(), R"(Did you mean 'hello world'?)");
}
}
diff --git a/src/tint/utils/text/styled_text.cc b/src/tint/utils/text/styled_text.cc
new file mode 100644
index 0000000..448ecdf
--- /dev/null
+++ b/src/tint/utils/text/styled_text.cc
@@ -0,0 +1,98 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/text/styled_text.h"
+#include <string_view>
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/text_style.h"
+
+namespace tint {
+
+StyledText::StyledText() = default;
+
+StyledText::StyledText(const StyledText&) = default;
+
+StyledText::StyledText(const std::string& text) {
+ stream_ << text;
+}
+
+StyledText::StyledText(std::string_view text) {
+ stream_ << text;
+}
+
+StyledText::StyledText(StyledText&&) = default;
+
+StyledText& StyledText::operator=(const StyledText& other) = default;
+
+StyledText& StyledText::operator=(std::string_view text) {
+ Clear();
+ return *this << text;
+}
+
+void StyledText::Clear() {
+ *this = StyledText{};
+}
+
+StyledText& StyledText::SetStyle(TextStyle style) {
+ if (spans_.Back().style != style) {
+ if (spans_.Back().length == 0) {
+ spans_.Back().style = style;
+ } else {
+ spans_.Push(Span{style});
+ }
+ }
+ return *this;
+}
+
+std::string StyledText::Plain() const {
+ StringStream ss;
+ bool is_code = false;
+ Walk([&](std::string_view text, TextStyle style) {
+ if (is_code != style.IsCode()) {
+ ss << "'";
+ }
+ is_code = style.IsCode();
+
+ ss << text;
+ });
+ if (is_code) {
+ ss << "'";
+ }
+ return ss.str();
+}
+
+void StyledText::Append(const StyledText& other) {
+ other.Walk([&](std::string_view text, TextStyle style) { *this << style << text; });
+}
+
+StyledText& StyledText::Repeat(char c, size_t n) {
+ stream_.repeat(c, n);
+ spans_.Back().length += n;
+ return *this;
+}
+
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text.h b/src/tint/utils/text/styled_text.h
new file mode 100644
index 0000000..f46ced1
--- /dev/null
+++ b/src/tint/utils/text/styled_text.h
@@ -0,0 +1,129 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_TEXT_STYLED_TEXT_H_
+#define SRC_TINT_UTILS_TEXT_STYLED_TEXT_H_
+
+#include <string>
+#include <string_view>
+#include <utility>
+
+#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/text/text_style.h"
+
+// Forward declarations
+namespace tint {
+class StyledTextPrinter;
+}
+
+namespace tint {
+
+/// StyledText is a string builder with support for styled text spans.
+class StyledText {
+ public:
+ /// Constructor - empty string
+ StyledText();
+
+ /// Copy constructor
+ StyledText(const StyledText&);
+
+ /// Constructor from unstyled text
+ explicit StyledText(const std::string&);
+
+ /// Constructor from unstyled text
+ explicit StyledText(std::string_view);
+
+ /// Move constructor
+ StyledText(StyledText&&);
+
+ /// Assignment copy operator
+ StyledText& operator=(const StyledText& other);
+
+ /// Assignment operator from unstyled text
+ StyledText& operator=(std::string_view text);
+
+ /// Clears the text and restore the default style
+ void Clear();
+
+ /// Sets the style for all future writes to this StyledText
+ StyledText& SetStyle(TextStyle style);
+
+ /// @returns the unstyled text.
+ std::string Plain() const;
+
+ /// Appends the styled text of @p other to this StyledText.
+ void Append(const StyledText& other);
+
+ /// repeat queues the character @p c to be written to the StyledText n times.
+ /// @param c the character to print @p n times
+ /// @param n the number of times to print character @p c
+ /// @returns this StyledText so calls can be chained.
+ StyledText& Repeat(char c, size_t n);
+
+ /// operator<<() appends @p value to the StyledText.
+ /// @p value can be a StyledText to change the style of future appends.
+ template <typename VALUE>
+ StyledText& operator<<(VALUE&& value) {
+ using T = std::decay_t<VALUE>;
+ if constexpr (std::is_same_v<T, TextStyle>) {
+ SetStyle(std::forward<VALUE>(value));
+ } else if constexpr (std::is_same_v<T, StyledText>) {
+ Append(value);
+ } else {
+ uint32_t offset = stream_.tellp();
+ stream_ << value;
+ spans_.Back().length += stream_.tellp() - offset;
+ }
+ return *this;
+ }
+
+ /// Walk calls @p callback with each styled span in the StyledText.
+ /// @param callback a function with the signature: void(std::string_view, TextStyle)
+ template <typename CB>
+ void Walk(CB&& callback) const {
+ std::string text = stream_.str();
+ size_t offset = 0;
+ for (auto& span : spans_) {
+ callback(text.substr(offset, span.length), span.style);
+ offset += span.length;
+ }
+ }
+
+ private:
+ struct Span {
+ TextStyle style;
+ size_t length = 0;
+ };
+
+ StringStream stream_;
+ Vector<Span, 1> spans_{Span{}};
+};
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_TEXT_STYLED_TEXT_H_
diff --git a/src/tint/utils/diagnostic/printer_other.cc b/src/tint/utils/text/styled_text_printer.cc
similarity index 69%
rename from src/tint/utils/diagnostic/printer_other.cc
rename to src/tint/utils/text/styled_text_printer.cc
index b311e5a..be83c03 100644
--- a/src/tint/utils/diagnostic/printer_other.cc
+++ b/src/tint/utils/text/styled_text_printer.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Dawn & Tint Authors
+// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
@@ -25,31 +25,35 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION((!tint_build_is_linux) && (!tint_build_is_mac) && (!tint_build_is_win))
-
#include <cstring>
-#include "src/tint/utils/diagnostic/printer.h"
+#include "src/tint/utils/text/styled_text_printer.h"
-namespace tint::diag {
+namespace tint {
namespace {
-class PrinterOther : public Printer {
+class Plain : public StyledTextPrinter {
public:
- explicit PrinterOther(FILE* f) : file(f) {}
+ explicit Plain(FILE* f) : file_(f) {}
- void Write(const std::string& str, const Style&) override {
- fwrite(str.data(), 1, str.size(), file);
+ void Print(const StyledText& text) override {
+ auto plain = text.Plain();
+ fwrite(plain.data(), 1, plain.size(), file_);
}
private:
- FILE* file;
+ FILE* const file_;
};
} // namespace
-std::unique_ptr<Printer> Printer::Create(FILE* out, bool) {
- return std::make_unique<PrinterOther>(out);
+std::unique_ptr<StyledTextPrinter> StyledTextPrinter::CreatePlain(FILE* out) {
+ return std::make_unique<Plain>(out);
+}
+std::unique_ptr<StyledTextPrinter> StyledTextPrinter::Create(FILE* out) {
+ return Create(out, StyledTextTheme::kDefault);
}
-} // namespace tint::diag
+StyledTextPrinter::~StyledTextPrinter() = default;
+
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text_printer.h b/src/tint/utils/text/styled_text_printer.h
new file mode 100644
index 0000000..468d906
--- /dev/null
+++ b/src/tint/utils/text/styled_text_printer.h
@@ -0,0 +1,75 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_TEXT_STYLED_TEXT_PRINTER_H_
+#define SRC_TINT_UTILS_TEXT_STYLED_TEXT_PRINTER_H_
+
+#include <memory>
+#include <string>
+
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/styled_text_theme.h"
+
+/// Forward declarations
+namespace tint {
+class TextStyle;
+}
+
+namespace tint {
+
+/// StyledTextPrinter is the interface for printing text with a style.
+class StyledTextPrinter {
+ public:
+ /// @returns a Printer using the default theme.
+ /// @param out the file to print to.
+ static std::unique_ptr<StyledTextPrinter> Create(FILE* out);
+
+ /// @returns a Printer using the theme @p theme.
+ /// @param out the file to print to.
+ /// @param theme the custom theme to use.
+ static std::unique_ptr<StyledTextPrinter> Create(FILE* out, const StyledTextTheme& theme);
+
+ /// @returns a Printer that emits non-styled text.
+ /// @param out the file to print to.
+ static std::unique_ptr<StyledTextPrinter> CreatePlain(FILE* out);
+
+ /// @returns a Printer that uses ANSI escape sequences and theme @p theme.
+ /// @param out the file to print to.
+ /// @param theme the custom theme to use.
+ static std::unique_ptr<StyledTextPrinter> CreateANSI(FILE* out, const StyledTextTheme& theme);
+
+ /// Destructor
+ virtual ~StyledTextPrinter();
+
+ /// Prints the styled text to the printer.
+ /// @param text the text to print.
+ virtual void Print(const StyledText& text) = 0;
+};
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_TEXT_STYLED_TEXT_PRINTER_H_
diff --git a/src/tint/utils/text/styled_text_printer_ansi.cc b/src/tint/utils/text/styled_text_printer_ansi.cc
new file mode 100644
index 0000000..8a6f39c
--- /dev/null
+++ b/src/tint/utils/text/styled_text_printer_ansi.cc
@@ -0,0 +1,116 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cstring>
+
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/styled_text_theme.h"
+#include "src/tint/utils/text/text_style.h"
+
+namespace tint {
+namespace {
+
+template <typename T>
+bool Equal(const std::optional<T>& lhs, const std::optional<T>& rhs) {
+ if (lhs.has_value() != rhs.has_value()) {
+ return false;
+ }
+ if (!lhs.has_value()) {
+ return true;
+ }
+ return lhs.value() == rhs.value();
+}
+
+#define ESCAPE "\u001b"
+
+class Printer : public StyledTextPrinter {
+ public:
+ Printer(FILE* f, const StyledTextTheme& t) : file_(f), theme_(t) {}
+
+ void Print(const StyledText& style_text) override {
+ StyledTextTheme::Attributes current;
+
+ style_text.Walk([&](std::string_view text, TextStyle text_style) {
+ auto style = theme_.Get(text_style);
+ if (!Equal(current.foreground, style.foreground)) {
+ current.foreground = style.foreground;
+ if (current.foreground.has_value()) {
+ fprintf(file_, ESCAPE "[38;2;%d;%d;%dm", //
+ static_cast<int>(style.foreground->r),
+ static_cast<int>(style.foreground->g),
+ static_cast<int>(style.foreground->b));
+ } else {
+ fprintf(file_, ESCAPE "[39m");
+ }
+ }
+ if (!Equal(current.background, style.background)) {
+ current.background = style.background;
+ if (current.background.has_value()) {
+ fprintf(file_, ESCAPE "[48;2;%d;%d;%dm", //
+ static_cast<int>(style.background->r),
+ static_cast<int>(style.background->g),
+ static_cast<int>(style.background->b));
+ } else {
+ fprintf(file_, ESCAPE "[49m");
+ }
+ }
+ if (!Equal(current.underlined, style.underlined)) {
+ current.underlined = style.underlined;
+ if (current.underlined == true) {
+ fprintf(file_, ESCAPE "[4m");
+ } else {
+ fprintf(file_, ESCAPE "[24m");
+ }
+ }
+ if (!Equal(current.bold, style.bold)) {
+ current.bold = style.bold;
+ if (current.bold == true) {
+ fprintf(file_, ESCAPE "[1m");
+ } else {
+ fprintf(file_, ESCAPE "[22m");
+ }
+ }
+ fwrite(text.data(), 1, text.size(), file_);
+ });
+ fprintf(file_, ESCAPE "[m");
+ fflush(file_);
+ }
+
+ private:
+ FILE* const file_;
+ const StyledTextTheme& theme_;
+};
+
+} // namespace
+
+std::unique_ptr<StyledTextPrinter> StyledTextPrinter::CreateANSI(FILE* out,
+ const StyledTextTheme& theme) {
+ return std::make_unique<Printer>(out, theme);
+}
+
+} // namespace tint
diff --git a/src/tint/utils/diagnostic/printer.cc b/src/tint/utils/text/styled_text_printer_other.cc
similarity index 77%
rename from src/tint/utils/diagnostic/printer.cc
rename to src/tint/utils/text/styled_text_printer_other.cc
index 819dc58..eec09c0 100644
--- a/src/tint/utils/diagnostic/printer.cc
+++ b/src/tint/utils/text/styled_text_printer_other.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Dawn & Tint Authors
+// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
@@ -25,23 +25,16 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "src/tint/utils/diagnostic/printer.h"
+// GEN_BUILD:CONDITION((!tint_build_is_linux) && (!tint_build_is_mac) && (!tint_build_is_win))
-#include <string>
+#include <cstring>
-namespace tint::diag {
+#include "src/tint/utils/text/styled_text_printer.h"
-Printer::~Printer() = default;
+namespace tint {
-StringPrinter::StringPrinter() = default;
-StringPrinter::~StringPrinter() = default;
-
-std::string StringPrinter::str() const {
- return stream.str();
+std::unique_ptr<StyledTextPrinter> StyledTextPrinter::Create(FILE* out, const StyledTextTheme&) {
+ return CreatePlain(out);
}
-void StringPrinter::Write(const std::string& str, const Style&) {
- stream << str;
-}
-
-} // namespace tint::diag
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text_printer_posix.cc b/src/tint/utils/text/styled_text_printer_posix.cc
new file mode 100644
index 0000000..e03ab52
--- /dev/null
+++ b/src/tint/utils/text/styled_text_printer_posix.cc
@@ -0,0 +1,73 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GEN_BUILD:CONDITION(tint_build_is_linux || tint_build_is_mac)
+
+#include <unistd.h>
+
+#include <cstring>
+
+#include "src/tint/utils/text/styled_text.h"
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/styled_text_theme.h"
+#include "src/tint/utils/text/text_style.h"
+
+namespace tint {
+namespace {
+
+bool SupportsANSIEscape(FILE* f) {
+ if (!isatty(fileno(f))) {
+ return false;
+ }
+
+ const char* cterm = getenv("TERM");
+ if (cterm == nullptr) {
+ return false;
+ }
+
+ std::string term = getenv("TERM");
+ if (term != "cygwin" && term != "linux" && term != "rxvt-unicode-256color" &&
+ term != "rxvt-unicode" && term != "screen-256color" && term != "screen" &&
+ term != "tmux-256color" && term != "tmux" && term != "xterm-256color" &&
+ term != "xterm-color" && term != "xterm") {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+std::unique_ptr<StyledTextPrinter> StyledTextPrinter::Create(FILE* out,
+ const StyledTextTheme& theme) {
+ if (SupportsANSIEscape(out)) {
+ return CreateANSI(out, theme);
+ }
+ return CreatePlain(out);
+}
+
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text_printer_test.cc b/src/tint/utils/text/styled_text_printer_test.cc
new file mode 100644
index 0000000..b9e53d3
--- /dev/null
+++ b/src/tint/utils/text/styled_text_printer_test.cc
@@ -0,0 +1,64 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/text/styled_text_printer.h"
+#include "src/tint/utils/text/text_style.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace {
+
+#define ENABLE_PRINTER_TESTS 0 // Print styled text as part of the unit tests
+#if ENABLE_PRINTER_TESTS
+
+using StyledTextPrinterTest = testing::Test;
+
+TEST_F(StyledTextPrinterTest, Themed) {
+ auto printer = StyledTextPrinter::Create(stdout);
+ printer->Print(StyledText{} << style::Plain << "Plain\n"
+ << style::Bold << "Bold\n"
+ << style::Underlined << "Underlined\n"
+ << style::Success << "Success\n"
+ << style::Warning << "Warning\n"
+ << style::Error << "Error\n"
+ << style::Fatal << "Fatal\n"
+ << style::Code << "Code\n"
+ << style::Keyword << "Keyword\n"
+ << style::Variable << "Variable\n"
+ << style::Type << "Type\n"
+ << style::Function << "Function\n"
+ << style::Enum << "Enum\n"
+ << style::Literal << "Literal\n"
+ << style::Attribute << "Attribute\n"
+ << style::Squiggle << "Squiggle\n");
+}
+
+#endif // ENABLE_PRINTER_TESTS
+
+} // namespace
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text_printer_windows.cc b/src/tint/utils/text/styled_text_printer_windows.cc
new file mode 100644
index 0000000..eb5b32b
--- /dev/null
+++ b/src/tint/utils/text/styled_text_printer_windows.cc
@@ -0,0 +1,69 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GEN_BUILD:CONDITION(tint_build_is_win)
+
+#include <cstring>
+
+#include "src/tint/utils/text/styled_text_printer.h"
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <Windows.h>
+
+namespace tint {
+namespace {
+
+HANDLE ConsoleHandleFrom(FILE* file) {
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ if (file == stdout) {
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ } else if (file == stderr) {
+ handle = GetStdHandle(STD_ERROR_HANDLE);
+ } else {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ CONSOLE_SCREEN_BUFFER_INFO info{};
+ if (GetConsoleScreenBufferInfo(handle, &info) == 0) {
+ return INVALID_HANDLE_VALUE;
+ }
+ return handle;
+}
+
+} // namespace
+
+std::unique_ptr<StyledTextPrinter> StyledTextPrinter::Create(FILE* out,
+ const StyledTextTheme& theme) {
+ if (HANDLE handle = ConsoleHandleFrom(out); handle != INVALID_HANDLE_VALUE) {
+ if (SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
+ return CreateANSI(out, theme);
+ }
+ }
+ return CreatePlain(out);
+}
+
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text_theme.cc b/src/tint/utils/text/styled_text_theme.cc
new file mode 100644
index 0000000..ba2944a
--- /dev/null
+++ b/src/tint/utils/text/styled_text_theme.cc
@@ -0,0 +1,215 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/text/styled_text_theme.h"
+#include "src/tint/utils/text/text_style.h"
+
+namespace tint {
+
+const StyledTextTheme StyledTextTheme::kDefault{
+ /* compare_match */ StyledTextTheme::Attributes{
+ /* foreground */ std::nullopt,
+ /* background */ Color{20, 100, 20},
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* compare_mismatch */
+ StyledTextTheme::Attributes{
+ /* foreground */ std::nullopt,
+ /* background */ Color{120, 20, 20},
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* severity_success */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{0, 200, 0},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* severity_warning */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{200, 200, 0},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* severity_failure */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{200, 0, 0},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* severity_fatal */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{200, 0, 200},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_code */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{212, 212, 212},
+ /* background */ Color{43, 43, 43},
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_keyword */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{197, 134, 192},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_variable */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{156, 220, 254},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_type */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{78, 201, 176},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_function */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{220, 220, 170},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_enum */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{79, 193, 255},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_literal */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{181, 206, 168},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_attribute */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{156, 220, 254},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+ /* kind_squiggle */
+ StyledTextTheme::Attributes{
+ /* foreground */ Color{0, 200, 255},
+ /* background */ std::nullopt,
+ /* bold */ std::nullopt,
+ /* underlined */ std::nullopt,
+ },
+};
+
+StyledTextTheme::Attributes StyledTextTheme::Get(TextStyle text_style) const {
+ Attributes out;
+ out.bold = false;
+ out.underlined = false;
+
+ auto apply = [&](const Attributes& in) {
+ if (in.foreground) {
+ out.foreground = in.foreground;
+ }
+ if (in.background) {
+ out.background = in.background;
+ }
+ if (in.bold) {
+ out.bold = in.bold;
+ }
+ if (in.underlined) {
+ out.underlined = in.underlined;
+ }
+ };
+
+ if (text_style.HasSeverity()) {
+ if (text_style.IsSuccess()) {
+ apply(severity_success);
+ } else if (text_style.IsWarning()) {
+ apply(severity_warning);
+ } else if (text_style.IsError()) {
+ apply(severity_failure);
+ } else if (text_style.IsFatal()) {
+ apply(severity_fatal);
+ }
+ }
+
+ if (text_style.HasKind()) {
+ if (text_style.IsCode()) {
+ apply(kind_code);
+
+ if (text_style.IsKeyword()) {
+ apply(kind_keyword);
+ } else if (text_style.IsVariable()) {
+ apply(kind_variable);
+ } else if (text_style.IsType()) {
+ apply(kind_type);
+ } else if (text_style.IsFunction()) {
+ apply(kind_function);
+ } else if (text_style.IsEnum()) {
+ apply(kind_enum);
+ } else if (text_style.IsLiteral()) {
+ apply(kind_literal);
+ } else if (text_style.IsAttribute()) {
+ apply(kind_attribute);
+ }
+ }
+ if (text_style.IsSquiggle()) {
+ apply(kind_squiggle);
+ }
+ }
+
+ if (text_style.HasCompare()) {
+ if (text_style.IsMatch()) {
+ apply(compare_match);
+ } else {
+ apply(compare_mismatch);
+ }
+ }
+
+ if (text_style.IsBold()) {
+ out.bold = true;
+ }
+ if (text_style.IsUnderlined()) {
+ out.underlined = true;
+ }
+
+ return out;
+}
+
+} // namespace tint
diff --git a/src/tint/utils/text/styled_text_theme.h b/src/tint/utils/text/styled_text_theme.h
new file mode 100644
index 0000000..c9dcfbb
--- /dev/null
+++ b/src/tint/utils/text/styled_text_theme.h
@@ -0,0 +1,107 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_TEXT_STYLED_TEXT_THEME_H_
+#define SRC_TINT_UTILS_TEXT_STYLED_TEXT_THEME_H_
+
+#include <stdint.h>
+#include <optional>
+
+/// Forward declarations
+namespace tint {
+class TextStyle;
+}
+
+namespace tint {
+
+/// StyledTextTheme describes the display theming for TextStyles
+struct StyledTextTheme {
+ /// The default theme
+ static const StyledTextTheme kDefault;
+
+ /// Color holds a 24-bit RGB color
+ struct Color {
+ uint8_t r = 0;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ /// Equality operator
+ bool operator==(const Color& other) const {
+ return r == other.r && g == other.g && b == other.b;
+ }
+ };
+
+ /// Attributes holds a number of optional attributes for a style of text.
+ /// Attributes that are std::nullopt do not change the default style.
+ struct Attributes {
+ std::optional<Color> foreground;
+ std::optional<Color> background;
+ std::optional<bool> bold;
+ std::optional<bool> underlined;
+ };
+
+ /// @returns Attributes from the text style @p text_style
+ Attributes Get(TextStyle text_style) const;
+
+ /// The theme's attributes for a compare-match
+ Attributes compare_match;
+ /// The theme's attributes for a compare-mismatch
+ Attributes compare_mismatch;
+
+ /// The theme's attributes for a success severity
+ Attributes severity_success;
+ /// The theme's attributes for a warning severity
+ Attributes severity_warning;
+ /// The theme's attributes for a failure severity
+ Attributes severity_failure;
+ /// The theme's attributes for a fatal severity
+ Attributes severity_fatal;
+
+ /// The theme's attributes for a code text style
+ Attributes kind_code;
+ /// The theme's attributes for a keyword token. This is applied on top #kind_code.
+ Attributes kind_keyword;
+ /// The theme's attributes for a variable token. This is applied on top #kind_code.
+ Attributes kind_variable;
+ /// The theme's attributes for a type token. This is applied on top #kind_code.
+ Attributes kind_type;
+ /// The theme's attributes for a function token. This is applied on top #kind_code.
+ Attributes kind_function;
+ /// The theme's attributes for a enum token. This is applied on top #kind_code.
+ Attributes kind_enum;
+ /// The theme's attributes for a literal token. This is applied on top #kind_code.
+ Attributes kind_literal;
+ /// The theme's attributes for a attribute token. This is applied on top #kind_code.
+ Attributes kind_attribute;
+
+ /// The theme's attributes for a squiggle-highlight.
+ Attributes kind_squiggle;
+};
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_TEXT_STYLED_TEXT_THEME_H_
diff --git a/src/tint/utils/text/text_style.h b/src/tint/utils/text/text_style.h
new file mode 100644
index 0000000..84deef9
--- /dev/null
+++ b/src/tint/utils/text/text_style.h
@@ -0,0 +1,170 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_TEXT_TEXT_STYLE_H_
+#define SRC_TINT_UTILS_TEXT_TEXT_STYLE_H_
+
+#include <cstdint>
+
+#include "src/tint/utils/containers/enum_set.h"
+
+namespace tint {
+
+/// TextStyle is a styling that can be applied to span of a StyledText.
+class TextStyle {
+ public:
+ /// Bits is the integer type used to store the text style.
+ using Bits = uint16_t;
+
+ /// Bit patterns
+
+ static constexpr Bits kStyleMask /* */ = 0b0000'0000'0000'0011;
+ static constexpr Bits kStyleUnderlined /* */ = 0b0000'0000'0000'0001;
+ static constexpr Bits kStyleBold /* */ = 0b0000'0000'0000'0010;
+
+ static constexpr Bits kCompareMask /* */ = 0b0000'0000'0000'1100;
+ static constexpr Bits kCompareMatch /* */ = 0b0000'0000'0000'0100;
+ static constexpr Bits kCompareMismatch /* */ = 0b0000'0000'0000'1000;
+
+ static constexpr Bits kSeverityMask /* */ = 0b0000'0000'1111'0000;
+ static constexpr Bits kSeverityDefault /* */ = 0b0000'0000'0000'0000;
+ static constexpr Bits kSeveritySuccess /* */ = 0b0000'0000'0001'0000;
+ static constexpr Bits kSeverityWarning /* */ = 0b0000'0000'0010'0000;
+ static constexpr Bits kSeverityError /* */ = 0b0000'0000'0011'0000;
+ static constexpr Bits kSeverityFatal /* */ = 0b0000'0000'0100'0000;
+
+ static constexpr Bits kKindMask /* */ = 0b0000'1111'0000'0000;
+ static constexpr Bits kKindCode /* */ = 0b0000'0001'0000'0000;
+ static constexpr Bits kKindKeyword /* */ = 0b0000'0011'0000'0000;
+ static constexpr Bits kKindVariable /* */ = 0b0000'0101'0000'0000;
+ static constexpr Bits kKindType /* */ = 0b0000'0111'0000'0000;
+ static constexpr Bits kKindFunction /* */ = 0b0000'1001'0000'0000;
+ static constexpr Bits kKindEnum /* */ = 0b0000'1011'0000'0000;
+ static constexpr Bits kKindLiteral /* */ = 0b0000'1101'0000'0000;
+ static constexpr Bits kKindAttribute /* */ = 0b0000'1111'0000'0000;
+ static constexpr Bits kKindSquiggle /* */ = 0b0000'0010'0000'0000;
+
+ /// Getters
+
+ bool IsBold() const { return (bits & kStyleBold) != 0; }
+ bool IsUnderlined() const { return (bits & kStyleUnderlined) != 0; }
+
+ bool HasCompare() const { return (bits & kCompareMask) != 0; }
+ bool IsMatch() const { return (bits & kCompareMask) == kCompareMatch; }
+ bool IsMismatch() const { return (bits & kCompareMask) == kCompareMismatch; }
+
+ bool HasSeverity() const { return (bits & kSeverityMask) != 0; }
+ bool IsSuccess() const { return (bits & kSeverityMask) == kSeveritySuccess; }
+ bool IsWarning() const { return (bits & kSeverityMask) == kSeverityWarning; }
+ bool IsError() const { return (bits & kSeverityMask) == kSeverityError; }
+ bool IsFatal() const { return (bits & kSeverityMask) == kSeverityFatal; }
+
+ bool HasKind() const { return (bits & kKindMask) != 0; }
+ bool IsCode() const { return (bits & kKindCode) != 0; }
+ bool IsKeyword() const { return (bits & kKindMask) == kKindKeyword; }
+ bool IsVariable() const { return (bits & kKindMask) == kKindVariable; }
+ bool IsType() const { return (bits & kKindMask) == kKindType; }
+ bool IsFunction() const { return (bits & kKindMask) == kKindFunction; }
+ bool IsEnum() const { return (bits & kKindMask) == kKindEnum; }
+ bool IsLiteral() const { return (bits & kKindMask) == kKindLiteral; }
+ bool IsAttribute() const { return (bits & kKindMask) == kKindAttribute; }
+ bool IsSquiggle() const { return (bits & kKindMask) == kKindSquiggle; }
+
+ /// Equality operator
+ bool operator==(TextStyle other) const { return bits == other.bits; }
+
+ /// Inequality operator
+ bool operator!=(TextStyle other) const { return bits != other.bits; }
+
+ /// @returns the combination of this TextStyle and @p other.
+ /// If both this TextStyle and @p other have a compare style, severity style or kind style, then
+ /// the style collision will resolve by using the style of @p other.
+ TextStyle operator+(TextStyle other) const {
+ Bits out = other.bits;
+ out |= bits & kStyleMask;
+ if (HasCompare() && !other.HasCompare()) {
+ out |= bits & kCompareMask;
+ }
+ if (HasSeverity() && !other.HasSeverity()) {
+ out |= bits & kSeverityMask;
+ }
+ if (HasKind() && !other.HasKind()) {
+ out |= bits & kKindMask;
+ }
+ return TextStyle{out};
+ }
+
+ /// The style bit pattern
+ Bits bits = 0;
+};
+
+} // namespace tint
+
+namespace tint::style {
+
+/// Plain renders text without any styling
+static constexpr TextStyle Plain = TextStyle{};
+/// Bold renders text with a heavy weight
+static constexpr TextStyle Bold = TextStyle{TextStyle::kStyleBold};
+/// Underlined renders text with an underline
+static constexpr TextStyle Underlined = TextStyle{TextStyle::kStyleUnderlined};
+/// Underlined renders text with the compare-match style
+static constexpr TextStyle Match = TextStyle{TextStyle::kCompareMatch};
+/// Underlined renders text with the compare-mismatch style
+static constexpr TextStyle Mismatch = TextStyle{TextStyle::kCompareMismatch};
+/// Success renders text with the styling for a successful status
+static constexpr TextStyle Success = TextStyle{TextStyle::kSeveritySuccess};
+/// Warning renders text with the styling for a warning status
+static constexpr TextStyle Warning = TextStyle{TextStyle::kSeverityWarning};
+/// Error renders text with the styling for a error status
+static constexpr TextStyle Error = TextStyle{TextStyle::kSeverityError};
+/// Fatal renders text with the styling for a fatal status
+static constexpr TextStyle Fatal = TextStyle{TextStyle::kSeverityFatal};
+/// Code renders text with a 'code' style
+static constexpr TextStyle Code = TextStyle{TextStyle::kKindCode};
+/// Keyword renders text with a 'code' style that represents a 'keyword' token
+static constexpr TextStyle Keyword = TextStyle{TextStyle::kKindKeyword};
+/// Variable renders text with a 'code' style that represents a 'variable' token
+static constexpr TextStyle Variable = TextStyle{TextStyle::kKindVariable};
+/// Type renders text with a 'code' style that represents a 'type' token
+static constexpr TextStyle Type = TextStyle{TextStyle::kKindType};
+/// Function renders text with a 'code' style that represents a 'function' token
+static constexpr TextStyle Function = TextStyle{TextStyle::kKindFunction};
+/// Enum renders text with a 'code' style that represents a 'enum' token
+static constexpr TextStyle Enum = TextStyle{TextStyle::kKindEnum};
+/// Literal renders text with a 'code' style that represents a 'literal' token
+static constexpr TextStyle Literal = TextStyle{TextStyle::kKindLiteral};
+/// Attribute renders text with a 'code' style that represents an 'attribute' token
+static constexpr TextStyle Attribute = TextStyle{TextStyle::kKindAttribute};
+/// Squiggle renders text with a squiggle-highlight style (`^^^^^`)
+static constexpr TextStyle Squiggle = TextStyle{TextStyle::kKindSquiggle};
+
+} // namespace tint::style
+
+#endif // SRC_TINT_UTILS_TEXT_TEXT_STYLE_H_
diff --git a/src/tint/utils/text/text_style_test.cc b/src/tint/utils/text/text_style_test.cc
new file mode 100644
index 0000000..41f32b9
--- /dev/null
+++ b/src/tint/utils/text/text_style_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/text/text_style.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace {
+
+using TextStyleTest = testing::Test;
+
+TEST_F(TextStyleTest, Add) {
+ // Plain + X = X
+ EXPECT_EQ(style::Plain + style::Plain, style::Plain);
+ EXPECT_EQ(style::Plain + style::Bold, style::Bold);
+ EXPECT_EQ(style::Plain + style::Underlined, style::Underlined);
+ EXPECT_EQ(style::Plain + style::Success, style::Success);
+ EXPECT_EQ(style::Plain + style::Warning, style::Warning);
+ EXPECT_EQ(style::Plain + style::Error, style::Error);
+ EXPECT_EQ(style::Plain + style::Fatal, style::Fatal);
+ EXPECT_EQ(style::Plain + style::Code, style::Code);
+ EXPECT_EQ(style::Plain + style::Keyword, style::Keyword);
+ EXPECT_EQ(style::Plain + style::Variable, style::Variable);
+ EXPECT_EQ(style::Plain + style::Type, style::Type);
+ EXPECT_EQ(style::Plain + style::Function, style::Function);
+ EXPECT_EQ(style::Plain + style::Enum, style::Enum);
+ EXPECT_EQ(style::Plain + style::Literal, style::Literal);
+ EXPECT_EQ(style::Plain + style::Attribute, style::Attribute);
+ EXPECT_EQ(style::Plain + style::Squiggle, style::Squiggle);
+
+ // Non-colliding combinations
+ EXPECT_EQ(style::Bold + style::Underlined, style::Bold + style::Underlined);
+ EXPECT_EQ(style::Underlined + style::Success, style::Underlined + style::Success);
+ EXPECT_EQ(style::Type + style::Error, style::Type + style::Error);
+ EXPECT_EQ(style::Bold + style::Underlined + style::Variable + style::Squiggle,
+ style::Bold + style::Underlined + style::Variable + style::Squiggle);
+
+ // Colliding combinations resolve to RHS
+ EXPECT_EQ(style::Error + style::Warning, style::Warning);
+ EXPECT_EQ(style::Warning + style::Error, style::Error);
+ EXPECT_EQ(style::Variable + style::Attribute + style::Type, style::Type);
+}
+
+} // namespace
+} // namespace tint