diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index d16c95831f..9c302e42f9 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc @@ -2733,12 +2733,41 @@ bool Resolver::UnaryOp(ast::UnaryOpExpression* unary) { const sem::Type* type = nullptr; switch (unary->op()) { - case ast::UnaryOp::kComplement: - case ast::UnaryOp::kNegation: case ast::UnaryOp::kNot: // Result type matches the deref'd inner type. type_name = TypeNameOf(unary->expr()); type = expr_type->UnwrapRef(); + if (!type->Is() && !type->is_bool_vector()) { + AddError("cannot logical negate expression of type '" + + TypeNameOf(unary->expr()), + unary->expr()->source()); + return false; + } + break; + + case ast::UnaryOp::kComplement: + // Result type matches the deref'd inner type. + type_name = TypeNameOf(unary->expr()); + type = expr_type->UnwrapRef(); + if (!type->is_integer_scalar_or_vector()) { + AddError("cannot bitwise complement expression of type '" + + TypeNameOf(unary->expr()), + unary->expr()->source()); + return false; + } + break; + + case ast::UnaryOp::kNegation: + // Result type matches the deref'd inner type. + type_name = TypeNameOf(unary->expr()); + type = expr_type->UnwrapRef(); + if (!(type->IsAnyOf() || + type->is_signed_integer_vector() || type->is_float_vector())) { + AddError( + "cannot negate expression of type '" + TypeNameOf(unary->expr()), + unary->expr()->source()); + return false; + } break; case ast::UnaryOp::kAddressOf: diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc index 90fe982f47..bbd9051767 100644 --- a/src/resolver/resolver_test.cc +++ b/src/resolver/resolver_test.cc @@ -1917,7 +1917,13 @@ using UnaryOpExpressionTest = ResolverTestWithParam; TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) { auto op = GetParam(); - Global("ident", ty.vec4(), ast::StorageClass::kPrivate); + if (op == ast::UnaryOp::kNot) { + Global("ident", ty.vec4(), ast::StorageClass::kPrivate); + } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) { + Global("ident", ty.vec4(), ast::StorageClass::kPrivate); + } else { + Global("ident", ty.vec4(), ast::StorageClass::kPrivate); + } auto* der = create(op, Expr("ident")); WrapInFunction(der); @@ -1925,7 +1931,13 @@ TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) { ASSERT_NE(TypeOf(der), nullptr); ASSERT_TRUE(TypeOf(der)->Is()); - EXPECT_TRUE(TypeOf(der)->As()->type()->Is()); + if (op == ast::UnaryOp::kNot) { + EXPECT_TRUE(TypeOf(der)->As()->type()->Is()); + } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) { + EXPECT_TRUE(TypeOf(der)->As()->type()->Is()); + } else { + EXPECT_TRUE(TypeOf(der)->As()->type()->Is()); + } EXPECT_EQ(TypeOf(der)->As()->size(), 4u); } INSTANTIATE_TEST_SUITE_P(ResolverTest, @@ -2181,6 +2193,38 @@ TEST_F(ResolverTest, ASTNodeReachedTwice) { "encountered twice in the same AST of a Program"); } +TEST_F(ResolverTest, UnaryOp_Not) { + Global("ident", ty.vec4(), ast::StorageClass::kPrivate); + auto* der = create(ast::UnaryOp::kNot, + Expr(Source{{12, 34}}, "ident")); + WrapInFunction(der); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "12:34 error: cannot logical negate expression of type 'vec4"); +} + +TEST_F(ResolverTest, UnaryOp_Complement) { + Global("ident", ty.vec4(), ast::StorageClass::kPrivate); + auto* der = create(ast::UnaryOp::kComplement, + Expr(Source{{12, 34}}, "ident")); + WrapInFunction(der); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + "12:34 error: cannot bitwise complement expression of type 'vec4"); +} + +TEST_F(ResolverTest, UnaryOp_Negation) { + Global("ident", ty.u32(), ast::StorageClass::kPrivate); + auto* der = create(ast::UnaryOp::kNegation, + Expr(Source{{12, 34}}, "ident")); + WrapInFunction(der); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), "12:34 error: cannot negate expression of type 'u32"); +} } // namespace } // namespace resolver } // namespace tint diff --git a/src/writer/hlsl/generator_impl_unary_op_test.cc b/src/writer/hlsl/generator_impl_unary_op_test.cc index 667469203b..5fb7cd6d82 100644 --- a/src/writer/hlsl/generator_impl_unary_op_test.cc +++ b/src/writer/hlsl/generator_impl_unary_op_test.cc @@ -35,7 +35,7 @@ TEST_F(HlslUnaryOpTest, AddressOf) { } TEST_F(HlslUnaryOpTest, Complement) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.u32(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kComplement, Expr("expr")); WrapInFunction(op); @@ -64,7 +64,7 @@ TEST_F(HlslUnaryOpTest, Indirection) { } TEST_F(HlslUnaryOpTest, Not) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.bool_(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kNot, Expr("expr")); WrapInFunction(op); @@ -76,7 +76,7 @@ TEST_F(HlslUnaryOpTest, Not) { } TEST_F(HlslUnaryOpTest, Negation) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.i32(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kNegation, Expr("expr")); WrapInFunction(op); diff --git a/src/writer/msl/generator_impl_unary_op_test.cc b/src/writer/msl/generator_impl_unary_op_test.cc index 6918c45d2f..2dfe8a9d8e 100644 --- a/src/writer/msl/generator_impl_unary_op_test.cc +++ b/src/writer/msl/generator_impl_unary_op_test.cc @@ -34,7 +34,7 @@ TEST_F(MslUnaryOpTest, AddressOf) { } TEST_F(MslUnaryOpTest, Complement) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.i32(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kComplement, Expr("expr")); WrapInFunction(op); @@ -61,7 +61,7 @@ TEST_F(MslUnaryOpTest, Indirection) { } TEST_F(MslUnaryOpTest, Not) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.bool_(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kNot, Expr("expr")); WrapInFunction(op); @@ -72,7 +72,7 @@ TEST_F(MslUnaryOpTest, Not) { } TEST_F(MslUnaryOpTest, Negation) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.i32(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kNegation, Expr("expr")); WrapInFunction(op); diff --git a/src/writer/wgsl/generator_impl_unary_op_test.cc b/src/writer/wgsl/generator_impl_unary_op_test.cc index e3f5b0983f..16b1a62a17 100644 --- a/src/writer/wgsl/generator_impl_unary_op_test.cc +++ b/src/writer/wgsl/generator_impl_unary_op_test.cc @@ -34,7 +34,7 @@ TEST_F(WgslUnaryOpTest, AddressOf) { } TEST_F(WgslUnaryOpTest, Complement) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.u32(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kComplement, Expr("expr")); WrapInFunction(op); @@ -61,7 +61,7 @@ TEST_F(WgslUnaryOpTest, Indirection) { } TEST_F(WgslUnaryOpTest, Not) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.bool_(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kNot, Expr("expr")); WrapInFunction(op); @@ -72,7 +72,7 @@ TEST_F(WgslUnaryOpTest, Not) { } TEST_F(WgslUnaryOpTest, Negation) { - Global("expr", ty.f32(), ast::StorageClass::kPrivate); + Global("expr", ty.i32(), ast::StorageClass::kPrivate); auto* op = create(ast::UnaryOp::kNegation, Expr("expr")); WrapInFunction(op);