blob: 63811e2cd605d818a76f76008dbbfc773337f1be [file] [log] [blame]
Ben Clayton2c41f4f2021-03-09 15:12:57 +00001// 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/ast/assignment_statement.h"
19#include "src/ast/bitcast_expression.h"
20#include "src/ast/break_statement.h"
21#include "src/ast/call_statement.h"
22#include "src/ast/continue_statement.h"
23#include "src/ast/if_statement.h"
24#include "src/ast/intrinsic_texture_helper_test.h"
25#include "src/ast/loop_statement.h"
26#include "src/ast/return_statement.h"
27#include "src/ast/stage_decoration.h"
28#include "src/ast/switch_statement.h"
29#include "src/ast/unary_op_expression.h"
30#include "src/ast/variable_decl_statement.h"
31#include "src/resolver/resolver_test_helper.h"
32#include "src/semantic/call.h"
33#include "src/semantic/function.h"
34#include "src/semantic/member_accessor_expression.h"
35#include "src/semantic/statement.h"
36#include "src/semantic/variable.h"
37#include "src/type/access_control_type.h"
38#include "src/type/sampled_texture_type.h"
39
40using ::testing::ElementsAre;
41using ::testing::HasSubstr;
42
43namespace tint {
44namespace resolver {
45namespace {
46
47using ResolverValidationTest = ResolverTest;
48
49class FakeStmt : public ast::Statement {
50 public:
51 explicit FakeStmt(Source source) : ast::Statement(source) {}
52 FakeStmt* Clone(CloneContext*) const override { return nullptr; }
Ben Clayton2c41f4f2021-03-09 15:12:57 +000053 void to_str(const semantic::Info&, std::ostream& out, size_t) const override {
54 out << "Fake";
55 }
56};
57
58class FakeExpr : public ast::Expression {
59 public:
60 explicit FakeExpr(Source source) : ast::Expression(source) {}
61 FakeExpr* Clone(CloneContext*) const override { return nullptr; }
Ben Clayton2c41f4f2021-03-09 15:12:57 +000062 void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
63};
64
65TEST_F(ResolverValidationTest, Error_WithEmptySource) {
66 auto* s = create<FakeStmt>();
67 WrapInFunction(s);
68
69 EXPECT_FALSE(r()->Resolve());
70
71 EXPECT_EQ(r()->error(),
72 "error: unknown statement type for type determination: Fake");
73}
74
75TEST_F(ResolverValidationTest, Stmt_Error_Unknown) {
76 auto* s = create<FakeStmt>(Source{Source::Location{2, 30}});
77 WrapInFunction(s);
78
79 EXPECT_FALSE(r()->Resolve());
80
81 EXPECT_EQ(r()->error(),
82 "2:30 error: unknown statement type for type determination: Fake");
83}
84
85TEST_F(ResolverValidationTest, Stmt_Call_undeclared) {
86 // fn main() -> void {func(); return; }
87 // fn func() -> void { return; }
88
89 SetSource(Source::Location{12, 34});
90 auto* call_expr = Call("func");
91 ast::VariableList params0;
92
93 Func("main", params0, ty.f32(),
94 ast::StatementList{
95 create<ast::CallStatement>(call_expr),
96 create<ast::ReturnStatement>(),
97 },
98 ast::FunctionDecorationList{});
99
100 Func("func", params0, ty.f32(),
101 ast::StatementList{
102 create<ast::ReturnStatement>(),
103 },
104 ast::FunctionDecorationList{});
105
106 EXPECT_FALSE(r()->Resolve());
107
108 EXPECT_EQ(r()->error(),
109 "12:34 error: v-0006: unable to find called function: func");
110}
111
112TEST_F(ResolverValidationTest, Stmt_Call_recursive) {
113 // fn main() -> void {main(); }
114
115 SetSource(Source::Location{12, 34});
116 auto* call_expr = Call("main");
117 ast::VariableList params0;
118
119 Func("main", params0, ty.f32(),
120 ast::StatementList{
121 create<ast::CallStatement>(call_expr),
122 },
123 ast::FunctionDecorationList{
124 create<ast::StageDecoration>(ast::PipelineStage::kVertex),
125 });
126
127 EXPECT_FALSE(r()->Resolve());
128
129 EXPECT_EQ(r()->error(),
130 "12:34 error: recursion is not permitted. 'main' attempted to call "
131 "itself.");
132}
133
Ben Clayton5fb87dd2021-03-09 15:17:28 +0000134TEST_F(ResolverValidationTest, Stmt_If_NonBool) {
135 // if (1.23f) {}
136
137 WrapInFunction(If(create<ast::ScalarConstructorExpression>(Source{{12, 34}},
138 Literal(1.23f)),
139 Block()));
140
141 EXPECT_FALSE(r()->Resolve());
142
143 EXPECT_EQ(r()->error(),
144 "12:34 error: if statement condition must be bool, got f32");
145}
146
Ben Clayton2c41f4f2021-03-09 15:12:57 +0000147TEST_F(ResolverValidationTest,
148 Stmt_VariableDecl_MismatchedTypeScalarConstructor) {
149 u32 unsigned_value = 2u; // Type does not match variable type
150 auto* var =
151 Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(unsigned_value));
152
153 auto* decl =
154 create<ast::VariableDeclStatement>(Source{{{3, 3}, {3, 22}}}, var);
155 WrapInFunction(decl);
156
157 EXPECT_FALSE(r()->Resolve());
158 EXPECT_EQ(
159 r()->error(),
160 R"(3:3 error: constructor expression type does not match variable type)");
161}
162
163TEST_F(ResolverValidationTest,
164 Stmt_VariableDecl_MismatchedTypeScalarConstructor_Alias) {
165 auto* my_int = ty.alias("MyInt", ty.i32());
166 u32 unsigned_value = 2u; // Type does not match variable type
167 auto* var =
168 Var("my_var", my_int, ast::StorageClass::kNone, Expr(unsigned_value));
169
170 auto* decl =
171 create<ast::VariableDeclStatement>(Source{{{3, 3}, {3, 22}}}, var);
172 WrapInFunction(decl);
173
174 EXPECT_FALSE(r()->Resolve());
175 EXPECT_EQ(
176 r()->error(),
177 R"(3:3 error: constructor expression type does not match variable type)");
178}
179
180TEST_F(ResolverValidationTest, Expr_Error_Unknown) {
181 FakeExpr e(Source{Source::Location{2, 30}});
182 WrapInFunction(&e);
183
184 EXPECT_FALSE(r()->Resolve());
185
186 EXPECT_EQ(r()->error(),
187 "2:30 error: unknown expression for type determination");
188}
189
190TEST_F(ResolverValidationTest, Expr_DontCall_Function) {
191 Func("func", {}, ty.void_(), {}, {});
192 auto* ident = create<ast::IdentifierExpression>(
193 Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
194 Symbols().Register("func"));
195 WrapInFunction(ident);
196
197 EXPECT_FALSE(r()->Resolve());
198 EXPECT_EQ(r()->error(), "3:8 error: missing '(' for function call");
199}
200
201TEST_F(ResolverValidationTest, Expr_DontCall_Intrinsic) {
202 auto* ident = create<ast::IdentifierExpression>(
203 Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
204 Symbols().Register("round"));
205 WrapInFunction(ident);
206
207 EXPECT_FALSE(r()->Resolve());
208 EXPECT_EQ(r()->error(), "3:8 error: missing '(' for intrinsic call");
209}
210
211TEST_F(ResolverValidationTest, UsingUndefinedVariable_Fail) {
212 // b = 2;
213
214 SetSource(Source{Source::Location{12, 34}});
215 auto* lhs = Expr("b");
216 auto* rhs = Expr(2);
217 auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
218 WrapInFunction(assign);
219
220 EXPECT_FALSE(r()->Resolve());
221 EXPECT_EQ(r()->error(),
222 "12:34 error: v-0006: identifier must be declared before use: b");
223}
224
225TEST_F(ResolverValidationTest, UsingUndefinedVariableInBlockStatement_Fail) {
226 // {
227 // b = 2;
228 // }
229
230 SetSource(Source{Source::Location{12, 34}});
231 auto* lhs = Expr("b");
232 auto* rhs = Expr(2);
233
234 auto* body = create<ast::BlockStatement>(ast::StatementList{
235 create<ast::AssignmentStatement>(lhs, rhs),
236 });
237 WrapInFunction(body);
238
239 EXPECT_FALSE(r()->Resolve());
240 EXPECT_EQ(r()->error(),
241 "12:34 error: v-0006: identifier must be declared before use: b");
242}
243
244TEST_F(ResolverValidationTest, StorageClass_NonFunctionClassError) {
245 auto* var = Var("var", ty.i32(), ast::StorageClass::kWorkgroup);
246
247 auto* stmt = create<ast::VariableDeclStatement>(var);
248 Func("func", ast::VariableList{}, ty.i32(), ast::StatementList{stmt},
249 ast::FunctionDecorationList{});
250
251 EXPECT_FALSE(r()->Resolve());
252
253 EXPECT_EQ(r()->error(),
254 "error: function variable has a non-function storage class");
255}
256
257TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
258 Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kNone);
259
260 auto* ident = create<ast::IdentifierExpression>(
261 Source{{Source::Location{3, 3}, Source::Location{3, 7}}},
262 Symbols().Register("xyqz"));
263
264 auto* mem = MemberAccessor("my_vec", ident);
265 WrapInFunction(mem);
266
267 EXPECT_FALSE(r()->Resolve());
268 EXPECT_EQ(r()->error(), "3:5 error: invalid vector swizzle character");
269}
270
271TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
272 Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kNone);
273
274 auto* ident = create<ast::IdentifierExpression>(
275 Source{{Source::Location{3, 3}, Source::Location{3, 7}}},
276 Symbols().Register("rgyw"));
277
278 auto* mem = MemberAccessor("my_vec", ident);
279 WrapInFunction(mem);
280
281 EXPECT_FALSE(r()->Resolve());
282 EXPECT_EQ(
283 r()->error(),
284 "3:3 error: invalid mixing of vector swizzle characters rgba with xyzw");
285}
286
287TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
288 Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kNone);
289
290 auto* ident = create<ast::IdentifierExpression>(
291 Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
292 Symbols().Register("zzzzz"));
293 auto* mem = MemberAccessor("my_vec", ident);
294 WrapInFunction(mem);
295
296 EXPECT_FALSE(r()->Resolve());
297 EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle size");
298}
299
300TEST_F(ResolverValidationTest,
301 Stmt_Loop_ContinueInLoopBodyBeforeDecl_UsageInContinuing) {
302 // loop {
303 // continue; // Bypasses z decl
304 // var z : i32;
305 //
306 // continuing {
307 // z = 2;
308 // }
309 // }
310
311 auto error_loc = Source{Source::Location{12, 34}};
312 auto* body = Block(create<ast::ContinueStatement>(),
313 Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
314 auto* continuing = Block(Assign(Expr(error_loc, "z"), Expr(2)));
315 auto* loop_stmt = Loop(body, continuing);
316 WrapInFunction(loop_stmt);
317
318 EXPECT_FALSE(r()->Resolve()) << r()->error();
319 EXPECT_EQ(r()->error(),
320 "12:34 error: continue statement bypasses declaration of 'z' in "
321 "continuing block");
322}
323
324TEST_F(ResolverValidationTest,
325 Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing) {
326 // loop {
327 // continue; // Bypasses z decl
328 // var z : i32;
329 // continue; // Ok
330 //
331 // continuing {
332 // z = 2;
333 // }
334 // }
335
336 auto error_loc = Source{Source::Location{12, 34}};
337 auto* body = Block(create<ast::ContinueStatement>(),
338 Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),
339 create<ast::ContinueStatement>());
340 auto* continuing = Block(Assign(Expr(error_loc, "z"), Expr(2)));
341 auto* loop_stmt = Loop(body, continuing);
342 WrapInFunction(loop_stmt);
343
344 EXPECT_FALSE(r()->Resolve()) << r()->error();
345 EXPECT_EQ(r()->error(),
346 "12:34 error: continue statement bypasses declaration of 'z' in "
347 "continuing block");
348}
349
350TEST_F(ResolverValidationTest,
351 Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuing) {
352 // loop {
353 // if (true) {
354 // continue; // Still bypasses z decl (if we reach here)
355 // }
356 // var z : i32;
357 // continuing {
358 // z = 2;
359 // }
360 // }
361
362 auto error_loc = Source{Source::Location{12, 34}};
363 auto* body = Block(If(Expr(true), Block(create<ast::ContinueStatement>())),
364 Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
365 auto* continuing = Block(Assign(Expr(error_loc, "z"), Expr(2)));
366 auto* loop_stmt = Loop(body, continuing);
367 WrapInFunction(loop_stmt);
368
369 EXPECT_FALSE(r()->Resolve()) << r()->error();
370 EXPECT_EQ(r()->error(),
371 "12:34 error: continue statement bypasses declaration of 'z' in "
372 "continuing block");
373}
374
375TEST_F(
376 ResolverTest,
377 Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingSubscope) {
378 // loop {
379 // if (true) {
380 // continue; // Still bypasses z decl (if we reach here)
381 // }
382 // var z : i32;
383 // continuing {
384 // if (true) {
385 // z = 2; // Must fail even if z is in a sub-scope
386 // }
387 // }
388 // }
389
390 auto error_loc = Source{Source::Location{12, 34}};
391 auto* body = Block(If(Expr(true), Block(create<ast::ContinueStatement>())),
392 Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
393
394 auto* continuing =
395 Block(If(Expr(true), Block(Assign(Expr(error_loc, "z"), Expr(2)))));
396 auto* loop_stmt = Loop(body, continuing);
397 WrapInFunction(loop_stmt);
398
399 EXPECT_FALSE(r()->Resolve()) << r()->error();
400 EXPECT_EQ(r()->error(),
401 "12:34 error: continue statement bypasses declaration of 'z' in "
402 "continuing block");
403}
404
405TEST_F(ResolverValidationTest,
406 Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop) {
407 // loop {
408 // if (true) {
409 // continue; // Still bypasses z decl (if we reach here)
410 // }
411 // var z : i32;
412 // continuing {
413 // loop {
414 // z = 2; // Must fail even if z is in a sub-scope
415 // }
416 // }
417 // }
418
419 auto error_loc = Source{Source::Location{12, 34}};
420 auto* body = Block(If(Expr(true), Block(create<ast::ContinueStatement>())),
421 Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
422
423 auto* continuing = Block(Loop(Block(Assign(Expr(error_loc, "z"), Expr(2)))));
424 auto* loop_stmt = Loop(body, continuing);
425 WrapInFunction(loop_stmt);
426
427 EXPECT_FALSE(r()->Resolve()) << r()->error();
428 EXPECT_EQ(r()->error(),
429 "12:34 error: continue statement bypasses declaration of 'z' in "
430 "continuing block");
431}
432
433TEST_F(ResolverValidationTest,
434 Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuing) {
435 // loop {
436 // loop {
437 // continue; // OK: not part of the outer loop
438 // }
439 // var z : i32;
440 //
441 // continuing {
442 // z = 2;
443 // }
444 // }
445
446 auto* inner_loop = Loop(Block(create<ast::ContinueStatement>()));
447 auto* body =
448 Block(inner_loop, Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
449 auto* continuing = Block(Assign(Expr("z"), Expr(2)));
450 auto* loop_stmt = Loop(body, continuing);
451 WrapInFunction(loop_stmt);
452
453 EXPECT_TRUE(r()->Resolve()) << r()->error();
454}
455
456TEST_F(ResolverValidationTest,
457 Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingSubscope) {
458 // loop {
459 // loop {
460 // continue; // OK: not part of the outer loop
461 // }
462 // var z : i32;
463 //
464 // continuing {
465 // if (true) {
466 // z = 2;
467 // }
468 // }
469 // }
470
471 auto* inner_loop = Loop(Block(create<ast::ContinueStatement>()));
472 auto* body =
473 Block(inner_loop, Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
474 auto* continuing = Block(If(Expr(true), Block(Assign(Expr("z"), Expr(2)))));
475 auto* loop_stmt = Loop(body, continuing);
476 WrapInFunction(loop_stmt);
477
478 EXPECT_TRUE(r()->Resolve()) << r()->error();
479}
480
481TEST_F(ResolverValidationTest,
482 Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingLoop) {
483 // loop {
484 // loop {
485 // continue; // OK: not part of the outer loop
486 // }
487 // var z : i32;
488 //
489 // continuing {
490 // loop {
491 // z = 2;
492 // }
493 // }
494 // }
495
496 auto* inner_loop = Loop(Block(create<ast::ContinueStatement>()));
497 auto* body =
498 Block(inner_loop, Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
499 auto* continuing = Block(Loop(Block(Assign(Expr("z"), Expr(2)))));
500 auto* loop_stmt = Loop(body, continuing);
501 WrapInFunction(loop_stmt);
502
503 EXPECT_TRUE(r()->Resolve()) << r()->error();
504}
505
Ben Claytonf4c0d542021-03-10 23:15:09 +0000506TEST_F(ResolverTest, Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing) {
507 // loop {
508 // var z : i32;
509 // continue;
510 //
511 // continuing {
512 // z = 2;
513 // }
514 // }
515
516 auto error_loc = Source{Source::Location{12, 34}};
517 auto* body = Block(Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),
518 create<ast::ContinueStatement>());
519 auto* continuing = Block(Assign(Expr(error_loc, "z"), Expr(2)));
520 auto* loop_stmt = Loop(body, continuing);
521 WrapInFunction(loop_stmt);
522
523 EXPECT_TRUE(r()->Resolve());
524}
525
Ben Clayton2c41f4f2021-03-09 15:12:57 +0000526TEST_F(ResolverValidationTest, Stmt_ContinueInLoop) {
527 WrapInFunction(Loop(Block(create<ast::ContinueStatement>(Source{{12, 34}}))));
528 EXPECT_TRUE(r()->Resolve()) << r()->error();
529}
530
531TEST_F(ResolverValidationTest, Stmt_ContinueNotInLoop) {
532 WrapInFunction(create<ast::ContinueStatement>(Source{{12, 34}}));
533 EXPECT_FALSE(r()->Resolve());
534 EXPECT_EQ(r()->error(), "12:34 error: continue statement must be in a loop");
535}
536
537TEST_F(ResolverValidationTest, Stmt_BreakInLoop) {
538 WrapInFunction(Loop(Block(create<ast::BreakStatement>(Source{{12, 34}}))));
539 EXPECT_TRUE(r()->Resolve()) << r()->error();
540}
541
542TEST_F(ResolverValidationTest, Stmt_BreakInSwitch) {
543 WrapInFunction(Loop(Block(create<ast::SwitchStatement>(
544 Expr(1), ast::CaseStatementList{
545 create<ast::CaseStatement>(
546 ast::CaseSelectorList{Literal(1)},
547 Block(create<ast::BreakStatement>(Source{{12, 34}}))),
548 }))));
549 EXPECT_TRUE(r()->Resolve()) << r()->error();
550}
551
552TEST_F(ResolverValidationTest, Stmt_BreakNotInLoopOrSwitch) {
553 WrapInFunction(create<ast::BreakStatement>(Source{{12, 34}}));
554 EXPECT_FALSE(r()->Resolve());
555 EXPECT_EQ(r()->error(),
556 "12:34 error: break statement must be in a loop or switch case");
557}
558
559} // namespace
560} // namespace resolver
561} // namespace tint