From 3549e2ea8ccd3a3448341d2aca36d02f76f09f36 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Mon, 15 Mar 2021 21:21:33 +0000 Subject: [PATCH] Resolver: Enforce vector constructor type rules Added enforcement for vector constructor type rules according to the table in https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr. This surfaced a number of existing tests that violated some of these rules or had a type-declaration related bug, so this CL fixes those as well (these tests either passed the incorrect number of arguments to a vector constructor or relied on implicit conversions between numeric types). Fixed: tint:632 Fixed: tint:476 Change-Id: I8279be3eeae50b64db486ee7a91a43bd94fdff62 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44480 Commit-Queue: Arman Uguray Reviewed-by: Ben Clayton --- src/ast/module_clone_test.cc | 2 +- src/reader/wgsl/parser_test.cc | 2 +- src/resolver/resolver.cc | 91 +- src/resolver/resolver.h | 2 + src/resolver/resolver_test.cc | 28 +- src/resolver/validation_test.cc | 1042 ++++++++++++++++- src/transform/hlsl_test.cc | 4 +- src/validator/validator_builtins_test.cc | 6 +- .../builder_constructor_expression_test.cc | 34 +- 9 files changed, 1173 insertions(+), 38 deletions(-) diff --git a/src/ast/module_clone_test.cc b/src/ast/module_clone_test.cc index 4e3fea63b7..87710e7b0b 100644 --- a/src/ast/module_clone_test.cc +++ b/src/ast/module_clone_test.cc @@ -65,7 +65,7 @@ fn f1(p0 : f32, p1 : i32) -> f32 { var l0 : i32 = 3; var l1 : f32 = 8.0; var l2 : u32 = bitcast(4); - var l3 : vec2 = vec2(l0, l1); + var l3 : vec2 = vec2(u32(l0), u32(l1)); var l4 : S; var l5 : u32 = l4.m1[5]; var l6 : ptr; diff --git a/src/reader/wgsl/parser_test.cc b/src/reader/wgsl/parser_test.cc index d75a74281f..b63c557ba6 100644 --- a/src/reader/wgsl/parser_test.cc +++ b/src/reader/wgsl/parser_test.cc @@ -38,7 +38,7 @@ TEST_F(ParserTest, Parses) { [[stage(vertex)]] fn main() -> void { - gl_FragColor = vec4(.4, .2, .3, 1); + gl_FragColor = vec4(.4, .2, .3, 1.); } )"); auto program = Parse(&file); diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index e1f1301ccb..8b27d4703e 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc @@ -597,16 +597,97 @@ bool Resolver::IntrinsicCall(ast::CallExpression* call, } bool Resolver::Constructor(ast::ConstructorExpression* expr) { - if (auto* ty = expr->As()) { - for (auto* value : ty->values()) { + if (auto* type_ctor = expr->As()) { + for (auto* value : type_ctor->values()) { if (!Expression(value)) { return false; } } - SetType(expr, ty->type()); + SetType(expr, type_ctor->type()); + + // Now that the argument types have been determined, make sure that they + // obey the constructor type rules laid out in + // https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr. + if (auto* vec_type = type_ctor->type()->As()) { + return VectorConstructor(*vec_type, type_ctor->values()); + } + // TODO(crbug.com/tint/633): Validate matrix constructor + // TODO(crbug.com/tint/634): Validate array constructor + } else if (auto* scalar_ctor = expr->As()) { + SetType(expr, scalar_ctor->literal()->type()); } else { - SetType(expr, - expr->As()->literal()->type()); + TINT_ICE(diagnostics_) << "unexpected constructor expression type"; + } + return true; +} + +bool Resolver::VectorConstructor(const type::Vector& vec_type, + const ast::ExpressionList& values) { + type::Type* elem_type = vec_type.type()->UnwrapAll(); + size_t value_cardinality_sum = 0; + for (auto* value : values) { + type::Type* value_type = TypeOf(value)->UnwrapAll(); + if (value_type->is_scalar()) { + if (elem_type != value_type) { + diagnostics_.add_error( + "type in vector constructor does not match vector type: " + "expected '" + + elem_type->FriendlyName(builder_->Symbols()) + "', found '" + + value_type->FriendlyName(builder_->Symbols()) + "'", + value->source()); + return false; + } + + value_cardinality_sum++; + } else if (auto* value_vec = value_type->As()) { + type::Type* value_elem_type = value_vec->type()->UnwrapAll(); + // A mismatch of vector type parameter T is only an error if multiple + // arguments are present. A single argument constructor constitutes a + // type conversion expression. + // NOTE: A conversion expression from a vec to any other vecN + // is disallowed (see + // https://gpuweb.github.io/gpuweb/wgsl.html#conversion-expr). + if (elem_type != value_elem_type && + (values.size() > 1u || value_vec->is_bool_vector())) { + diagnostics_.add_error( + "type in vector constructor does not match vector type: " + "expected '" + + elem_type->FriendlyName(builder_->Symbols()) + "', found '" + + value_elem_type->FriendlyName(builder_->Symbols()) + "'", + value->source()); + return false; + } + + value_cardinality_sum += value_vec->size(); + } else { + // A vector constructor can only accept vectors and scalars. + diagnostics_.add_error( + "expected vector or scalar type in vector constructor; found: " + + value_type->FriendlyName(builder_->Symbols()), + value->source()); + return false; + } + } + + // A correct vector constructor must either be a zero-value expression + // or the number of components of all constructor arguments must add up + // to the vector cardinality. + if (value_cardinality_sum > 0 && value_cardinality_sum != vec_type.size()) { + if (values.empty()) { + TINT_ICE(diagnostics_) + << "constructor arguments expected to be non-empty!"; + } + const Source& values_start = values[0]->source(); + const Source& values_end = values[values.size() - 1]->source(); + const Source src( + Source::Range(values_start.range.begin, values_end.range.end), + values_start.file_path, values_start.file_content); + diagnostics_.add_error( + "attempted to construct '" + + vec_type.FriendlyName(builder_->Symbols()) + "' with " + + std::to_string(value_cardinality_sum) + " component(s)", + src); + return false; } return true; } diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h index 485bff8749..ddf7c11ef7 100644 --- a/src/resolver/resolver.h +++ b/src/resolver/resolver.h @@ -177,6 +177,8 @@ class Resolver { bool Call(ast::CallExpression*); bool CaseStatement(ast::CaseStatement*); bool Constructor(ast::ConstructorExpression*); + bool VectorConstructor(const type::Vector& vec_type, + const ast::ExpressionList& values); bool Expression(ast::Expression*); bool Expressions(const ast::ExpressionList&); bool Function(ast::Function*); diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc index 66bf2af125..caf608e964 100644 --- a/src/resolver/resolver_test.cc +++ b/src/resolver/resolver_test.cc @@ -578,8 +578,20 @@ TEST_F(ResolverTest, Expr_Constructor_Scalar) { EXPECT_TRUE(TypeOf(s)->Is()); } -TEST_F(ResolverTest, Expr_Constructor_Type) { - auto* tc = vec3(1.0f, 1.0f, 3.0f); +TEST_F(ResolverTest, Expr_Constructor_Type_Vec2) { + auto* tc = vec2(1.0f, 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverTest, Expr_Constructor_Type_Vec3) { + auto* tc = vec3(1.0f, 1.0f, 1.0f); WrapInFunction(tc); EXPECT_TRUE(r()->Resolve()) << r()->error(); @@ -590,6 +602,18 @@ TEST_F(ResolverTest, Expr_Constructor_Type) { EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); } +TEST_F(ResolverTest, Expr_Constructor_Type_Vec4) { + auto* tc = vec4(1.0f, 1.0f, 1.0f, 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) { auto* my_var = Global("my_var", ty.f32(), ast::StorageClass::kNone); diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc index 02965feb5e..9dc2e0d279 100644 --- a/src/resolver/validation_test.cc +++ b/src/resolver/validation_test.cc @@ -373,7 +373,7 @@ TEST_F(ResolverValidationTest, } TEST_F( - ResolverTest, + ResolverValidationTest, Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingSubscope) { // loop { // if (true) { @@ -624,6 +624,1046 @@ TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeDecoration) { "decorations"); } +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2F32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec2( + create(Source{{12, 34}}, Literal(1)), + 1.0f); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2U32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec2(1u, create( + Source{{12, 34}}, Literal(1))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'u32', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2I32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec2( + create(Source{{12, 34}}, Literal(1u)), + 1); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'i32', found 'u32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2Bool_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec2(true, create( + Source{{12, 34}}, Literal(1))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'bool', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_Vec3ArgumentCardinalityTooLarge) { + auto* tc = vec2(create( + Source{{12, 34}}, ty.vec3(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 3 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_Vec4ArgumentCardinalityTooLarge) { + auto* tc = vec2(create( + Source{{12, 34}}, ty.vec4(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_TooFewArgumentsScalar) { + auto* tc = vec2(create( + Source{{12, 34}}, Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 1 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) { + auto* tc = vec2( + create(Source{{12, 34}}, Literal(1.0f)), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 3 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_TooManyArgumentsVector) { + auto* tc = vec2(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, ty.vec2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_TooManyArgumentsVectorAndScalar) { + auto* tc = vec2(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 3 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_InvalidConversionFromVec2Bool) { + SetSource(Source::Location({12, 34})); + + auto* tc = vec2(create( + Source{{12, 34}}, ty.vec2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'bool'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Error_InvalidArgumentType) { + auto* tc = vec2(create( + Source{{12, 34}}, ty.mat2x2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: expected vector or scalar type in vector " + "constructor; found: mat2x2"); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec2_Success_ZeroValue) { + auto* tc = vec2(); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec2F32_Success_Scalar) { + auto* tc = vec2(1.0f, 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec2U32_Success_Scalar) { + auto* tc = vec2(1u, 1u); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec2I32_Success_Scalar) { + auto* tc = vec2(1, 1); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec2Bool_Success_Scalar) { + auto* tc = vec2(true, false); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec2_Success_Identity) { + auto* tc = vec2(vec2()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec2_Success_Vec2TypeConversion) { + auto* tc = vec2(vec2()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 2u); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3F32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec3( + 1.0f, 1.0f, + create(Source{{12, 34}}, Literal(1))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3U32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec3( + 1u, + create(Source{{12, 34}}, Literal(1)), + 1u); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'u32', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3I32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec3( + 1, + create(Source{{12, 34}}, Literal(1u)), + 1); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'i32', found 'u32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3Bool_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec3( + true, + create(Source{{12, 34}}, Literal(1)), + false); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'bool', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_Vec4ArgumentCardinalityTooLarge) { + auto* tc = vec3(create( + Source{{12, 34}}, ty.vec4(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_TooFewArgumentsScalar) { + auto* tc = vec3( + create(Source{{12, 34}}, Literal(1.0f)), + create(Source{{12, 40}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 2 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_TooManyArgumentsScalar) { + auto* tc = vec3( + create(Source{{12, 34}}, Literal(1.0f)), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, Literal(1.0f)), + create(Source{{12, 52}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_TooFewArgumentsVec2) { + auto* tc = vec3(create( + Source{{12, 34}}, ty.vec2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 2 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_TooManyArgumentsVec2) { + auto* tc = vec3(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, ty.vec2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_TooManyArgumentsVec2AndScalar) { + auto* tc = vec3( + create(Source{{12, 34}}, ty.vec2(), + ExprList()), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_TooManyArgumentsVec3) { + auto* tc = vec3(create( + Source{{12, 34}}, ty.vec3(), ExprList()), + create( + Source{{12, 40}}, Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec3' with 4 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_InvalidConversionFromVec3Bool) { + auto* tc = vec3(create( + Source{{12, 34}}, ty.vec3(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'bool'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Error_InvalidArgumentType) { + auto* tc = vec3(create( + Source{{12, 34}}, ty.mat2x2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: expected vector or scalar type in vector " + "constructor; found: mat2x2"); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3_Success_ZeroValue) { + auto* tc = vec3(); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3F32_Success_Scalar) { + auto* tc = vec3(1.0f, 1.0f, 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3U32_Success_Scalar) { + auto* tc = vec3(1u, 1u, 1u); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3I32_Success_Scalar) { + auto* tc = vec3(1, 1, 1); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3Bool_Success_Scalar) { + auto* tc = vec3(true, false, true); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3_Success_Vec2AndScalar) { + auto* tc = vec3(vec2(), 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3_Success_ScalarAndVec2) { + auto* tc = vec3(1.0f, vec2()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec3_Success_Identity) { + auto* tc = vec3(vec3()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec3_Success_Vec3TypeConversion) { + auto* tc = vec3(vec3()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 3u); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4F32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec4( + 1.0f, 1.0f, + create(Source{{12, 34}}, Literal(1)), + 1.0f); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4U32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec4( + 1u, 1u, + create(Source{{12, 34}}, Literal(1)), + 1u); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'u32', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4I32_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec4( + 1, 1, + create(Source{{12, 34}}, Literal(1u)), + 1); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'i32', found 'u32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4Bool_Error_ScalarArgumentTypeMismatch) { + auto* tc = vec4( + true, false, + create(Source{{12, 34}}, Literal(1)), + true); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'bool', found 'i32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooFewArgumentsScalar) { + auto* tc = vec4( + create(Source{{12, 34}}, Literal(1.0f)), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 3 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsScalar) { + auto* tc = vec4( + create(Source{{12, 34}}, Literal(1.0f)), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, Literal(1.0f)), + create(Source{{12, 52}}, Literal(1.0f)), + create(Source{{12, 58}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 5 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooFewArgumentsVec2AndScalar) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 3 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndScalars) { + auto* tc = vec4( + create(Source{{12, 34}}, ty.vec2(), + ExprList()), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, Literal(1.0f)), + create(Source{{12, 52}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 5 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec2Vec2Scalar) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, ty.vec2(), ExprList()), + create( + Source{{12, 46}}, Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 5 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec2Vec2Vec2) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, ty.vec2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 6 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooFewArgumentsVec3) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec3(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 3 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndScalars) { + auto* tc = vec4( + create(Source{{12, 34}}, ty.vec3(), + ExprList()), + create(Source{{12, 40}}, Literal(1.0f)), + create(Source{{12, 46}}, + Literal(1.0f))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 5 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndVec2) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec3(), ExprList()), + create( + Source{{12, 40}}, ty.vec2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 5 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndVec3) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec2(), ExprList()), + create( + Source{{12, 40}}, ty.vec3(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 5 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndVec3) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec3(), ExprList()), + create( + Source{{12, 40}}, ty.vec3(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec4' with 6 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_InvalidConversionFromVec4Bool) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.vec4(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'bool'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Error_InvalidArgumentType) { + auto* tc = vec4(create( + Source{{12, 34}}, ty.mat2x2(), ExprList())); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: expected vector or scalar type in vector " + "constructor; found: mat2x2"); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_ZeroValue) { + auto* tc = vec4(); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4F32_Success_Scalar) { + auto* tc = vec4(1.0f, 1.0f, 1.0f, 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4U32_Success_Scalar) { + auto* tc = vec4(1u, 1u, 1u, 1u); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4I32_Success_Scalar) { + auto* tc = vec4(1, 1, 1, 1); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4Bool_Success_Scalar) { + auto* tc = vec4(true, false, true, false); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_Vec2ScalarScalar) { + auto* tc = vec4(vec2(), 1.0f, 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_ScalarVec2Scalar) { + auto* tc = vec4(1.0f, vec2(), 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_ScalarScalarVec2) { + auto* tc = vec4(1.0f, 1.0f, vec2()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_Vec2AndVec2) { + auto* tc = vec4(vec2(), vec2()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_Vec3AndScalar) { + auto* tc = vec4(vec3(), 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_ScalarAndVec3) { + auto* tc = vec4(1.0f, vec3()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vec4_Success_Identity) { + auto* tc = vec4(vec4()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vec4_Success_Vec4TypeConversion) { + auto* tc = vec4(vec4()); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_NestedVectorConstructors_InnerError) { + auto* tc = vec4( + vec3(1.0f, vec2(create( + Source{{12, 34}}, Literal(1.0f)))), + 1.0f); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: attempted to construct 'vec2' with 1 component(s)"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_NestedVectorConstructors_Success) { + auto* tc = vec4(vec3(vec2(1.0f, 1.0f), 1.0f), 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + + ASSERT_NE(TypeOf(tc), nullptr); + ASSERT_TRUE(TypeOf(tc)->Is()); + EXPECT_TRUE(TypeOf(tc)->As()->type()->Is()); + EXPECT_EQ(TypeOf(tc)->As()->size(), 4u); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) { + auto* alias = ty.alias("UnsignedInt", ty.u32()); + Global("uint_var", alias, ast::StorageClass::kNone); + + auto* tc = vec2(Expr(Source{{12, 34}}, "uint_var")); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'u32'"); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) { + auto* f32_alias = ty.alias("Float32", ty.f32()); + auto* vec2_alias = ty.alias("VectorFloat2", ty.vec2()); + Global("my_f32", f32_alias, ast::StorageClass::kNone); + Global("my_vec2", vec2_alias, ast::StorageClass::kNone); + + auto* tc = vec3("my_vec2", "my_f32"); + WrapInFunction(tc); + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + +TEST_F(ResolverValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Error) { + auto* f32_alias = ty.alias("Float32", ty.f32()); + auto* vec_type = create(f32_alias, 2); + + // vec2(1.0f, 1u) + auto* tc = create( + Source{{12, 34}}, vec_type, + ExprList(1.0f, create(Source{{12, 40}}, + Literal(1u)))); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:40 error: type in vector constructor does not match vector " + "type: expected 'f32', found 'u32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vector_ElementTypeAlias_Success) { + auto* f32_alias = ty.alias("Float32", ty.f32()); + auto* vec_type = create(f32_alias, 2); + + // vec2(1.0f, 1.0f) + auto* tc = create(Source{{12, 34}}, vec_type, + ExprList(1.0f, 1.0f)); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vector_ArgumentElementTypeAlias_Error) { + auto* f32_alias = ty.alias("Float32", ty.f32()); + auto* vec_type = create(f32_alias, 2); + + // vec3(vec(), 1.0f) + auto* tc = vec3(create( + Source{{12, 34}}, vec_type, ExprList()), + 1.0f); + WrapInFunction(tc); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: type in vector constructor does not match vector " + "type: expected 'u32', found 'f32'"); +} + +TEST_F(ResolverValidationTest, + Expr_Constructor_Vector_ArgumentElementTypeAlias_Success) { + auto* f32_alias = ty.alias("Float32", ty.f32()); + auto* vec_type = create(f32_alias, 2); + + // vec3(vec(), 1.0f) + auto* tc = vec3(create( + Source{{12, 34}}, vec_type, ExprList()), + 1.0f); + WrapInFunction(tc); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); +} + } // namespace } // namespace resolver } // namespace tint diff --git a/src/transform/hlsl_test.cc b/src/transform/hlsl_test.cc index 70fdfb304a..82c732d8e7 100644 --- a/src/transform/hlsl_test.cc +++ b/src/transform/hlsl_test.cc @@ -108,7 +108,7 @@ struct Uniforms { [[stage(vertex)]] fn main() -> void { const transform : mat2x2 = ubo.transform; - var coord : array, 3> = array, 3>( + var coord : vec2 = array, 3>( vec2(-1.0, 1.0), vec2( 1.0, 1.0), vec2(-1.0, -1.0) @@ -133,7 +133,7 @@ struct Uniforms { fn main() -> void { const transform : mat2x2 = ubo.transform; const tint_symbol_1 : array, 3> = array, 3>(vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(-1.0, -1.0)); - var coord : array, 3> = tint_symbol_1[vertex_index]; + var coord : vec2 = tint_symbol_1[vertex_index]; position = vec4((transform * coord), 0.0, 1.0); } )"; diff --git a/src/validator/validator_builtins_test.cc b/src/validator/validator_builtins_test.cc index c65393bdcd..fa9aedea1e 100644 --- a/src/validator/validator_builtins_test.cc +++ b/src/validator/validator_builtins_test.cc @@ -509,7 +509,7 @@ TEST_P(IntegerAllMatching, Vec2Unsigned) { ast::ExpressionList params; for (uint32_t i = 0; i < num_params; ++i) { - params.push_back(vec2(1, 1)); + params.push_back(vec2(1u, 1u)); } auto* builtin = Call(name, params); WrapInFunction(builtin); @@ -526,7 +526,7 @@ TEST_P(IntegerAllMatching, Vec3Unsigned) { ast::ExpressionList params; for (uint32_t i = 0; i < num_params; ++i) { - params.push_back(vec3(1, 1, 1)); + params.push_back(vec3(1u, 1u, 1u)); } auto* builtin = Call(name, params); WrapInFunction(builtin); @@ -543,7 +543,7 @@ TEST_P(IntegerAllMatching, Vec4Unsigned) { ast::ExpressionList params; for (uint32_t i = 0; i < num_params; ++i) { - params.push_back(vec4(1, 1, 1, 1)); + params.push_back(vec4(1u, 1u, 1u, 1u)); } auto* builtin = Call(name, params); WrapInFunction(builtin); diff --git a/src/writer/spirv/builder_constructor_expression_test.cc b/src/writer/spirv/builder_constructor_expression_test.cc index 6a11cb0854..e11f4ea560 100644 --- a/src/writer/spirv/builder_constructor_expression_test.cc +++ b/src/writer/spirv/builder_constructor_expression_test.cc @@ -141,7 +141,7 @@ TEST_F(SpvBuilderConstructorTest, Type_IdentifierExpression_Param) { } TEST_F(SpvBuilderConstructorTest, Vector_Bitcast_Params) { - auto* t = vec2(1, 1); + auto* t = vec2(Construct(1), Construct(1)); WrapInFunction(t); spirv::Builder& b = Build(); @@ -153,14 +153,14 @@ TEST_F(SpvBuilderConstructorTest, Vector_Bitcast_Params) { EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0 %1 = OpTypeVector %2 2 -%3 = OpTypeInt 32 1 -%4 = OpConstant %3 1 +%4 = OpTypeInt 32 1 +%5 = OpConstant %4 1 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%5 = OpBitcast %2 %4 -%6 = OpBitcast %2 %4 -%7 = OpCompositeConstruct %1 %5 %6 + R"(%3 = OpBitcast %2 %5 +%6 = OpBitcast %2 %5 +%7 = OpCompositeConstruct %1 %3 %6 )"); } @@ -1450,7 +1450,7 @@ TEST_F(SpvBuilderConstructorTest, TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithMatchingTypeConstructors) { - // vec3(f32(1.0), f32(2.0)) -> false + // vec2(f32(1.0), f32(2.0)) -> false auto* t = vec2(Construct(1.f), Construct(2.f)); WrapInFunction(t); @@ -1463,7 +1463,7 @@ TEST_F(SpvBuilderConstructorTest, TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalWithTypeCastConstructor) { - // vec3(f32(1), f32(2)) -> false + // vec2(f32(1), f32(2)) -> false auto* t = vec2(Construct(1), Construct(2)); WrapInFunction(t); @@ -1521,22 +1521,10 @@ TEST_F(SpvBuilderConstructorTest, } TEST_F(SpvBuilderConstructorTest, - IsConstructorConst_VectorWith_TypeCastConstConstructors) { + IsConstructorConst_VectorWithTypeCastConstConstructors) { // vec2(f32(1), f32(2)) -> false - auto* t = vec2(1, 2); - WrapInFunction(t); - - spirv::Builder& b = Build(); - - EXPECT_FALSE(b.is_constructor_const(t, false)); - EXPECT_FALSE(b.has_error()); -} - -TEST_F(SpvBuilderConstructorTest, IsConstructorConst_WithTypeCastConstructor) { - // vec3(f32(1), f32(2)) -> false - - auto* t = vec3(1, 2); + auto* t = vec2(Construct(1), Construct(2)); WrapInFunction(t); spirv::Builder& b = Build(); @@ -1546,7 +1534,7 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_WithTypeCastConstructor) { } TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) { - auto* t = vec2(1, 1); + auto* t = vec2(Construct(1), Construct(1)); WrapInFunction(t); spirv::Builder& b = Build();