// Copyright 2021 The Tint Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/resolver/resolver.h" #include "gmock/gmock.h" #include "src/resolver/resolver_test_helper.h" #include "src/sem/reference_type.h" namespace tint { namespace resolver { namespace { using ResolverArrayAccessorTest = ResolverTest; TEST_F(ResolverArrayAccessorTest, Matrix_Dynamic_F32) { Global("my_var", ty.mat2x3(), ast::StorageClass::kPrivate); auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1.0f)); WrapInFunction(acc); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'"); } TEST_F(ResolverArrayAccessorTest, Matrix_Dynamic_Ref) { Global("my_var", ty.mat2x3(), ast::StorageClass::kPrivate); auto* idx = Var("idx", ty.i32(), Construct(ty.i32())); auto* acc = IndexAccessor("my_var", idx); WrapInFunction(Decl(idx), acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); } TEST_F(ResolverArrayAccessorTest, Matrix_BothDimensions_Dynamic_Ref) { Global("my_var", ty.mat4x4(), ast::StorageClass::kPrivate); auto* idx = Var("idx", ty.u32(), Expr(3u)); auto* idy = Var("idy", ty.u32(), Expr(2u)); auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy); WrapInFunction(Decl(idx), Decl(idy), acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); } TEST_F(ResolverArrayAccessorTest, Matrix_Dynamic) { GlobalConst("my_const", ty.mat2x3(), Construct(ty.mat2x3())); auto* idx = Var("idx", ty.i32(), Construct(ty.i32())); auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx)); WrapInFunction(Decl(idx), acc); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be signed or unsigned integer literal"); } TEST_F(ResolverArrayAccessorTest, Matrix_XDimension_Dynamic) { GlobalConst("my_var", ty.mat4x4(), Construct(ty.mat4x4())); auto* idx = Var("idx", ty.u32(), Expr(3u)); auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)); WrapInFunction(Decl(idx), acc); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be signed or unsigned integer literal"); } TEST_F(ResolverArrayAccessorTest, Matrix_BothDimension_Dynamic) { GlobalConst("my_var", ty.mat4x4(), Construct(ty.mat4x4())); auto* idx = Var("idy", ty.u32(), Expr(2u)); auto* acc = IndexAccessor(IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)), 1); WrapInFunction(Decl(idx), acc); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be signed or unsigned integer literal"); } TEST_F(ResolverArrayAccessorTest, Matrix) { Global("my_var", ty.mat2x3(), ast::StorageClass::kPrivate); auto* acc = IndexAccessor("my_var", 2); WrapInFunction(acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); ASSERT_NE(TypeOf(acc), nullptr); ASSERT_TRUE(TypeOf(acc)->Is()); auto* ref = TypeOf(acc)->As(); ASSERT_TRUE(ref->StoreType()->Is()); EXPECT_EQ(ref->StoreType()->As()->Width(), 3u); } TEST_F(ResolverArrayAccessorTest, Matrix_BothDimensions) { Global("my_var", ty.mat2x3(), ast::StorageClass::kPrivate); auto* acc = IndexAccessor(IndexAccessor("my_var", 2), 1); WrapInFunction(acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); ASSERT_NE(TypeOf(acc), nullptr); ASSERT_TRUE(TypeOf(acc)->Is()); auto* ref = TypeOf(acc)->As(); EXPECT_TRUE(ref->StoreType()->Is()); } TEST_F(ResolverArrayAccessorTest, Vector_F32) { Global("my_var", ty.vec3(), ast::StorageClass::kPrivate); auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2.0f)); WrapInFunction(acc); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'"); } TEST_F(ResolverArrayAccessorTest, Vector_Dynamic_Ref) { Global("my_var", ty.vec3(), ast::StorageClass::kPrivate); auto* idx = Var("idx", ty.i32(), Expr(2)); auto* acc = IndexAccessor("my_var", idx); WrapInFunction(Decl(idx), acc); EXPECT_TRUE(r()->Resolve()); } TEST_F(ResolverArrayAccessorTest, Vector_Dynamic) { GlobalConst("my_var", ty.vec3(), Construct(ty.vec3())); auto* idx = Var("idx", ty.i32(), Expr(2)); auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)); WrapInFunction(Decl(idx), acc); EXPECT_TRUE(r()->Resolve()); } TEST_F(ResolverArrayAccessorTest, Vector) { Global("my_var", ty.vec3(), ast::StorageClass::kPrivate); auto* acc = IndexAccessor("my_var", 2); WrapInFunction(acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); ASSERT_NE(TypeOf(acc), nullptr); ASSERT_TRUE(TypeOf(acc)->Is()); auto* ref = TypeOf(acc)->As(); EXPECT_TRUE(ref->StoreType()->Is()); } TEST_F(ResolverArrayAccessorTest, Array) { auto* idx = Expr(2); Global("my_var", ty.array(), ast::StorageClass::kPrivate); auto* acc = IndexAccessor("my_var", idx); WrapInFunction(acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); ASSERT_NE(TypeOf(acc), nullptr); ASSERT_TRUE(TypeOf(acc)->Is()); auto* ref = TypeOf(acc)->As(); EXPECT_TRUE(ref->StoreType()->Is()); } TEST_F(ResolverArrayAccessorTest, Alias_Array) { auto* aary = Alias("myarrty", ty.array()); Global("my_var", ty.Of(aary), ast::StorageClass::kPrivate); auto* acc = IndexAccessor("my_var", 2); WrapInFunction(acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); ASSERT_NE(TypeOf(acc), nullptr); ASSERT_TRUE(TypeOf(acc)->Is()); auto* ref = TypeOf(acc)->As(); EXPECT_TRUE(ref->StoreType()->Is()); } TEST_F(ResolverArrayAccessorTest, Array_Constant) { GlobalConst("my_var", ty.array(), array()); auto* acc = IndexAccessor("my_var", 2); WrapInFunction(acc); EXPECT_TRUE(r()->Resolve()) << r()->error(); ASSERT_NE(TypeOf(acc), nullptr); EXPECT_TRUE(TypeOf(acc)->Is()) << TypeOf(acc)->type_name(); } TEST_F(ResolverArrayAccessorTest, Array_Dynamic_I32) { // let a : array = 0; // var idx : i32 = 0; // var f : f32 = a[idx]; auto* a = Const("a", ty.array(), array()); auto* idx = Var("idx", ty.i32(), Construct(ty.i32())); auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx))); Func("my_func", ast::VariableList{}, ty.void_(), { Decl(a), Decl(idx), Decl(f), }, ast::DecorationList{}); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be signed or unsigned integer literal"); } TEST_F(ResolverArrayAccessorTest, Array_Literal_F32) { // let a : array; // var f : f32 = a[2.0f]; auto* a = Const("a", ty.array(), array()); auto* f = Var("a_2", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, 2.0f))); Func("my_func", ast::VariableList{}, ty.void_(), { Decl(a), Decl(f), }, ast::DecorationList{}); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'"); } TEST_F(ResolverArrayAccessorTest, Array_Literal_I32) { // let a : array; // var f : f32 = a[2]; auto* a = Const("a", ty.array(), array()); auto* f = Var("a_2", ty.f32(), IndexAccessor("a", 2)); Func("my_func", ast::VariableList{}, ty.void_(), { Decl(a), Decl(f), }, ast::DecorationList{}); EXPECT_TRUE(r()->Resolve()) << r()->error(); } } // namespace } // namespace resolver } // namespace tint