Convert the resolver over to utils::StringStream.

This CL updates the resolver to use utils::StringStream instead of
std::stringstream.

Bug: tint:1686
Change-Id: Ib15a9ae3228757bbddcf787fa9130ca19bc9eab7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121980
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2023-02-28 17:31:54 +00:00 committed by Dawn LUCI CQ
parent e143338f65
commit b23cda4bc2
26 changed files with 205 additions and 159 deletions

View File

@ -44,6 +44,7 @@
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/reverse.h" #include "src/tint/utils/reverse.h"
#include "src/tint/utils/string.h" #include "src/tint/utils/string.h"
#include "src/tint/utils/string_stream.h"
namespace tint::reader::wgsl { namespace tint::reader::wgsl {
namespace { namespace {
@ -911,7 +912,7 @@ Expect<ENUM> ParserImpl::expect_enum(std::string_view name,
} }
/// Create a sensible error message /// Create a sensible error message
std::ostringstream err; utils::StringStream err;
err << "expected " << name; err << "expected " << name;
if (!use.empty()) { if (!use.empty()) {

View File

@ -14,6 +14,7 @@
#include "src/tint/resolver/resolver.h" #include "src/tint/resolver/resolver.h"
#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
@ -196,7 +197,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAliasAnalysisTest,
TwoPointerConfig{builtin::AddressSpace::kPrivate, false}, TwoPointerConfig{builtin::AddressSpace::kPrivate, false},
TwoPointerConfig{builtin::AddressSpace::kPrivate, true}), TwoPointerConfig{builtin::AddressSpace::kPrivate, true}),
[](const ::testing::TestParamInfo<TwoPointers::ParamType>& p) { [](const ::testing::TestParamInfo<TwoPointers::ParamType>& p) {
std::stringstream ss; utils::StringStream ss;
ss << (p.param.aliased ? "Aliased" : "Unaliased") << "_" ss << (p.param.aliased ? "Aliased" : "Unaliased") << "_"
<< p.param.address_space; << p.param.address_space;
return ss.str(); return ss.str();

View File

@ -18,6 +18,7 @@
#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/transform/add_block_attribute.h" #include "src/tint/transform/add_block_attribute.h"
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
@ -1164,7 +1165,7 @@ TEST_P(ArrayStrideTest, All) {
auto& params = GetParam(); auto& params = GetParam();
ast::Type el_ty = params.create_el_type(*this); ast::Type el_ty = params.create_el_type(*this);
std::stringstream ss; utils::StringStream ss;
ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride
<< ", should_pass: " << params.should_pass; << ", should_pass: " << params.should_pass;
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());

View File

@ -38,6 +38,7 @@
#include "src/tint/type/test_helper.h" #include "src/tint/type/test_helper.h"
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/string.h" #include "src/tint/utils/string.h"
#include "src/tint/utils/string_stream.h"
using ::testing::ElementsAre; using ::testing::ElementsAre;
using ::testing::HasSubstr; using ::testing::HasSubstr;
@ -2185,7 +2186,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest,
static std::string to_str(const std::string& function, static std::string to_str(const std::string& function,
utils::VectorRef<const sem::Parameter*> params) { utils::VectorRef<const sem::Parameter*> params) {
std::stringstream out; utils::StringStream out;
out << function << "("; out << function << "(";
bool first = true; bool first = true;
for (auto* param : params) { for (auto* param : params) {

View File

@ -17,6 +17,7 @@
#include "src/tint/ast/builtin_texture_helper_test.h" #include "src/tint/ast/builtin_texture_helper_test.h"
#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/sem/value_constructor.h" #include "src/tint/sem/value_constructor.h"
#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT using namespace tint::number_suffixes; // NOLINT
@ -335,7 +336,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, Immediate) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} else { } else {
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
std::stringstream err; utils::StringStream err;
if (is_vector) { if (is_vector) {
err << "12:34 error: each component of the " << param.name err << "12:34 error: each component of the " << param.name
<< " argument must be at least " << param.min << " and at most " << param.max << " argument must be at least " << param.min << " and at most " << param.max
@ -392,7 +393,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalConst) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} else { } else {
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
std::stringstream err; utils::StringStream err;
if (is_vector) { if (is_vector) {
err << "12:34 error: each component of the " << param.name err << "12:34 error: each component of the " << param.name
<< " argument must be at least " << param.min << " and at most " << param.max << " argument must be at least " << param.min << " and at most " << param.max
@ -442,7 +443,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalVar) {
}); });
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
std::stringstream err; utils::StringStream err;
err << "12:34 error: the " << param.name << " argument must be a const-expression"; err << "12:34 error: the " << param.name << " argument must be a const-expression";
EXPECT_EQ(r()->error(), err.str()); EXPECT_EQ(r()->error(), err.str());
} }

View File

@ -15,6 +15,7 @@
#include "src/tint/ast/call_statement.h" #include "src/tint/ast/call_statement.h"
#include "src/tint/builtin/builtin_value.h" #include "src/tint/builtin/builtin_value.h"
#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT using namespace tint::number_suffixes; // NOLINT
@ -145,7 +146,7 @@ TEST_P(ResolverBuiltinsStageTest, All_input) {
if (params.is_valid) { if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} else { } else {
std::stringstream err; utils::StringStream err;
err << "12:34 error: @builtin(" << params.builtin << ")"; err << "12:34 error: @builtin(" << params.builtin << ")";
err << " cannot be used in input of " << params.stage << " pipeline stage"; err << " cannot be used in input of " << params.stage << " pipeline stage";
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());

View File

@ -44,6 +44,7 @@
#include "src/tint/utils/bitcast.h" #include "src/tint/utils/bitcast.h"
#include "src/tint/utils/compiler_macros.h" #include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h" #include "src/tint/utils/transform.h"
using namespace tint::number_suffixes; // NOLINT using namespace tint::number_suffixes; // NOLINT
@ -184,8 +185,7 @@ auto ZeroTypeDispatch(const type::Type* type, F&& f) {
template <typename NumberT> template <typename NumberT>
std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) { std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) {
std::stringstream ss; utils::StringStream ss;
ss << std::setprecision(20);
ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '" ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '"
<< FriendlyName<NumberT>() << "'"; << FriendlyName<NumberT>() << "'";
return ss.str(); return ss.str();
@ -193,8 +193,7 @@ std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) {
template <typename VALUE_TY> template <typename VALUE_TY>
std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) { std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) {
std::stringstream ss; utils::StringStream ss;
ss << std::setprecision(20);
ss << "value " << value << " cannot be represented as " ss << "value " << value << " cannot be represented as "
<< "'" << target_ty << "'"; << "'" << target_ty << "'";
return ss.str(); return ss.str();
@ -202,8 +201,7 @@ std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) {
template <typename NumberT> template <typename NumberT>
std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) { std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) {
std::stringstream ss; utils::StringStream ss;
ss << std::setprecision(20);
ss << base << "^" << exp << " cannot be represented as " ss << base << "^" << exp << " cannot be represented as "
<< "'" << FriendlyName<NumberT>() << "'"; << "'" << FriendlyName<NumberT>() << "'";
return ss.str(); return ss.str();

View File

@ -1077,7 +1077,15 @@ TEST_F(ResolverConstEvalTest, BinaryAbstractAddOverflow_AFloat) {
GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Highest()), AFloat::Highest())); GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Highest()), AFloat::Highest()));
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(),
"1:1 error: '1.7976931348623157081e+308 + 1.7976931348623157081e+308' cannot be " "1:1 error: "
"'17976931348623157081452742373170435679807056752584499659891747680315726078002853876"
"058955863276687817154045895351438246423432132688946418276846754670353751698604991057"
"655128207624549009038932894407586850845513394230458323690322294816580855933212334827"
"4797826204144723168738177180919299881250404026184124858368.0 + "
"179769313486231570814527423731704356798070567525844996598917476803157260780028538760"
"589558632766878171540458953514382464234321326889464182768467546703537516986049910576"
"551282076245490090389328944075868508455133942304583236903222948165808559332123348274"
"797826204144723168738177180919299881250404026184124858368.0' cannot be "
"represented as 'abstract-float'"); "represented as 'abstract-float'");
} }
@ -1085,7 +1093,16 @@ TEST_F(ResolverConstEvalTest, BinaryAbstractAddUnderflow_AFloat) {
GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Lowest()), AFloat::Lowest())); GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Lowest()), AFloat::Lowest()));
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(),
"1:1 error: '-1.7976931348623157081e+308 + -1.7976931348623157081e+308' cannot be " "1:1 error: "
"'-"
"179769313486231570814527423731704356798070567525844996598917476803157260780028538760"
"589558632766878171540458953514382464234321326889464182768467546703537516986049910576"
"551282076245490090389328944075868508455133942304583236903222948165808559332123348274"
"797826204144723168738177180919299881250404026184124858368.0 + "
"-17976931348623157081452742373170435679807056752584499659891747680315726078002853876"
"058955863276687817154045895351438246423432132688946418276846754670353751698604991057"
"655128207624549009038932894407586850845513394230458323690322294816580855933212334827"
"4797826204144723168738177180919299881250404026184124858368.0' cannot be "
"represented as 'abstract-float'"); "represented as 'abstract-float'");
} }
@ -1584,8 +1601,13 @@ TEST_F(ResolverConstEvalTest, NonShortCircuit_And_Invalid_Materialize) {
GlobalConst("result", binary); GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(
"12:34 error: value 1.7976931348623157081e+308 cannot be represented as 'f32'"); r()->error(),
"12:34 error: value "
"179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558"
"632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245"
"490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168"
"738177180919299881250404026184124858368.000000000 cannot be represented as 'f32'");
} }
TEST_F(ResolverConstEvalTest, ShortCircuit_And_Error_Materialize) { TEST_F(ResolverConstEvalTest, ShortCircuit_And_Error_Materialize) {
@ -1630,8 +1652,13 @@ TEST_F(ResolverConstEvalTest, NonShortCircuit_Or_Invalid_Materialize) {
GlobalConst("result", binary); GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(
"12:34 error: value 1.7976931348623157081e+308 cannot be represented as 'f32'"); r()->error(),
"12:34 error: value "
"179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558"
"632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245"
"490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168"
"738177180919299881250404026184124858368.000000000 cannot be represented as 'f32'");
} }
TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_Materialize) { TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_Materialize) {

View File

@ -2025,9 +2025,11 @@ std::vector<Case> Pack2x16floatCases() {
C({Vec(f32(10), f32(-10.5))}, Val(u32(0xc940'4900))), C({Vec(f32(10), f32(-10.5))}, Val(u32(0xc940'4900))),
E({Vec(f32(0), f32::Highest())}, E({Vec(f32(0), f32::Highest())},
"12:34 error: value 3.4028234663852885981e+38 cannot be represented as 'f16'"), "12:34 error: value 340282346638528859811704183484516925440.000000000 cannot be "
"represented as 'f16'"),
E({Vec(f32::Lowest(), f32(0))}, E({Vec(f32::Lowest(), f32(0))},
"12:34 error: value -3.4028234663852885981e+38 cannot be represented as 'f16'"), "12:34 error: value -340282346638528859811704183484516925440.000000000 cannot be "
"represented as 'f16'"),
}; };
} }
INSTANTIATE_TEST_SUITE_P( // INSTANTIATE_TEST_SUITE_P( //
@ -2848,15 +2850,16 @@ std::vector<Case> QuantizeToF16Cases() {
Vec(0x0.034p-14_f, -0x0.034p-14_f, 0x0.068p-14_f, -0x0.068p-14_f)), Vec(0x0.034p-14_f, -0x0.034p-14_f, 0x0.068p-14_f, -0x0.068p-14_f)),
// Value out of f16 range // Value out of f16 range
E({65504.003_f}, "12:34 error: value 65504.00390625 cannot be represented as 'f16'"), E({65504.003_f}, "12:34 error: value 65504.003906250 cannot be represented as 'f16'"),
E({-65504.003_f}, "12:34 error: value -65504.00390625 cannot be represented as 'f16'"), E({-65504.003_f}, "12:34 error: value -65504.003906250 cannot be represented as 'f16'"),
E({0x1.234p56_f}, "12:34 error: value 81979586966978560 cannot be represented as 'f16'"), E({0x1.234p56_f},
"12:34 error: value 81979586966978560.000000000 cannot be represented as 'f16'"),
E({0x4.321p65_f}, E({0x4.321p65_f},
"12:34 error: value 1.5478871919272394752e+20 cannot be represented as 'f16'"), "12:34 error: value 154788719192723947520.000000000 cannot be represented as 'f16'"),
E({Vec(65504.003_f, 0_f)}, E({Vec(65504.003_f, 0_f)},
"12:34 error: value 65504.00390625 cannot be represented as 'f16'"), "12:34 error: value 65504.003906250 cannot be represented as 'f16'"),
E({Vec(0_f, -0x4.321p65_f)}, E({Vec(0_f, -0x4.321p65_f)},
"12:34 error: value -1.5478871919272394752e+20 cannot be represented as 'f16'"), "12:34 error: value -154788719192723947520.000000000 cannot be represented as 'f16'"),
}; };
} }
INSTANTIATE_TEST_SUITE_P( // INSTANTIATE_TEST_SUITE_P( //

View File

@ -431,7 +431,8 @@ TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_f16) {
WrapInFunction(expr); WrapInFunction(expr);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: value 10000000000 cannot be represented as 'f16'"); EXPECT_EQ(r()->error(),
"12:34 error: value 10000000000.000000000 cannot be represented as 'f16'");
} }
TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) { TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) {

View File

@ -75,7 +75,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_AFloat_Overflow) {
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ( EXPECT_EQ(
error(), error(),
R"(warning: '1.7976931348623157081e+308 + 1.7976931348623157081e+308' cannot be represented as 'abstract-float')"); R"(warning: '179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 + 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_F32_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_F32_Overflow) {
@ -86,7 +86,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_F32_Overflow) {
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ( EXPECT_EQ(
error(), error(),
R"(warning: '3.4028234663852885981e+38 + 3.4028234663852885981e+38' cannot be represented as 'f32')"); R"(warning: '340282346638528859811704183484516925440.0 + 340282346638528859811704183484516925440.0' cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_AInt_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_AInt_Overflow) {
@ -107,7 +107,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_AFloat_Overflow) {
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ( EXPECT_EQ(
error(), error(),
R"(warning: '-1.7976931348623157081e+308 - 1.7976931348623157081e+308' cannot be represented as 'abstract-float')"); R"(warning: '-179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 - 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_F32_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_F32_Overflow) {
@ -118,7 +118,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_F32_Overflow) {
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ( EXPECT_EQ(
error(), error(),
R"(warning: '-3.4028234663852885981e+38 - 3.4028234663852885981e+38' cannot be represented as 'f32')"); R"(warning: '-340282346638528859811704183484516925440.0 - 340282346638528859811704183484516925440.0' cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_AInt_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_AInt_Overflow) {
@ -139,7 +139,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_AFloat_Overflow) {
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ( EXPECT_EQ(
error(), error(),
R"(warning: '1.7976931348623157081e+308 * 1.7976931348623157081e+308' cannot be represented as 'abstract-float')"); R"(warning: '179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 * 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_F32_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_F32_Overflow) {
@ -150,7 +150,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_F32_Overflow) {
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ( EXPECT_EQ(
error(), error(),
R"(warning: '3.4028234663852885981e+38 * 3.4028234663852885981e+38' cannot be represented as 'f32')"); R"(warning: '340282346638528859811704183484516925440.0 * 340282346638528859811704183484516925440.0' cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_AInt_ZeroDenominator) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_AInt_ZeroDenominator) {
@ -186,7 +186,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_AFloat_ZeroDenominator) {
auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {}); auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 42.f); EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 42.f);
EXPECT_EQ(error(), R"(warning: '42 / 0' cannot be represented as 'abstract-float')"); EXPECT_EQ(error(), R"(warning: '42.0 / 0.0' cannot be represented as 'abstract-float')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_F32_ZeroDenominator) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_F32_ZeroDenominator) {
@ -195,7 +195,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_F32_ZeroDenominator) {
auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {}); auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 42.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 42.f);
EXPECT_EQ(error(), R"(warning: '42 / 0' cannot be represented as 'f32')"); EXPECT_EQ(error(), R"(warning: '42.0 / 0.0' cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_I32_MostNegativeByMinInt) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_I32_MostNegativeByMinInt) {
@ -240,7 +240,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_AFloat_ZeroDenominator) {
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {}); auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'abstract-float')"); EXPECT_EQ(error(), R"(warning: '42.0 % 0.0' cannot be represented as 'abstract-float')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_F32_ZeroDenominator) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_F32_ZeroDenominator) {
@ -249,7 +249,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_F32_ZeroDenominator) {
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {}); auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'f32')"); EXPECT_EQ(error(), R"(warning: '42.0 % 0.0' cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_I32_MostNegativeByMinInt) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_I32_MostNegativeByMinInt) {
@ -363,7 +363,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp_F32_Overflow) {
auto result = const_eval.exp(a->Type(), utils::Vector{a}, {}); auto result = const_eval.exp(a->Type(), utils::Vector{a}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(error(), R"(warning: e^1000 cannot be represented as 'f32')"); EXPECT_EQ(error(), R"(warning: e^1000.000000000 cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp2_F32_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp2_F32_Overflow) {
@ -371,7 +371,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp2_F32_Overflow) {
auto result = const_eval.exp2(a->Type(), utils::Vector{a}, {}); auto result = const_eval.exp2(a->Type(), utils::Vector{a}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(error(), R"(warning: 2^1000 cannot be represented as 'f32')"); EXPECT_EQ(error(), R"(warning: 2^1000.000000000 cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, ExtractBits_I32_TooManyBits) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, ExtractBits_I32_TooManyBits) {
@ -476,7 +476,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pack2x16Float_OutOfRange) {
auto result = const_eval.pack2x16float(create<type::U32>(), utils::Vector{vec}, {}); auto result = const_eval.pack2x16float(create<type::U32>(), utils::Vector{vec}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<u32>(), 0x51430000); EXPECT_EQ(result.Get()->ValueAs<u32>(), 0x51430000);
EXPECT_EQ(error(), R"(warning: value 75250 cannot be represented as 'f16')"); EXPECT_EQ(error(), R"(warning: value 75250.000000000 cannot be represented as 'f16')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pow_F32_Overflow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pow_F32_Overflow) {
@ -485,7 +485,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pow_F32_Overflow) {
auto result = const_eval.pow(a->Type(), utils::Vector{a, b}, {}); auto result = const_eval.pow(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f); EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(error(), R"(warning: '2 ^ 1000' cannot be represented as 'f32')"); EXPECT_EQ(error(), R"(warning: '2.0 ^ 1000.0' cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Unpack2x16Float_OutOfRange) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Unpack2x16Float_OutOfRange) {
@ -502,7 +502,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, QuantizeToF16_OutOfRange) {
auto result = const_eval.quantizeToF16(create<type::U32>(), utils::Vector{a}, {}); auto result = const_eval.quantizeToF16(create<type::U32>(), utils::Vector{a}, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<u32>(), 0); EXPECT_EQ(result.Get()->ValueAs<u32>(), 0);
EXPECT_EQ(error(), R"(warning: value 75250 cannot be represented as 'f16')"); EXPECT_EQ(error(), R"(warning: value 75250.000000000 cannot be represented as 'f16')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sqrt_F32_OutOfRange) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sqrt_F32_OutOfRange) {
@ -534,8 +534,9 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooHigh) {
auto result = const_eval.Convert(create<type::F32>(), a, {}); auto result = const_eval.Convert(create<type::F32>(), a, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f32::kHighestValue); EXPECT_EQ(result.Get()->ValueAs<f32>(), f32::kHighestValue);
EXPECT_EQ(error(), EXPECT_EQ(
R"(warning: value 1.7976931348623157081e+308 cannot be represented as 'f32')"); error(),
R"(warning: value 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000000 cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooLow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooLow) {
@ -543,8 +544,9 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooLow) {
auto result = const_eval.Convert(create<type::F32>(), a, {}); auto result = const_eval.Convert(create<type::F32>(), a, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f32::kLowestValue); EXPECT_EQ(result.Get()->ValueAs<f32>(), f32::kLowestValue);
EXPECT_EQ(error(), EXPECT_EQ(
R"(warning: value -1.7976931348623157081e+308 cannot be represented as 'f32')"); error(),
R"(warning: value -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000000 cannot be represented as 'f32')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooHigh) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooHigh) {
@ -552,7 +554,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooHigh) {
auto result = const_eval.Convert(create<type::F16>(), a, {}); auto result = const_eval.Convert(create<type::F16>(), a, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f16::kHighestValue); EXPECT_EQ(result.Get()->ValueAs<f32>(), f16::kHighestValue);
EXPECT_EQ(error(), R"(warning: value 1000000 cannot be represented as 'f16')"); EXPECT_EQ(error(), R"(warning: value 1000000.000000000 cannot be represented as 'f16')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooLow) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooLow) {
@ -560,7 +562,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooLow) {
auto result = const_eval.Convert(create<type::F16>(), a, {}); auto result = const_eval.Convert(create<type::F16>(), a, {});
ASSERT_TRUE(result); ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f16::kLowestValue); EXPECT_EQ(result.Get()->ValueAs<f32>(), f16::kLowestValue);
EXPECT_EQ(error(), R"(warning: value -1000000 cannot be represented as 'f16')"); EXPECT_EQ(error(), R"(warning: value -1000000.000000000 cannot be represented as 'f16')");
} }
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Vec_Overflow_SingleComponent) { TEST_F(ResolverConstEvalRuntimeSemanticsTest, Vec_Overflow_SingleComponent) {

View File

@ -24,6 +24,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/type/test_helper.h" #include "src/tint/type/test_helper.h"
#include "src/tint/utils/string_stream.h"
namespace tint::resolver { namespace tint::resolver {
@ -218,8 +219,7 @@ inline void ConcatIntoIf([[maybe_unused]] Vec& v1, [[maybe_unused]] Vecs&&... vs
/// Returns the overflow error message for binary ops /// Returns the overflow error message for binary ops
template <typename NumberT> template <typename NumberT>
inline std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) { inline std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) {
std::stringstream ss; utils::StringStream ss;
ss << std::setprecision(20);
ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '" ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '"
<< FriendlyName<NumberT>() << "'"; << FriendlyName<NumberT>() << "'";
return ss.str(); return ss.str();
@ -228,8 +228,7 @@ inline std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs
/// Returns the overflow error message for conversions /// Returns the overflow error message for conversions
template <typename VALUE_TY> template <typename VALUE_TY>
std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) { std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) {
std::stringstream ss; utils::StringStream ss;
ss << std::setprecision(20);
ss << "value " << value << " cannot be represented as " ss << "value " << value << " cannot be represented as "
<< "'" << target_ty << "'"; << "'" << target_ty << "'";
return ss.str(); return ss.str();
@ -238,8 +237,7 @@ std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) {
/// Returns the overflow error message for exponentiation /// Returns the overflow error message for exponentiation
template <typename NumberT> template <typename NumberT>
std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) { std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) {
std::stringstream ss; utils::StringStream ss;
ss << std::setprecision(20);
ss << base << "^" << exp << " cannot be represented as " ss << base << "^" << exp << " cannot be represented as "
<< "'" << FriendlyName<NumberT>() << "'"; << "'" << FriendlyName<NumberT>() << "'";
return ss.str(); return ss.str();

View File

@ -65,6 +65,7 @@
#include "src/tint/utils/defer.h" #include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/unique_vector.h" #include "src/tint/utils/unique_vector.h"
#define TINT_DUMP_DEPENDENCY_GRAPH 0 #define TINT_DUMP_DEPENDENCY_GRAPH 0
@ -711,7 +712,7 @@ struct DependencyAnalysis {
/// found in `stack`. /// found in `stack`.
/// @param stack is the global dependency stack that contains a loop. /// @param stack is the global dependency stack that contains a loop.
void CyclicDependencyFound(const Global* root, utils::VectorRef<const Global*> stack) { void CyclicDependencyFound(const Global* root, utils::VectorRef<const Global*> stack) {
std::stringstream msg; utils::StringStream msg;
msg << "cyclic dependency found: "; msg << "cyclic dependency found: ";
constexpr size_t kLoopNotStarted = ~0u; constexpr size_t kLoopNotStarted = ~0u;
size_t loop_start = kLoopNotStarted; size_t loop_start = kLoopNotStarted;

View File

@ -18,6 +18,7 @@
#include "src/tint/builtin/builtin_value.h" #include "src/tint/builtin/builtin_value.h"
#include "src/tint/resolver/resolver.h" #include "src/tint/resolver/resolver.h"
#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
@ -1054,7 +1055,7 @@ TEST_P(ResolverFunctionParameterValidationTest, AddressSpaceNoExtension) {
if (param.expectation == Expectation::kAlwaysPass) { if (param.expectation == Expectation::kAlwaysPass) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
} else { } else {
std::stringstream ss; utils::StringStream ss;
ss << param.address_space; ss << param.address_space;
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
if (param.expectation == Expectation::kInvalid) { if (param.expectation == Expectation::kInvalid) {

View File

@ -39,6 +39,7 @@
#include "src/tint/utils/hashmap.h" #include "src/tint/utils/hashmap.h"
#include "src/tint/utils/math.h" #include "src/tint/utils/math.h"
#include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string_stream.h"
namespace tint::resolver { namespace tint::resolver {
namespace { namespace {
@ -1202,12 +1203,12 @@ class Impl : public IntrinsicTable {
sem::EvaluationStage earliest_eval_stage) const; sem::EvaluationStage earliest_eval_stage) const;
// Prints the overload for emitting diagnostics // Prints the overload for emitting diagnostics
void PrintOverload(std::ostream& ss, void PrintOverload(utils::StringStream& ss,
const OverloadInfo* overload, const OverloadInfo* overload,
const char* intrinsic_name) const; const char* intrinsic_name) const;
// Prints the list of candidates for emitting diagnostics // Prints the list of candidates for emitting diagnostics
void PrintCandidates(std::ostream& ss, void PrintCandidates(utils::StringStream& ss,
utils::VectorRef<Candidate> candidates, utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const; const char* intrinsic_name) const;
@ -1232,7 +1233,7 @@ std::string CallSignature(ProgramBuilder& builder,
const char* intrinsic_name, const char* intrinsic_name,
utils::VectorRef<const type::Type*> args, utils::VectorRef<const type::Type*> args,
const type::Type* template_arg = nullptr) { const type::Type* template_arg = nullptr) {
std::stringstream ss; utils::StringStream ss;
ss << intrinsic_name; ss << intrinsic_name;
if (template_arg) { if (template_arg) {
ss << "<" << template_arg->FriendlyName(builder.Symbols()) << ">"; ss << "<" << template_arg->FriendlyName(builder.Symbols()) << ">";
@ -1271,7 +1272,7 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
// Generates an error when no overloads match the provided arguments // Generates an error when no overloads match the provided arguments
auto on_no_match = [&](utils::VectorRef<Candidate> candidates) { auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
std::stringstream ss; utils::StringStream ss;
ss << "no matching call to " << CallSignature(builder, intrinsic_name, args) << std::endl; ss << "no matching call to " << CallSignature(builder, intrinsic_name, args) << std::endl;
if (!candidates.IsEmpty()) { if (!candidates.IsEmpty()) {
ss << std::endl ss << std::endl
@ -1340,7 +1341,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
// Generates an error when no overloads match the provided arguments // Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) { auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) {
std::stringstream ss; utils::StringStream ss;
ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl; ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl;
if (!candidates.IsEmpty()) { if (!candidates.IsEmpty()) {
ss << std::endl ss << std::endl
@ -1418,7 +1419,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
// Generates an error when no overloads match the provided arguments // Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) { auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) {
std::stringstream ss; utils::StringStream ss;
ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl; ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl;
if (!candidates.IsEmpty()) { if (!candidates.IsEmpty()) {
ss << std::endl ss << std::endl
@ -1453,7 +1454,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
// Generates an error when no overloads match the provided arguments // Generates an error when no overloads match the provided arguments
auto on_no_match = [&](utils::VectorRef<Candidate> candidates) { auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
std::stringstream ss; utils::StringStream ss;
ss << "no matching constructor for " << CallSignature(builder, name, args, template_arg) ss << "no matching constructor for " << CallSignature(builder, name, args, template_arg)
<< std::endl; << std::endl;
Candidates ctor, conv; Candidates ctor, conv;
@ -1755,7 +1756,7 @@ MatchState Impl::Match(TemplateState& templates,
return MatchState(builder, templates, matchers, overload, matcher_indices, earliest_eval_stage); return MatchState(builder, templates, matchers, overload, matcher_indices, earliest_eval_stage);
} }
void Impl::PrintOverload(std::ostream& ss, void Impl::PrintOverload(utils::StringStream& ss,
const OverloadInfo* overload, const OverloadInfo* overload,
const char* intrinsic_name) const { const char* intrinsic_name) const {
TemplateState templates; TemplateState templates;
@ -1827,7 +1828,7 @@ void Impl::PrintOverload(std::ostream& ss,
} }
} }
void Impl::PrintCandidates(std::ostream& ss, void Impl::PrintCandidates(utils::StringStream& ss,
utils::VectorRef<Candidate> candidates, utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const { const char* intrinsic_name) const {
for (auto& candidate : candidates) { for (auto& candidate : candidates) {
@ -1865,7 +1866,7 @@ void Impl::ErrAmbiguousOverload(const char* intrinsic_name,
utils::VectorRef<const type::Type*> args, utils::VectorRef<const type::Type*> args,
TemplateState templates, TemplateState templates,
utils::VectorRef<Candidate> candidates) const { utils::VectorRef<Candidate> candidates) const {
std::stringstream ss; utils::StringStream ss;
ss << "ambiguous overload while attempting to match " << intrinsic_name; ss << "ambiguous overload while attempting to match " << intrinsic_name;
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) { for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
if (auto* ty = templates.Type(i)) { if (auto* ty = templates.Type(i)) {

View File

@ -71,7 +71,7 @@ const type::Type* Ia::Match(MatchState& state, const type::Type* ty) const {
} }
std::string Ia::String(MatchState*) const { std::string Ia::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
ss << "abstract-int"; ss << "abstract-int";
return ss.str(); return ss.str();
} }
@ -99,7 +99,7 @@ const type::Type* Fa::Match(MatchState& state, const type::Type* ty) const {
} }
std::string Fa::String(MatchState*) const { std::string Fa::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
ss << "abstract-float"; ss << "abstract-float";
return ss.str(); return ss.str();
} }
@ -627,7 +627,7 @@ const type::Type* Vec::Match(MatchState& state, const type::Type* ty) const {
std::string Vec::String(MatchState* state) const { std::string Vec::String(MatchState* state) const {
const std::string N = state->NumName(); const std::string N = state->NumName();
const std::string T = state->TypeName(); const std::string T = state->TypeName();
std::stringstream ss; utils::StringStream ss;
ss << "vec" << N << "<" << T << ">"; ss << "vec" << N << "<" << T << ">";
return ss.str(); return ss.str();
} }
@ -673,7 +673,7 @@ std::string Mat::String(MatchState* state) const {
const std::string N = state->NumName(); const std::string N = state->NumName();
const std::string M = state->NumName(); const std::string M = state->NumName();
const std::string T = state->TypeName(); const std::string T = state->TypeName();
std::stringstream ss; utils::StringStream ss;
ss << "mat" << N << "x" << M << "<" << T << ">"; ss << "mat" << N << "x" << M << "<" << T << ">";
return ss.str(); return ss.str();
} }
@ -1431,7 +1431,7 @@ const type::Type* ModfResult::Match(MatchState& state, const type::Type* ty) con
std::string ModfResult::String(MatchState* state) const { std::string ModfResult::String(MatchState* state) const {
const std::string T = state->TypeName(); const std::string T = state->TypeName();
std::stringstream ss; utils::StringStream ss;
ss << "__modf_result_" << T; ss << "__modf_result_" << T;
return ss.str(); return ss.str();
} }
@ -1471,7 +1471,7 @@ const type::Type* ModfResultVec::Match(MatchState& state, const type::Type* ty)
std::string ModfResultVec::String(MatchState* state) const { std::string ModfResultVec::String(MatchState* state) const {
const std::string N = state->NumName(); const std::string N = state->NumName();
const std::string T = state->TypeName(); const std::string T = state->TypeName();
std::stringstream ss; utils::StringStream ss;
ss << "__modf_result_vec" << N << "_" << T; ss << "__modf_result_vec" << N << "_" << T;
return ss.str(); return ss.str();
} }
@ -1505,7 +1505,7 @@ const type::Type* FrexpResult::Match(MatchState& state, const type::Type* ty) co
std::string FrexpResult::String(MatchState* state) const { std::string FrexpResult::String(MatchState* state) const {
const std::string T = state->TypeName(); const std::string T = state->TypeName();
std::stringstream ss; utils::StringStream ss;
ss << "__frexp_result_" << T; ss << "__frexp_result_" << T;
return ss.str(); return ss.str();
} }
@ -1545,7 +1545,7 @@ const type::Type* FrexpResultVec::Match(MatchState& state, const type::Type* ty)
std::string FrexpResultVec::String(MatchState* state) const { std::string FrexpResultVec::String(MatchState* state) const {
const std::string N = state->NumName(); const std::string N = state->NumName();
const std::string T = state->TypeName(); const std::string T = state->TypeName();
std::stringstream ss; utils::StringStream ss;
ss << "__frexp_result_vec" << N << "_" << T; ss << "__frexp_result_vec" << N << "_" << T;
return ss.str(); return ss.str();
} }
@ -1624,7 +1624,7 @@ const type::Type* Scalar::Match(MatchState& state, const type::Type* ty) const {
} }
std::string Scalar::String(MatchState*) const { std::string Scalar::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@ -1667,7 +1667,7 @@ const type::Type* ConcreteScalar::Match(MatchState& state, const type::Type* ty)
} }
std::string ConcreteScalar::String(MatchState*) const { std::string ConcreteScalar::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@ -1713,7 +1713,7 @@ const type::Type* ScalarNoF32::Match(MatchState& state, const type::Type* ty) co
} }
std::string ScalarNoF32::String(MatchState*) const { std::string ScalarNoF32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << I32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << I32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@ -1759,7 +1759,7 @@ const type::Type* ScalarNoF16::Match(MatchState& state, const type::Type* ty) co
} }
std::string ScalarNoF16::String(MatchState*) const { std::string ScalarNoF16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@ -1805,7 +1805,7 @@ const type::Type* ScalarNoI32::Match(MatchState& state, const type::Type* ty) co
} }
std::string ScalarNoI32::String(MatchState*) const { std::string ScalarNoI32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@ -1851,7 +1851,7 @@ const type::Type* ScalarNoU32::Match(MatchState& state, const type::Type* ty) co
} }
std::string ScalarNoU32::String(MatchState*) const { std::string ScalarNoU32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << Bool().String(nullptr); ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << Bool().String(nullptr);
@ -1897,7 +1897,7 @@ const type::Type* ScalarNoBool::Match(MatchState& state, const type::Type* ty) c
} }
std::string ScalarNoBool::String(MatchState*) const { std::string ScalarNoBool::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@ -1943,7 +1943,7 @@ const type::Type* FiaFiu32F16::Match(MatchState& state, const type::Type* ty) co
} }
std::string FiaFiu32F16::String(MatchState*) const { std::string FiaFiu32F16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr); ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr);
@ -1986,7 +1986,7 @@ const type::Type* FiaFi32F16::Match(MatchState& state, const type::Type* ty) con
} }
std::string FiaFi32F16::String(MatchState*) const { std::string FiaFi32F16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr); ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr);
@ -2029,7 +2029,7 @@ const type::Type* FiaFiu32::Match(MatchState& state, const type::Type* ty) const
} }
std::string FiaFiu32::String(MatchState*) const { std::string FiaFiu32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@ -2063,7 +2063,7 @@ const type::Type* FaF32::Match(MatchState& state, const type::Type* ty) const {
} }
std::string FaF32::String(MatchState*) const { std::string FaF32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << " or " << F32().String(nullptr); ss << Fa().String(nullptr) << " or " << F32().String(nullptr);
@ -2100,7 +2100,7 @@ const type::Type* FaF32F16::Match(MatchState& state, const type::Type* ty) const
} }
std::string FaF32F16::String(MatchState*) const { std::string FaF32F16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << F32().String(nullptr) << " or " << F16().String(nullptr); ss << Fa().String(nullptr) << ", " << F32().String(nullptr) << " or " << F16().String(nullptr);
@ -2137,7 +2137,7 @@ const type::Type* IaIu32::Match(MatchState& state, const type::Type* ty) const {
} }
std::string IaIu32::String(MatchState*) const { std::string IaIu32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); ss << Ia().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@ -2171,7 +2171,7 @@ const type::Type* IaI32::Match(MatchState& state, const type::Type* ty) const {
} }
std::string IaI32::String(MatchState*) const { std::string IaI32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << " or " << I32().String(nullptr); ss << Ia().String(nullptr) << " or " << I32().String(nullptr);
@ -2211,7 +2211,7 @@ const type::Type* Fiu32F16::Match(MatchState& state, const type::Type* ty) const
} }
std::string Fiu32F16::String(MatchState*) const { std::string Fiu32F16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr); ss << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr);
@ -2248,7 +2248,7 @@ const type::Type* Fiu32::Match(MatchState& state, const type::Type* ty) const {
} }
std::string Fiu32::String(MatchState*) const { std::string Fiu32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@ -2285,7 +2285,7 @@ const type::Type* Fi32F16::Match(MatchState& state, const type::Type* ty) const
} }
std::string Fi32F16::String(MatchState*) const { std::string Fi32F16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr); ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr);
@ -2319,7 +2319,7 @@ const type::Type* Fi32::Match(MatchState& state, const type::Type* ty) const {
} }
std::string Fi32::String(MatchState*) const { std::string Fi32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << " or " << I32().String(nullptr); ss << F32().String(nullptr) << " or " << I32().String(nullptr);
@ -2353,7 +2353,7 @@ const type::Type* F32F16::Match(MatchState& state, const type::Type* ty) const {
} }
std::string F32F16::String(MatchState*) const { std::string F32F16::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << " or " << F16().String(nullptr); ss << F32().String(nullptr) << " or " << F16().String(nullptr);
@ -2387,7 +2387,7 @@ const type::Type* Iu32::Match(MatchState& state, const type::Type* ty) const {
} }
std::string Iu32::String(MatchState*) const { std::string Iu32::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << I32().String(nullptr) << " or " << U32().String(nullptr); ss << I32().String(nullptr) << " or " << U32().String(nullptr);

View File

@ -221,7 +221,7 @@ std::string {{$class}}::String(MatchState*{{if .TemplateParams}} state{{end}}) c
{{- end }} {{- end }}
{{- if .DisplayName }} {{- if .DisplayName }}
std::stringstream ss; utils::StringStream ss;
ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}}; ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}};
return ss.str(); return ss.str();
{{- else if .TemplateParams }} {{- else if .TemplateParams }}
@ -264,7 +264,7 @@ const type::Type* {{$class}}::Match(MatchState& state, const type::Type* ty) con
} }
std::string {{$class}}::String(MatchState*) const { std::string {{$class}}::String(MatchState*) const {
std::stringstream ss; utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState. // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss ss

View File

@ -84,6 +84,7 @@
#include "src/tint/utils/reverse.h" #include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string.h" #include "src/tint/utils/string.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h" #include "src/tint/utils/transform.h"
#include "src/tint/utils/vector.h" #include "src/tint/utils/vector.h"
@ -3099,7 +3100,7 @@ sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
filtered.Push(str); filtered.Push(str);
} }
} }
std::ostringstream msg; utils::StringStream msg;
utils::SuggestAlternatives(unresolved->name, utils::SuggestAlternatives(unresolved->name,
filtered.Slice().Reinterpret<char const* const>(), msg); filtered.Slice().Reinterpret<char const* const>(), msg);
AddNote(msg.str(), expr->source); AddNote(msg.str(), expr->source);
@ -3464,7 +3465,7 @@ bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
if (rule != builtin::DiagnosticRule::kUndefined) { if (rule != builtin::DiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity); validator_.DiagnosticFilters().Set(rule, control.severity);
} else { } else {
std::ostringstream ss; utils::StringStream ss;
ss << "unrecognized diagnostic rule '" << rule_name << "'\n"; ss << "unrecognized diagnostic rule '" << rule_name << "'\n";
utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss); utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss);
AddWarning(ss.str(), control.rule_name->source); AddWarning(ss.str(), control.rule_name->source);
@ -3584,7 +3585,7 @@ type::Array* Resolver::Array(const Source& array_source,
if (auto const_count = el_count->As<type::ConstantArrayCount>()) { if (auto const_count = el_count->As<type::ConstantArrayCount>()) {
size = const_count->value * stride; size = const_count->value * stride;
if (size > std::numeric_limits<uint32_t>::max()) { if (size > std::numeric_limits<uint32_t>::max()) {
std::stringstream msg; utils::StringStream msg;
msg << "array byte size (0x" << std::hex << size msg << "array byte size (0x" << std::hex << size
<< ") must not exceed 0xffffffff bytes"; << ") must not exceed 0xffffffff bytes";
AddError(msg.str(), count_source); AddError(msg.str(), count_source);
@ -3822,7 +3823,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
offset = utils::RoundUp(align, offset); offset = utils::RoundUp(align, offset);
if (offset > std::numeric_limits<uint32_t>::max()) { if (offset > std::numeric_limits<uint32_t>::max()) {
std::stringstream msg; utils::StringStream msg;
msg << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x" msg << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x"
<< std::hex << std::numeric_limits<uint32_t>::max() << " bytes"; << std::hex << std::numeric_limits<uint32_t>::max() << " bytes";
AddError(msg.str(), member->source); AddError(msg.str(), member->source);
@ -3844,7 +3845,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
struct_size = utils::RoundUp(struct_align, struct_size); struct_size = utils::RoundUp(struct_align, struct_size);
if (struct_size > std::numeric_limits<uint32_t>::max()) { if (struct_size > std::numeric_limits<uint32_t>::max()) {
std::stringstream msg; utils::StringStream msg;
msg << "struct size (0x" << std::hex << struct_size << ") must not exceed 0xffffffff bytes"; msg << "struct size (0x" << std::hex << struct_size << ") must not exceed 0xffffffff bytes";
AddError(msg.str(), str->source); AddError(msg.str(), str->source);
return nullptr; return nullptr;
@ -4192,7 +4193,7 @@ bool Resolver::ApplyAddressSpaceUsageToType(builtin::AddressSpace address_space,
if (decl && if (decl &&
!ApplyAddressSpaceUsageToType( !ApplyAddressSpaceUsageToType(
address_space, const_cast<type::Type*>(member->Type()), decl->type->source)) { address_space, const_cast<type::Type*>(member->Type()), decl->type->source)) {
std::stringstream err; utils::StringStream err;
err << "while analyzing structure member " << sem_.TypeNameOf(str) << "." err << "while analyzing structure member " << sem_.TypeNameOf(str) << "."
<< builder_->Symbols().NameFor(member->Name()); << builder_->Symbols().NameFor(member->Name());
AddNote(err.str(), member->Source()); AddNote(err.str(), member->Source());
@ -4223,7 +4224,7 @@ bool Resolver::ApplyAddressSpaceUsageToType(builtin::AddressSpace address_space,
} }
if (builtin::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) { if (builtin::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
std::stringstream err; utils::StringStream err;
err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '" err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '"
<< address_space << "' as it is non-host-shareable"; << address_space << "' as it is non-host-shareable";
AddError(err.str(), usage); AddError(err.str(), usage);
@ -4248,7 +4249,7 @@ SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback)
return false; return false;
} }
} else { } else {
std::ostringstream ss; utils::StringStream ss;
ss << "attribute is not valid for " << use; ss << "attribute is not valid for " << use;
AddError(ss.str(), attr->source); AddError(ss.str(), attr->source);
return false; return false;

View File

@ -46,6 +46,7 @@
#include "src/tint/type/reference.h" #include "src/tint/type/reference.h"
#include "src/tint/type/sampled_texture.h" #include "src/tint/type/sampled_texture.h"
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/string_stream.h"
using ::testing::ElementsAre; using ::testing::ElementsAre;
using ::testing::HasSubstr; using ::testing::HasSubstr;
@ -1647,7 +1648,7 @@ TEST_P(Expr_Binary_Test_Valid, All) {
ast::Type rhs_type = params.create_rhs_type(*this); ast::Type rhs_type = params.create_rhs_type(*this);
auto* result_type = params.create_result_type(*this); auto* result_type = params.create_result_type(*this);
std::stringstream ss; utils::StringStream ss;
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type); ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());
@ -1679,7 +1680,7 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
ast::Type lhs_type = create_lhs_type(*this); ast::Type lhs_type = create_lhs_type(*this);
ast::Type rhs_type = create_rhs_type(*this); ast::Type rhs_type = create_rhs_type(*this);
std::stringstream ss; utils::StringStream ss;
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type); ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op << " " ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op << " "
@ -1728,7 +1729,7 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
ast::Type lhs_type = lhs_create_type_func(*this); ast::Type lhs_type = lhs_create_type_func(*this);
ast::Type rhs_type = rhs_create_type_func(*this); ast::Type rhs_type = rhs_create_type_func(*this);
std::stringstream ss; utils::StringStream ss;
ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type); ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());

View File

@ -40,6 +40,7 @@
#include "src/tint/sem/while_statement.h" #include "src/tint/sem/while_statement.h"
#include "src/tint/utils/block_allocator.h" #include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/unique_vector.h" #include "src/tint/utils/unique_vector.h"
// Set to `1` to dump the uniformity graph for each function in graphviz format. // Set to `1` to dump the uniformity graph for each function in graphviz format.
@ -1778,7 +1779,7 @@ class UniformityGraph {
non_uniform_source->ast, non_uniform_source->ast,
[&](const ast::IdentifierExpression* ident) { [&](const ast::IdentifierExpression* ident) {
auto* var = sem_.GetVal(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable(); auto* var = sem_.GetVal(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable();
std::ostringstream ss; utils::StringStream ss;
if (auto* param = var->As<sem::Parameter>()) { if (auto* param = var->As<sem::Parameter>()) {
auto* func = param->Owner()->As<sem::Function>(); auto* func = param->Owner()->As<sem::Function>();
ss << param_type(param) << "'" << NameFor(ident) << "' of '" << NameFor(func) ss << param_type(param) << "'" << NameFor(ident) << "' of '" << NameFor(func)
@ -1791,7 +1792,7 @@ class UniformityGraph {
}, },
[&](const ast::Variable* v) { [&](const ast::Variable* v) {
auto* var = sem_.Get(v); auto* var = sem_.Get(v);
std::ostringstream ss; utils::StringStream ss;
ss << "reading from " << var_type(var) << "'" << NameFor(v) ss << "reading from " << var_type(var) << "'" << NameFor(v)
<< "' may result in a non-uniform value"; << "' may result in a non-uniform value";
diagnostics_.add_note(diag::System::Resolver, ss.str(), v->source); diagnostics_.add_note(diag::System::Resolver, ss.str(), v->source);
@ -1808,7 +1809,7 @@ class UniformityGraph {
case Node::kFunctionCallArgumentContents: { case Node::kFunctionCallArgumentContents: {
auto* arg = c->args[non_uniform_source->arg_index]; auto* arg = c->args[non_uniform_source->arg_index];
auto* var = sem_.GetVal(arg)->RootIdentifier(); auto* var = sem_.GetVal(arg)->RootIdentifier();
std::ostringstream ss; utils::StringStream ss;
ss << "reading from " << var_type(var) << "'" << NameFor(var) ss << "reading from " << var_type(var) << "'" << NameFor(var)
<< "' may result in a non-uniform value"; << "' may result in a non-uniform value";
diagnostics_.add_note(diag::System::Resolver, ss.str(), diagnostics_.add_note(diag::System::Resolver, ss.str(),
@ -1895,7 +1896,7 @@ class UniformityGraph {
// Show the place where the non-uniform argument was passed. // Show the place where the non-uniform argument was passed.
// If this is a builtin, this will be the trigger location for the failure. // If this is a builtin, this will be the trigger location for the failure.
std::ostringstream ss; utils::StringStream ss;
ss << "possibly non-uniform value passed" << (is_value ? "" : " via pointer") ss << "possibly non-uniform value passed" << (is_value ? "" : " via pointer")
<< " here"; << " here";
report(call->args[cause->arg_index]->source, ss.str(), /* note */ user_func != nullptr); report(call->args[cause->arg_index]->source, ss.str(), /* note */ user_func != nullptr);
@ -1907,7 +1908,7 @@ class UniformityGraph {
{ {
// Show a builtin was reachable from this call (which may be the call itself). // Show a builtin was reachable from this call (which may be the call itself).
// This will be the trigger location for the failure. // This will be the trigger location for the failure.
std::ostringstream ss; utils::StringStream ss;
ss << "'" << NameFor(builtin_call->target) ss << "'" << NameFor(builtin_call->target)
<< "' must only be called from uniform control flow"; << "' must only be called from uniform control flow";
report(builtin_call->source, ss.str(), /* note */ false); report(builtin_call->source, ss.str(), /* note */ false);
@ -1915,7 +1916,7 @@ class UniformityGraph {
if (builtin_call != call) { if (builtin_call != call) {
// The call was to a user function, so show that call too. // The call was to a user function, so show that call too.
std::ostringstream ss; utils::StringStream ss;
ss << "called "; ss << "called ";
if (target->As<sem::Function>() != SemCall(builtin_call)->Stmt()->Function()) { if (target->As<sem::Function>() != SemCall(builtin_call)->Stmt()->Function()) {
ss << "indirectly "; ss << "indirectly ";

View File

@ -21,6 +21,7 @@
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
#include "src/tint/reader/wgsl/parser.h" #include "src/tint/reader/wgsl/parser.h"
#include "src/tint/resolver/uniformity.h" #include "src/tint/resolver/uniformity.h"
#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -7890,7 +7891,7 @@ class UniformityAnalysisDiagnosticFilterTest
TEST_P(UniformityAnalysisDiagnosticFilterTest, Directive) { TEST_P(UniformityAnalysisDiagnosticFilterTest, Directive) {
auto& param = GetParam(); auto& param = GetParam();
std::ostringstream ss; utils::StringStream ss;
ss << "diagnostic(" << param << ", derivative_uniformity);" ss << "diagnostic(" << param << ", derivative_uniformity);"
<< R"( << R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32; @group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@ -7909,7 +7910,7 @@ fn foo() {
if (param == builtin::DiagnosticSeverity::kOff) { if (param == builtin::DiagnosticSeverity::kOff) {
EXPECT_TRUE(error_.empty()); EXPECT_TRUE(error_.empty());
} else { } else {
std::ostringstream err; utils::StringStream err;
err << ToStr(param) << ": 'textureSample' must only be called"; err << ToStr(param) << ": 'textureSample' must only be called";
EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
} }
@ -7917,7 +7918,7 @@ fn foo() {
TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) { TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) {
auto& param = GetParam(); auto& param = GetParam();
std::ostringstream ss; utils::StringStream ss;
ss << R"( ss << R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32; @group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@group(0) @binding(1) var t : texture_2d<f32>; @group(0) @binding(1) var t : texture_2d<f32>;
@ -7936,7 +7937,7 @@ TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) {
if (param == builtin::DiagnosticSeverity::kOff) { if (param == builtin::DiagnosticSeverity::kOff) {
EXPECT_TRUE(error_.empty()); EXPECT_TRUE(error_.empty());
} else { } else {
std::ostringstream err; utils::StringStream err;
err << ToStr(param) << ": 'textureSample' must only be called"; err << ToStr(param) << ": 'textureSample' must only be called";
EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
} }
@ -7944,7 +7945,7 @@ TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) {
TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnBlock) { TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnBlock) {
auto& param = GetParam(); auto& param = GetParam();
std::ostringstream ss; utils::StringStream ss;
ss << R"( ss << R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32; @group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@group(0) @binding(1) var t : texture_2d<f32>; @group(0) @binding(1) var t : texture_2d<f32>;
@ -7962,7 +7963,7 @@ fn foo() {
if (param == builtin::DiagnosticSeverity::kOff) { if (param == builtin::DiagnosticSeverity::kOff) {
EXPECT_TRUE(error_.empty()); EXPECT_TRUE(error_.empty());
} else { } else {
std::ostringstream err; utils::StringStream err;
err << ToStr(param) << ": 'textureSample' must only be called"; err << ToStr(param) << ": 'textureSample' must only be called";
EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
} }

View File

@ -71,6 +71,7 @@
#include "src/tint/utils/reverse.h" #include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string.h" #include "src/tint/utils/string.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h" #include "src/tint/utils/transform.h"
namespace tint::resolver { namespace tint::resolver {
@ -380,7 +381,7 @@ bool Validator::VariableInitializer(const ast::Variable* v,
// Value type has to match storage type // Value type has to match storage type
if (storage_ty != value_type) { if (storage_ty != value_type) {
std::stringstream s; utils::StringStream s;
s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty) s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty)
<< "' with value of type '" << sem_.TypeNameOf(initializer_ty) << "'"; << "' with value of type '" << sem_.TypeNameOf(initializer_ty) << "'";
AddError(s.str(), v->source); AddError(s.str(), v->source);
@ -842,7 +843,7 @@ bool Validator::Parameter(const ast::Function* func, const sem::Variable* var) c
break; break;
} }
if (!ok) { if (!ok) {
std::stringstream ss; utils::StringStream ss;
ss << "function parameter of pointer type cannot be in '" << sc ss << "function parameter of pointer type cannot be in '" << sc
<< "' address space"; << "' address space";
AddError(ss.str(), decl->source); AddError(ss.str(), decl->source);
@ -870,7 +871,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
ast::PipelineStage stage, ast::PipelineStage stage,
const bool is_input) const { const bool is_input) const {
auto* type = storage_ty->UnwrapRef(); auto* type = storage_ty->UnwrapRef();
std::stringstream stage_name; utils::StringStream stage_name;
stage_name << stage; stage_name << stage;
bool is_stage_mismatch = false; bool is_stage_mismatch = false;
bool is_output = !is_input; bool is_output = !is_input;
@ -883,7 +884,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!(type->is_float_vector() && type->As<type::Vector>()->Width() == 4)) { if (!(type->is_float_vector() && type->As<type::Vector>()->Width() == 4)) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'vec4<f32>'"; err << "store type of @builtin(" << builtin << ") must be 'vec4<f32>'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -898,7 +899,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!(type->is_unsigned_integer_vector() && type->As<type::Vector>()->Width() == 3)) { if (!(type->is_unsigned_integer_vector() && type->As<type::Vector>()->Width() == 3)) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'vec3<u32>'"; err << "store type of @builtin(" << builtin << ") must be 'vec3<u32>'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -910,7 +911,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!type->Is<type::F32>()) { if (!type->Is<type::F32>()) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'f32'"; err << "store type of @builtin(" << builtin << ") must be 'f32'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -922,7 +923,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!type->Is<type::Bool>()) { if (!type->Is<type::Bool>()) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'bool'"; err << "store type of @builtin(" << builtin << ") must be 'bool'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -934,7 +935,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!type->Is<type::U32>()) { if (!type->Is<type::U32>()) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'"; err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -947,7 +948,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!type->Is<type::U32>()) { if (!type->Is<type::U32>()) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'"; err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -958,7 +959,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!type->Is<type::U32>()) { if (!type->Is<type::U32>()) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'"; err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -970,7 +971,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
is_stage_mismatch = true; is_stage_mismatch = true;
} }
if (!type->Is<type::U32>()) { if (!type->Is<type::U32>()) {
std::stringstream err; utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'"; err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
return false; return false;
@ -981,7 +982,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
} }
if (is_stage_mismatch) { if (is_stage_mismatch) {
std::stringstream err; utils::StringStream err;
err << "@builtin(" << builtin << ") cannot be used in " err << "@builtin(" << builtin << ") cannot be used in "
<< (is_input ? "input of " : "output of ") << stage_name.str() << " pipeline stage"; << (is_input ? "input of " : "output of ") << stage_name.str() << " pipeline stage";
AddError(err.str(), attr->source); AddError(err.str(), attr->source);
@ -1156,7 +1157,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
pipeline_io_attribute = attr; pipeline_io_attribute = attr;
if (builtins.Contains(builtin)) { if (builtins.Contains(builtin)) {
std::stringstream err; utils::StringStream err;
err << "@builtin(" << builtin << ") appears multiple times as pipeline " err << "@builtin(" << builtin << ") appears multiple times as pipeline "
<< (param_or_ret == ParamOrRetType::kParameter ? "input" : "output"); << (param_or_ret == ParamOrRetType::kParameter ? "input" : "output");
AddError(err.str(), decl->source); AddError(err.str(), decl->source);
@ -1949,7 +1950,7 @@ bool Validator::PipelineStages(utils::VectorRef<sem::Function*> entry_points) co
if (stage != ast::PipelineStage::kCompute) { if (stage != ast::PipelineStage::kCompute) {
for (auto* var : func->DirectlyReferencedGlobals()) { for (auto* var : func->DirectlyReferencedGlobals()) {
if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) { if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
std::stringstream stage_name; utils::StringStream stage_name;
stage_name << stage; stage_name << stage;
for (auto* user : var->Users()) { for (auto* user : var->Users()) {
if (func == user->Stmt()->Function()) { if (func == user->Stmt()->Function()) {
@ -1973,7 +1974,7 @@ bool Validator::PipelineStages(utils::VectorRef<sem::Function*> entry_points) co
for (auto* builtin : func->DirectlyCalledBuiltins()) { for (auto* builtin : func->DirectlyCalledBuiltins()) {
if (!builtin->SupportedStages().Contains(stage)) { if (!builtin->SupportedStages().Contains(stage)) {
auto* call = func->FindDirectCallTo(builtin); auto* call = func->FindDirectCallTo(builtin);
std::stringstream err; utils::StringStream err;
err << "built-in cannot be used by " << stage << " pipeline stage"; err << "built-in cannot be used by " << stage << " pipeline stage";
AddError(err.str(), AddError(err.str(),
call ? call->Declaration()->source : func->Declaration()->source); call ? call->Declaration()->source : func->Declaration()->source);
@ -1987,7 +1988,7 @@ bool Validator::PipelineStages(utils::VectorRef<sem::Function*> entry_points) co
auto check_no_discards = [&](const sem::Function* func, const sem::Function* entry_point) { auto check_no_discards = [&](const sem::Function* func, const sem::Function* entry_point) {
if (auto* discard = func->DiscardStatement()) { if (auto* discard = func->DiscardStatement()) {
auto stage = entry_point->Declaration()->PipelineStage(); auto stage = entry_point->Declaration()->PipelineStage();
std::stringstream err; utils::StringStream err;
err << "discard statement cannot be used in " << stage << " pipeline stage"; err << "discard statement cannot be used in " << stage << " pipeline stage";
AddError(err.str(), discard->Declaration()->source); AddError(err.str(), discard->Declaration()->source);
backtrace(func, entry_point); backtrace(func, entry_point);
@ -2283,7 +2284,7 @@ bool Validator::LocationAttribute(const ast::LocationAttribute* loc_attr,
} }
if (!locations.Add(location)) { if (!locations.Add(location)) {
std::stringstream err; utils::StringStream err;
err << "@location(" << location << ") appears multiple times"; err << "@location(" << location << ") appears multiple times";
AddError(err.str(), loc_attr->source); AddError(err.str(), loc_attr->source);
return false; return false;
@ -2543,12 +2544,12 @@ bool Validator::DiagnosticControls(utils::VectorRef<const ast::DiagnosticControl
auto diag_added = diagnostics.Add(dc->rule_name->symbol, dc); auto diag_added = diagnostics.Add(dc->rule_name->symbol, dc);
if (!diag_added && (*diag_added.value)->severity != dc->severity) { if (!diag_added && (*diag_added.value)->severity != dc->severity) {
{ {
std::ostringstream ss; utils::StringStream ss;
ss << "conflicting diagnostic " << use; ss << "conflicting diagnostic " << use;
AddError(ss.str(), dc->rule_name->source); AddError(ss.str(), dc->rule_name->source);
} }
{ {
std::ostringstream ss; utils::StringStream ss;
ss << "severity of '" << symbols_.NameFor(dc->rule_name->symbol) << "' set to '" ss << "severity of '" << symbols_.NameFor(dc->rule_name->symbol) << "' set to '"
<< dc->severity << "' here"; << dc->severity << "' here";
AddNote(ss.str(), (*diag_added.value)->rule_name->source); AddNote(ss.str(), (*diag_added.value)->rule_name->source);

View File

@ -17,6 +17,7 @@
#include "src/tint/sem/value_constructor.h" #include "src/tint/sem/value_constructor.h"
#include "src/tint/sem/value_conversion.h" #include "src/tint/sem/value_conversion.h"
#include "src/tint/type/reference.h" #include "src/tint/type/reference.h"
#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT using namespace tint::number_suffixes; // NOLINT
@ -354,7 +355,7 @@ TEST_P(ConversionConstructorValidTest, All) {
auto rhs_type = params.rhs_type(*this); auto rhs_type = params.rhs_type(*this);
auto* rhs_value_expr = params.rhs_value_expr(*this, 0); auto* rhs_value_expr = params.rhs_value_expr(*this, 0);
std::stringstream ss; utils::StringStream ss;
ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "(" ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
<< FriendlyName(rhs_type) << "(<rhs value expr>))"; << FriendlyName(rhs_type) << "(<rhs value expr>))";
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());
@ -447,7 +448,7 @@ TEST_P(ConversionConstructorInvalidTest, All) {
auto rhs_type = rhs_params.ast(*this); auto rhs_type = rhs_params.ast(*this);
auto* rhs_value_expr = rhs_params.expr_from_double(*this, 0); auto* rhs_value_expr = rhs_params.expr_from_double(*this, 0);
std::stringstream ss; utils::StringStream ss;
ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "(" ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
<< FriendlyName(rhs_type) << "(<rhs value expr>))"; << FriendlyName(rhs_type) << "(<rhs value expr>))";
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());
@ -2414,7 +2415,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewArguments) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name(); const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns - 1; i++) { for (uint32_t i = 0; i < param.columns - 1; i++) {
ast::Type vec_type = param.create_column_ast_type(*this); ast::Type vec_type = param.create_column_ast_type(*this);
@ -2443,7 +2444,7 @@ TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooFewArguments) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name(); const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns * param.rows - 1; i++) { for (uint32_t i = 0; i < param.columns * param.rows - 1; i++) {
args.Push(Call(param.create_element_ast_type(*this))); args.Push(Call(param.create_element_ast_type(*this)));
@ -2471,7 +2472,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyArguments) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name(); const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns + 1; i++) { for (uint32_t i = 0; i < param.columns + 1; i++) {
ast::Type vec_type = param.create_column_ast_type(*this); ast::Type vec_type = param.create_column_ast_type(*this);
@ -2500,7 +2501,7 @@ TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooManyArguments) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name(); const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns * param.rows + 1; i++) { for (uint32_t i = 0; i < param.columns * param.rows + 1; i++) {
args.Push(Call(param.create_element_ast_type(*this))); args.Push(Call(param.create_element_ast_type(*this)));
@ -2527,7 +2528,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_InvalidArgumentType) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) { for (uint32_t i = 0; i < param.columns; i++) {
auto vec_type = ty.vec<u32>(param.rows); auto vec_type = ty.vec<u32>(param.rows);
@ -2555,7 +2556,7 @@ TEST_P(MatrixConstructorTest, ElementConstructor_Error_InvalidArgumentType) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) { for (uint32_t i = 0; i < param.columns; i++) {
args.Push(Expr(1_u)); args.Push(Expr(1_u));
@ -2588,7 +2589,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewRowsInVectorArgument
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name(); const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) { for (uint32_t i = 0; i < param.columns; i++) {
ast::Type valid_vec_type = param.create_column_ast_type(*this); ast::Type valid_vec_type = param.create_column_ast_type(*this);
@ -2626,7 +2627,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyRowsInVectorArgumen
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name(); const std::string element_type_name = param.get_element_type_name();
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) { for (uint32_t i = 0; i < param.columns; i++) {
ast::Type valid_vec_type = param.create_column_ast_type(*this); ast::Type valid_vec_type = param.create_column_ast_type(*this);
@ -2715,7 +2716,7 @@ TEST_P(MatrixConstructorTest, ElementTypeAlias_Error) {
auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this)); auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 4> args; utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) { for (uint32_t i = 0; i < param.columns; i++) {
auto vec_type = ty.vec(ty.u32(), param.rows); auto vec_type = ty.vec(ty.u32(), param.rows);
@ -2797,7 +2798,7 @@ TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Error) {
ast::Type matrix_type = param.create_mat_ast_type(*this); ast::Type matrix_type = param.create_mat_ast_type(*this);
auto* u32_type_alias = Alias("UnsignedInt", ty.u32()); auto* u32_type_alias = Alias("UnsignedInt", ty.u32());
std::stringstream args_tys; utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 4> args; utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) { for (uint32_t i = 0; i < param.columns; i++) {
auto vec_type = ty.vec(ty.Of(u32_type_alias), param.rows); auto vec_type = ty.vec(ty.Of(u32_type_alias), param.rows);
@ -2874,7 +2875,7 @@ TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
std::stringstream err; utils::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
<< "("; << "(";
@ -2905,7 +2906,7 @@ TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) {
Enable(builtin::Extension::kF16); Enable(builtin::Extension::kF16);
std::stringstream err; utils::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
<< "("; << "(";
@ -3073,7 +3074,7 @@ TEST_P(StructConstructorTypeTest, AllTypes) {
auto* tc = Call(ty.Of(s), values); auto* tc = Call(ty.Of(s), values);
WrapInFunction(tc); WrapInFunction(tc);
std::stringstream err; utils::StringStream err;
err << "error: type in structure constructor does not match struct member "; err << "error: type in structure constructor does not match struct member ";
err << "type: expected '" << str_params.name() << "', found '" << ctor_params.name() << "'"; err << "type: expected '" << str_params.name() << "', found '" << ctor_params.name() << "'";
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());

View File

@ -50,7 +50,7 @@ size_t Distance(std::string_view str_a, std::string_view str_b) {
void SuggestAlternatives(std::string_view got, void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings, Slice<char const* const> strings,
std::ostringstream& ss) { utils::StringStream& ss) {
// If the string typed was within kSuggestionDistance of one of the possible enum values, // 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. // suggest that. Don't bother with suggestions if the string was extremely long.
constexpr size_t kSuggestionDistance = 5; constexpr size_t kSuggestionDistance = 5;

View File

@ -20,6 +20,7 @@
#include <variant> #include <variant>
#include "src/tint/utils/slice.h" #include "src/tint/utils/slice.h"
#include "src/tint/utils/string_stream.h"
namespace tint::utils { namespace tint::utils {
@ -74,7 +75,7 @@ size_t Distance(std::string_view a, std::string_view b);
/// @param ss the stream to write the suggest and list of possible values to /// @param ss the stream to write the suggest and list of possible values to
void SuggestAlternatives(std::string_view got, void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings, Slice<char const* const> strings,
std::ostringstream& ss); utils::StringStream& ss);
} // namespace tint::utils } // namespace tint::utils

View File

@ -15,6 +15,7 @@
#include "src/tint/utils/string.h" #include "src/tint/utils/string.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/tint/utils/string_stream.h"
namespace tint::utils { namespace tint::utils {
namespace { namespace {
@ -61,14 +62,14 @@ TEST(StringTest, Distance) {
TEST(StringTest, SuggestAlternatives) { TEST(StringTest, SuggestAlternatives) {
{ {
const char* alternatives[] = {"hello world", "Hello World"}; const char* alternatives[] = {"hello world", "Hello World"};
std::ostringstream ss; utils::StringStream ss;
SuggestAlternatives("hello wordl", alternatives, ss); SuggestAlternatives("hello wordl", alternatives, ss);
EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'? EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'?
Possible values: 'hello world', 'Hello World')"); Possible values: 'hello world', 'Hello World')");
} }
{ {
const char* alternatives[] = {"foobar", "something else"}; const char* alternatives[] = {"foobar", "something else"};
std::ostringstream ss; utils::StringStream ss;
SuggestAlternatives("hello world", alternatives, ss); SuggestAlternatives("hello world", alternatives, ss);
EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')"); EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')");
} }