1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/resolver/resolver.h"
16
17 #include "gmock/gmock.h"
18 #include "src/resolver/resolver_test_helper.h"
19 #include "src/sem/reference_type.h"
20
21 namespace tint {
22 namespace resolver {
23 namespace {
24
25 using ResolverIndexAccessorTest = ResolverTest;
26
TEST_F(ResolverIndexAccessorTest,Matrix_Dynamic_F32)27 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
28 Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
29 auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1.0f));
30 WrapInFunction(acc);
31
32 EXPECT_FALSE(r()->Resolve());
33 EXPECT_EQ(r()->error(),
34 "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
35 }
36
TEST_F(ResolverIndexAccessorTest,Matrix_Dynamic_Ref)37 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
38 Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
39 auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
40 auto* acc = IndexAccessor("my_var", idx);
41 WrapInFunction(Decl(idx), acc);
42
43 EXPECT_TRUE(r()->Resolve()) << r()->error();
44 }
45
TEST_F(ResolverIndexAccessorTest,Matrix_BothDimensions_Dynamic_Ref)46 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions_Dynamic_Ref) {
47 Global("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
48 auto* idx = Var("idx", ty.u32(), Expr(3u));
49 auto* idy = Var("idy", ty.u32(), Expr(2u));
50 auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
51 WrapInFunction(Decl(idx), Decl(idy), acc);
52
53 EXPECT_TRUE(r()->Resolve()) << r()->error();
54 }
55
TEST_F(ResolverIndexAccessorTest,Matrix_Dynamic)56 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic) {
57 GlobalConst("my_const", ty.mat2x3<f32>(), Construct(ty.mat2x3<f32>()));
58 auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
59 auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
60 WrapInFunction(Decl(idx), acc);
61
62 EXPECT_FALSE(r()->Resolve());
63 EXPECT_EQ(r()->error(),
64 "12:34 error: index must be signed or unsigned integer literal");
65 }
66
TEST_F(ResolverIndexAccessorTest,Matrix_XDimension_Dynamic)67 TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic) {
68 GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
69 auto* idx = Var("idx", ty.u32(), Expr(3u));
70 auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
71 WrapInFunction(Decl(idx), acc);
72
73 EXPECT_FALSE(r()->Resolve());
74 EXPECT_EQ(r()->error(),
75 "12:34 error: index must be signed or unsigned integer literal");
76 }
77
TEST_F(ResolverIndexAccessorTest,Matrix_BothDimension_Dynamic)78 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
79 GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
80 auto* idx = Var("idy", ty.u32(), Expr(2u));
81 auto* acc =
82 IndexAccessor(IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)), 1);
83 WrapInFunction(Decl(idx), acc);
84
85 EXPECT_FALSE(r()->Resolve());
86 EXPECT_EQ(r()->error(),
87 "12:34 error: index must be signed or unsigned integer literal");
88 }
89
TEST_F(ResolverIndexAccessorTest,Matrix)90 TEST_F(ResolverIndexAccessorTest, Matrix) {
91 Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
92
93 auto* acc = IndexAccessor("my_var", 2);
94 WrapInFunction(acc);
95
96 EXPECT_TRUE(r()->Resolve()) << r()->error();
97
98 ASSERT_NE(TypeOf(acc), nullptr);
99 ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
100
101 auto* ref = TypeOf(acc)->As<sem::Reference>();
102 ASSERT_TRUE(ref->StoreType()->Is<sem::Vector>());
103 EXPECT_EQ(ref->StoreType()->As<sem::Vector>()->Width(), 3u);
104 }
105
TEST_F(ResolverIndexAccessorTest,Matrix_BothDimensions)106 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
107 Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
108
109 auto* acc = IndexAccessor(IndexAccessor("my_var", 2), 1);
110 WrapInFunction(acc);
111
112 EXPECT_TRUE(r()->Resolve()) << r()->error();
113
114 ASSERT_NE(TypeOf(acc), nullptr);
115 ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
116
117 auto* ref = TypeOf(acc)->As<sem::Reference>();
118 EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
119 }
120
TEST_F(ResolverIndexAccessorTest,Vector_F32)121 TEST_F(ResolverIndexAccessorTest, Vector_F32) {
122 Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
123 auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2.0f));
124 WrapInFunction(acc);
125
126 EXPECT_FALSE(r()->Resolve());
127 EXPECT_EQ(r()->error(),
128 "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
129 }
130
TEST_F(ResolverIndexAccessorTest,Vector_Dynamic_Ref)131 TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Ref) {
132 Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
133 auto* idx = Var("idx", ty.i32(), Expr(2));
134 auto* acc = IndexAccessor("my_var", idx);
135 WrapInFunction(Decl(idx), acc);
136
137 EXPECT_TRUE(r()->Resolve());
138 }
139
TEST_F(ResolverIndexAccessorTest,Vector_Dynamic)140 TEST_F(ResolverIndexAccessorTest, Vector_Dynamic) {
141 GlobalConst("my_var", ty.vec3<f32>(), Construct(ty.vec3<f32>()));
142 auto* idx = Var("idx", ty.i32(), Expr(2));
143 auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
144 WrapInFunction(Decl(idx), acc);
145
146 EXPECT_TRUE(r()->Resolve());
147 }
148
TEST_F(ResolverIndexAccessorTest,Vector)149 TEST_F(ResolverIndexAccessorTest, Vector) {
150 Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
151
152 auto* acc = IndexAccessor("my_var", 2);
153 WrapInFunction(acc);
154
155 EXPECT_TRUE(r()->Resolve()) << r()->error();
156
157 ASSERT_NE(TypeOf(acc), nullptr);
158 ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
159
160 auto* ref = TypeOf(acc)->As<sem::Reference>();
161 EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
162 }
163
TEST_F(ResolverIndexAccessorTest,Array)164 TEST_F(ResolverIndexAccessorTest, Array) {
165 auto* idx = Expr(2);
166 Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
167
168 auto* acc = IndexAccessor("my_var", idx);
169 WrapInFunction(acc);
170
171 EXPECT_TRUE(r()->Resolve()) << r()->error();
172
173 ASSERT_NE(TypeOf(acc), nullptr);
174 ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
175
176 auto* ref = TypeOf(acc)->As<sem::Reference>();
177 EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
178 }
179
TEST_F(ResolverIndexAccessorTest,Alias_Array)180 TEST_F(ResolverIndexAccessorTest, Alias_Array) {
181 auto* aary = Alias("myarrty", ty.array<f32, 3>());
182
183 Global("my_var", ty.Of(aary), ast::StorageClass::kPrivate);
184
185 auto* acc = IndexAccessor("my_var", 2);
186 WrapInFunction(acc);
187
188 EXPECT_TRUE(r()->Resolve()) << r()->error();
189
190 ASSERT_NE(TypeOf(acc), nullptr);
191 ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
192
193 auto* ref = TypeOf(acc)->As<sem::Reference>();
194 EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
195 }
196
TEST_F(ResolverIndexAccessorTest,Array_Constant)197 TEST_F(ResolverIndexAccessorTest, Array_Constant) {
198 GlobalConst("my_var", ty.array<f32, 3>(), array<f32, 3>());
199
200 auto* acc = IndexAccessor("my_var", 2);
201 WrapInFunction(acc);
202
203 EXPECT_TRUE(r()->Resolve()) << r()->error();
204
205 ASSERT_NE(TypeOf(acc), nullptr);
206 EXPECT_TRUE(TypeOf(acc)->Is<sem::F32>()) << TypeOf(acc)->type_name();
207 }
208
TEST_F(ResolverIndexAccessorTest,Array_Dynamic_I32)209 TEST_F(ResolverIndexAccessorTest, Array_Dynamic_I32) {
210 // let a : array<f32, 3> = 0;
211 // var idx : i32 = 0;
212 // var f : f32 = a[idx];
213 auto* a = Const("a", ty.array<f32, 3>(), array<f32, 3>());
214 auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
215 auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
216 Func("my_func", ast::VariableList{}, ty.void_(),
217 {
218 Decl(a),
219 Decl(idx),
220 Decl(f),
221 },
222 ast::DecorationList{});
223
224 EXPECT_FALSE(r()->Resolve());
225 EXPECT_EQ(r()->error(),
226 "12:34 error: index must be signed or unsigned integer literal");
227 }
228
TEST_F(ResolverIndexAccessorTest,Array_Literal_F32)229 TEST_F(ResolverIndexAccessorTest, Array_Literal_F32) {
230 // let a : array<f32, 3>;
231 // var f : f32 = a[2.0f];
232 auto* a = Const("a", ty.array<f32, 3>(), array<f32, 3>());
233 auto* f =
234 Var("a_2", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, 2.0f)));
235 Func("my_func", ast::VariableList{}, ty.void_(),
236 {
237 Decl(a),
238 Decl(f),
239 },
240 ast::DecorationList{});
241 EXPECT_FALSE(r()->Resolve());
242 EXPECT_EQ(r()->error(),
243 "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
244 }
245
TEST_F(ResolverIndexAccessorTest,Array_Literal_I32)246 TEST_F(ResolverIndexAccessorTest, Array_Literal_I32) {
247 // let a : array<f32, 3>;
248 // var f : f32 = a[2];
249 auto* a = Const("a", ty.array<f32, 3>(), array<f32, 3>());
250 auto* f = Var("a_2", ty.f32(), IndexAccessor("a", 2));
251 Func("my_func", ast::VariableList{}, ty.void_(),
252 {
253 Decl(a),
254 Decl(f),
255 },
256 ast::DecorationList{});
257 EXPECT_TRUE(r()->Resolve()) << r()->error();
258 }
259
TEST_F(ResolverIndexAccessorTest,EXpr_Deref_FuncGoodParent)260 TEST_F(ResolverIndexAccessorTest, EXpr_Deref_FuncGoodParent) {
261 // fn func(p: ptr<function, vec4<f32>>) -> f32 {
262 // let idx: u32 = u32();
263 // let x: f32 = (*p)[idx];
264 // return x;
265 // }
266 auto* p =
267 Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
268 auto* idx = Const("idx", ty.u32(), Construct(ty.u32()));
269 auto* star_p = Deref(p);
270 auto* accessor_expr = IndexAccessor(Source{{12, 34}}, star_p, idx);
271 auto* x = Var("x", ty.f32(), accessor_expr);
272 Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
273
274 EXPECT_TRUE(r()->Resolve()) << r()->error();
275 }
276
TEST_F(ResolverIndexAccessorTest,EXpr_Deref_FuncBadParent)277 TEST_F(ResolverIndexAccessorTest, EXpr_Deref_FuncBadParent) {
278 // fn func(p: ptr<function, vec4<f32>>) -> f32 {
279 // let idx: u32 = u32();
280 // let x: f32 = *p[idx];
281 // return x;
282 // }
283 auto* p =
284 Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
285 auto* idx = Const("idx", ty.u32(), Construct(ty.u32()));
286 auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
287 auto* star_p = Deref(accessor_expr);
288 auto* x = Var("x", ty.f32(), star_p);
289 Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
290
291 EXPECT_FALSE(r()->Resolve());
292 EXPECT_EQ(
293 r()->error(),
294 "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
295 }
296
TEST_F(ResolverIndexAccessorTest,Exr_Deref_BadParent)297 TEST_F(ResolverIndexAccessorTest, Exr_Deref_BadParent) {
298 // var param: vec4<f32>
299 // let x: f32 = *(¶m)[0];
300 auto* param = Var("param", ty.vec4<f32>());
301 auto* idx = Var("idx", ty.u32(), Construct(ty.u32()));
302 auto* addressOf_expr = AddressOf(param);
303 auto* accessor_expr = IndexAccessor(Source{{12, 34}}, addressOf_expr, idx);
304 auto* star_p = Deref(accessor_expr);
305 auto* x = Var("x", ty.f32(), star_p);
306 WrapInFunction(param, idx, x);
307
308 EXPECT_FALSE(r()->Resolve());
309 EXPECT_EQ(
310 r()->error(),
311 "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
312 }
313
314 } // namespace
315 } // namespace resolver
316 } // namespace tint
317