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 <string>
16 #include <tuple>
17 #include <utility>
18
19 #include "gmock/gmock.h"
20 #include "src/resolver/dependency_graph.h"
21 #include "src/resolver/resolver_test_helper.h"
22
23 namespace tint {
24 namespace resolver {
25 namespace {
26
27 using ::testing::ElementsAre;
28
29 template <typename T>
30 class ResolverDependencyGraphTestWithParam : public ResolverTestWithParam<T> {
31 public:
32 bool allow_out_of_order_decls = true;
33
Build(std::string expected_error="")34 DependencyGraph Build(std::string expected_error = "") {
35 DependencyGraph graph;
36 auto result = DependencyGraph::Build(this->AST(), this->Symbols(),
37 this->Diagnostics(), graph,
38 allow_out_of_order_decls);
39 if (expected_error.empty()) {
40 EXPECT_TRUE(result) << this->Diagnostics().str();
41 } else {
42 EXPECT_FALSE(result);
43 EXPECT_EQ(expected_error, this->Diagnostics().str());
44 }
45 return graph;
46 }
47 };
48
49 using ResolverDependencyGraphTest =
50 ResolverDependencyGraphTestWithParam<::testing::Test>;
51
52 ////////////////////////////////////////////////////////////////////////////////
53 // Parameterized test helpers
54 ////////////////////////////////////////////////////////////////////////////////
55
56 /// SymbolDeclKind is used by parameterized tests to enumerate the different
57 /// kinds of symbol declarations.
58 enum class SymbolDeclKind {
59 GlobalVar,
60 GlobalLet,
61 Alias,
62 Struct,
63 Function,
64 Parameter,
65 LocalVar,
66 LocalLet,
67 NestedLocalVar,
68 NestedLocalLet,
69 };
70
71 static constexpr SymbolDeclKind kAllSymbolDeclKinds[] = {
72 SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalLet,
73 SymbolDeclKind::Alias, SymbolDeclKind::Struct,
74 SymbolDeclKind::Function, SymbolDeclKind::Parameter,
75 SymbolDeclKind::LocalVar, SymbolDeclKind::LocalLet,
76 SymbolDeclKind::NestedLocalVar, SymbolDeclKind::NestedLocalLet,
77 };
78
79 static constexpr SymbolDeclKind kTypeDeclKinds[] = {
80 SymbolDeclKind::Alias,
81 SymbolDeclKind::Struct,
82 };
83
84 static constexpr SymbolDeclKind kValueDeclKinds[] = {
85 SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalLet,
86 SymbolDeclKind::Parameter, SymbolDeclKind::LocalVar,
87 SymbolDeclKind::LocalLet, SymbolDeclKind::NestedLocalVar,
88 SymbolDeclKind::NestedLocalLet,
89 };
90
91 static constexpr SymbolDeclKind kGlobalDeclKinds[] = {
92 SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalLet, SymbolDeclKind::Alias,
93 SymbolDeclKind::Struct, SymbolDeclKind::Function,
94 };
95
96 static constexpr SymbolDeclKind kLocalDeclKinds[] = {
97 SymbolDeclKind::Parameter, SymbolDeclKind::LocalVar,
98 SymbolDeclKind::LocalLet, SymbolDeclKind::NestedLocalVar,
99 SymbolDeclKind::NestedLocalLet,
100 };
101
102 static constexpr SymbolDeclKind kGlobalValueDeclKinds[] = {
103 SymbolDeclKind::GlobalVar,
104 SymbolDeclKind::GlobalLet,
105 };
106
107 static constexpr SymbolDeclKind kFuncDeclKinds[] = {
108 SymbolDeclKind::Function,
109 };
110
111 /// SymbolUseKind is used by parameterized tests to enumerate the different
112 /// kinds of symbol uses.
113 enum class SymbolUseKind {
114 GlobalVarType,
115 GlobalVarArrayElemType,
116 GlobalVarArraySizeValue,
117 GlobalVarVectorElemType,
118 GlobalVarMatrixElemType,
119 GlobalVarSampledTexElemType,
120 GlobalVarMultisampledTexElemType,
121 GlobalVarValue,
122 GlobalLetType,
123 GlobalLetArrayElemType,
124 GlobalLetArraySizeValue,
125 GlobalLetVectorElemType,
126 GlobalLetMatrixElemType,
127 GlobalLetValue,
128 AliasType,
129 StructMemberType,
130 CallFunction,
131 ParameterType,
132 LocalVarType,
133 LocalVarArrayElemType,
134 LocalVarArraySizeValue,
135 LocalVarVectorElemType,
136 LocalVarMatrixElemType,
137 LocalVarValue,
138 LocalLetType,
139 LocalLetValue,
140 NestedLocalVarType,
141 NestedLocalVarValue,
142 NestedLocalLetType,
143 NestedLocalLetValue,
144 WorkgroupSizeValue,
145 };
146
147 static constexpr SymbolUseKind kTypeUseKinds[] = {
148 SymbolUseKind::GlobalVarType,
149 SymbolUseKind::GlobalVarArrayElemType,
150 SymbolUseKind::GlobalVarArraySizeValue,
151 SymbolUseKind::GlobalVarVectorElemType,
152 SymbolUseKind::GlobalVarMatrixElemType,
153 SymbolUseKind::GlobalVarSampledTexElemType,
154 SymbolUseKind::GlobalVarMultisampledTexElemType,
155 SymbolUseKind::GlobalLetType,
156 SymbolUseKind::GlobalLetArrayElemType,
157 SymbolUseKind::GlobalLetArraySizeValue,
158 SymbolUseKind::GlobalLetVectorElemType,
159 SymbolUseKind::GlobalLetMatrixElemType,
160 SymbolUseKind::AliasType,
161 SymbolUseKind::StructMemberType,
162 SymbolUseKind::ParameterType,
163 SymbolUseKind::LocalVarType,
164 SymbolUseKind::LocalVarArrayElemType,
165 SymbolUseKind::LocalVarArraySizeValue,
166 SymbolUseKind::LocalVarVectorElemType,
167 SymbolUseKind::LocalVarMatrixElemType,
168 SymbolUseKind::LocalLetType,
169 SymbolUseKind::NestedLocalVarType,
170 SymbolUseKind::NestedLocalLetType,
171 };
172
173 static constexpr SymbolUseKind kValueUseKinds[] = {
174 SymbolUseKind::GlobalVarValue, SymbolUseKind::GlobalLetValue,
175 SymbolUseKind::LocalVarValue, SymbolUseKind::LocalLetValue,
176 SymbolUseKind::NestedLocalVarValue, SymbolUseKind::NestedLocalLetValue,
177 SymbolUseKind::WorkgroupSizeValue,
178 };
179
180 static constexpr SymbolUseKind kFuncUseKinds[] = {
181 SymbolUseKind::CallFunction,
182 };
183
184 /// @returns the description of the symbol declaration kind.
185 /// @note: This differs from the strings used in diagnostic messages.
operator <<(std::ostream & out,SymbolDeclKind kind)186 std::ostream& operator<<(std::ostream& out, SymbolDeclKind kind) {
187 switch (kind) {
188 case SymbolDeclKind::GlobalVar:
189 return out << "global var";
190 case SymbolDeclKind::GlobalLet:
191 return out << "global let";
192 case SymbolDeclKind::Alias:
193 return out << "alias";
194 case SymbolDeclKind::Struct:
195 return out << "struct";
196 case SymbolDeclKind::Function:
197 return out << "function";
198 case SymbolDeclKind::Parameter:
199 return out << "parameter";
200 case SymbolDeclKind::LocalVar:
201 return out << "local var";
202 case SymbolDeclKind::LocalLet:
203 return out << "local let";
204 case SymbolDeclKind::NestedLocalVar:
205 return out << "nested local var";
206 case SymbolDeclKind::NestedLocalLet:
207 return out << "nested local let";
208 }
209 return out << "<unknown>";
210 }
211
212 /// @returns the description of the symbol use kind.
213 /// @note: This differs from the strings used in diagnostic messages.
operator <<(std::ostream & out,SymbolUseKind kind)214 std::ostream& operator<<(std::ostream& out, SymbolUseKind kind) {
215 switch (kind) {
216 case SymbolUseKind::GlobalVarType:
217 return out << "global var type";
218 case SymbolUseKind::GlobalVarValue:
219 return out << "global var value";
220 case SymbolUseKind::GlobalVarArrayElemType:
221 return out << "global var array element type";
222 case SymbolUseKind::GlobalVarArraySizeValue:
223 return out << "global var array size value";
224 case SymbolUseKind::GlobalVarVectorElemType:
225 return out << "global var vector element type";
226 case SymbolUseKind::GlobalVarMatrixElemType:
227 return out << "global var matrix element type";
228 case SymbolUseKind::GlobalVarSampledTexElemType:
229 return out << "global var sampled_texture element type";
230 case SymbolUseKind::GlobalVarMultisampledTexElemType:
231 return out << "global var multisampled_texture element type";
232 case SymbolUseKind::GlobalLetType:
233 return out << "global let type";
234 case SymbolUseKind::GlobalLetValue:
235 return out << "global let value";
236 case SymbolUseKind::GlobalLetArrayElemType:
237 return out << "global let array element type";
238 case SymbolUseKind::GlobalLetArraySizeValue:
239 return out << "global let array size value";
240 case SymbolUseKind::GlobalLetVectorElemType:
241 return out << "global let vector element type";
242 case SymbolUseKind::GlobalLetMatrixElemType:
243 return out << "global let matrix element type";
244 case SymbolUseKind::AliasType:
245 return out << "alias type";
246 case SymbolUseKind::StructMemberType:
247 return out << "struct member type";
248 case SymbolUseKind::CallFunction:
249 return out << "call function";
250 case SymbolUseKind::ParameterType:
251 return out << "parameter type";
252 case SymbolUseKind::LocalVarType:
253 return out << "local var type";
254 case SymbolUseKind::LocalVarArrayElemType:
255 return out << "local var array element type";
256 case SymbolUseKind::LocalVarArraySizeValue:
257 return out << "local var array size value";
258 case SymbolUseKind::LocalVarVectorElemType:
259 return out << "local var vector element type";
260 case SymbolUseKind::LocalVarMatrixElemType:
261 return out << "local var matrix element type";
262 case SymbolUseKind::LocalVarValue:
263 return out << "local var value";
264 case SymbolUseKind::LocalLetType:
265 return out << "local let type";
266 case SymbolUseKind::LocalLetValue:
267 return out << "local let value";
268 case SymbolUseKind::NestedLocalVarType:
269 return out << "nested local var type";
270 case SymbolUseKind::NestedLocalVarValue:
271 return out << "nested local var value";
272 case SymbolUseKind::NestedLocalLetType:
273 return out << "nested local let type";
274 case SymbolUseKind::NestedLocalLetValue:
275 return out << "nested local let value";
276 case SymbolUseKind::WorkgroupSizeValue:
277 return out << "workgroup size value";
278 }
279 return out << "<unknown>";
280 }
281
282 /// @returns the the diagnostic message name used for the given use
DiagString(SymbolUseKind kind)283 std::string DiagString(SymbolUseKind kind) {
284 switch (kind) {
285 case SymbolUseKind::GlobalVarType:
286 case SymbolUseKind::GlobalVarArrayElemType:
287 case SymbolUseKind::GlobalVarVectorElemType:
288 case SymbolUseKind::GlobalVarMatrixElemType:
289 case SymbolUseKind::GlobalVarSampledTexElemType:
290 case SymbolUseKind::GlobalVarMultisampledTexElemType:
291 case SymbolUseKind::GlobalLetType:
292 case SymbolUseKind::GlobalLetArrayElemType:
293 case SymbolUseKind::GlobalLetVectorElemType:
294 case SymbolUseKind::GlobalLetMatrixElemType:
295 case SymbolUseKind::AliasType:
296 case SymbolUseKind::StructMemberType:
297 case SymbolUseKind::ParameterType:
298 case SymbolUseKind::LocalVarType:
299 case SymbolUseKind::LocalVarArrayElemType:
300 case SymbolUseKind::LocalVarVectorElemType:
301 case SymbolUseKind::LocalVarMatrixElemType:
302 case SymbolUseKind::LocalLetType:
303 case SymbolUseKind::NestedLocalVarType:
304 case SymbolUseKind::NestedLocalLetType:
305 return "type";
306 case SymbolUseKind::GlobalVarValue:
307 case SymbolUseKind::GlobalVarArraySizeValue:
308 case SymbolUseKind::GlobalLetValue:
309 case SymbolUseKind::GlobalLetArraySizeValue:
310 case SymbolUseKind::LocalVarValue:
311 case SymbolUseKind::LocalVarArraySizeValue:
312 case SymbolUseKind::LocalLetValue:
313 case SymbolUseKind::NestedLocalVarValue:
314 case SymbolUseKind::NestedLocalLetValue:
315 case SymbolUseKind::WorkgroupSizeValue:
316 return "identifier";
317 case SymbolUseKind::CallFunction:
318 return "function";
319 }
320 return "<unknown>";
321 }
322
323 /// @returns the declaration scope depth for the symbol declaration kind.
324 /// Globals are at depth 0, parameters and locals are at depth 1,
325 /// nested locals are at depth 2.
ScopeDepth(SymbolDeclKind kind)326 int ScopeDepth(SymbolDeclKind kind) {
327 switch (kind) {
328 case SymbolDeclKind::GlobalVar:
329 case SymbolDeclKind::GlobalLet:
330 case SymbolDeclKind::Alias:
331 case SymbolDeclKind::Struct:
332 case SymbolDeclKind::Function:
333 return 0;
334 case SymbolDeclKind::Parameter:
335 case SymbolDeclKind::LocalVar:
336 case SymbolDeclKind::LocalLet:
337 return 1;
338 case SymbolDeclKind::NestedLocalVar:
339 case SymbolDeclKind::NestedLocalLet:
340 return 2;
341 }
342 return -1;
343 }
344
345 /// @returns the use depth for the symbol use kind.
346 /// Globals are at depth 0, parameters and locals are at depth 1,
347 /// nested locals are at depth 2.
ScopeDepth(SymbolUseKind kind)348 int ScopeDepth(SymbolUseKind kind) {
349 switch (kind) {
350 case SymbolUseKind::GlobalVarType:
351 case SymbolUseKind::GlobalVarValue:
352 case SymbolUseKind::GlobalVarArrayElemType:
353 case SymbolUseKind::GlobalVarArraySizeValue:
354 case SymbolUseKind::GlobalVarVectorElemType:
355 case SymbolUseKind::GlobalVarMatrixElemType:
356 case SymbolUseKind::GlobalVarSampledTexElemType:
357 case SymbolUseKind::GlobalVarMultisampledTexElemType:
358 case SymbolUseKind::GlobalLetType:
359 case SymbolUseKind::GlobalLetValue:
360 case SymbolUseKind::GlobalLetArrayElemType:
361 case SymbolUseKind::GlobalLetArraySizeValue:
362 case SymbolUseKind::GlobalLetVectorElemType:
363 case SymbolUseKind::GlobalLetMatrixElemType:
364 case SymbolUseKind::AliasType:
365 case SymbolUseKind::StructMemberType:
366 case SymbolUseKind::WorkgroupSizeValue:
367 return 0;
368 case SymbolUseKind::CallFunction:
369 case SymbolUseKind::ParameterType:
370 case SymbolUseKind::LocalVarType:
371 case SymbolUseKind::LocalVarArrayElemType:
372 case SymbolUseKind::LocalVarArraySizeValue:
373 case SymbolUseKind::LocalVarVectorElemType:
374 case SymbolUseKind::LocalVarMatrixElemType:
375 case SymbolUseKind::LocalVarValue:
376 case SymbolUseKind::LocalLetType:
377 case SymbolUseKind::LocalLetValue:
378 return 1;
379 case SymbolUseKind::NestedLocalVarType:
380 case SymbolUseKind::NestedLocalVarValue:
381 case SymbolUseKind::NestedLocalLetType:
382 case SymbolUseKind::NestedLocalLetValue:
383 return 2;
384 }
385 return -1;
386 }
387
388 /// A helper for building programs that exercise symbol declaration tests.
389 struct SymbolTestHelper {
390 /// The program builder
391 ProgramBuilder* const builder;
392 /// Parameters to a function that may need to be built
393 std::vector<const ast::Variable*> parameters;
394 /// Shallow function var / let declaration statements
395 std::vector<const ast::Statement*> statements;
396 /// Nested function local var / let declaration statements
397 std::vector<const ast::Statement*> nested_statements;
398 /// Function decorations
399 ast::DecorationList func_decos;
400
401 /// Constructor
402 /// @param builder the program builder
403 explicit SymbolTestHelper(ProgramBuilder* builder);
404
405 /// Destructor.
406 ~SymbolTestHelper();
407
408 /// Declares a symbol with the given kind
409 /// @param kind the kind of symbol declaration
410 /// @param symbol the symbol to use for the declaration
411 /// @param source the source of the declaration
412 /// @returns the declaration node
413 const ast::Node* Add(SymbolDeclKind kind, Symbol symbol, Source source);
414
415 /// Declares a use of a symbol with the given kind
416 /// @param kind the kind of symbol use
417 /// @param symbol the declaration symbol to use
418 /// @param source the source of the use
419 /// @returns the use node
420 const ast::Node* Add(SymbolUseKind kind, Symbol symbol, Source source);
421
422 /// Builds a function, if any parameter or local declarations have been added
423 void Build();
424 };
425
SymbolTestHelper(ProgramBuilder * b)426 SymbolTestHelper::SymbolTestHelper(ProgramBuilder* b) : builder(b) {}
427
~SymbolTestHelper()428 SymbolTestHelper::~SymbolTestHelper() {}
429
Add(SymbolDeclKind kind,Symbol symbol,Source source)430 const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind,
431 Symbol symbol,
432 Source source) {
433 auto& b = *builder;
434 switch (kind) {
435 case SymbolDeclKind::GlobalVar:
436 return b.Global(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
437 case SymbolDeclKind::GlobalLet:
438 return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1));
439 case SymbolDeclKind::Alias:
440 return b.Alias(source, symbol, b.ty.i32());
441 case SymbolDeclKind::Struct:
442 return b.Structure(source, symbol, {b.Member("m", b.ty.i32())});
443 case SymbolDeclKind::Function:
444 return b.Func(source, symbol, {}, b.ty.void_(), {});
445 case SymbolDeclKind::Parameter: {
446 auto* node = b.Param(source, symbol, b.ty.i32());
447 parameters.emplace_back(node);
448 return node;
449 }
450 case SymbolDeclKind::LocalVar: {
451 auto* node = b.Var(source, symbol, b.ty.i32());
452 statements.emplace_back(b.Decl(node));
453 return node;
454 }
455 case SymbolDeclKind::LocalLet: {
456 auto* node = b.Const(source, symbol, b.ty.i32(), b.Expr(1));
457 statements.emplace_back(b.Decl(node));
458 return node;
459 }
460 case SymbolDeclKind::NestedLocalVar: {
461 auto* node = b.Var(source, symbol, b.ty.i32());
462 nested_statements.emplace_back(b.Decl(node));
463 return node;
464 }
465 case SymbolDeclKind::NestedLocalLet: {
466 auto* node = b.Const(source, symbol, b.ty.i32(), b.Expr(1));
467 nested_statements.emplace_back(b.Decl(node));
468 return node;
469 }
470 }
471 return nullptr;
472 }
473
Add(SymbolUseKind kind,Symbol symbol,Source source)474 const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind,
475 Symbol symbol,
476 Source source) {
477 auto& b = *builder;
478 switch (kind) {
479 case SymbolUseKind::GlobalVarType: {
480 auto* node = b.ty.type_name(source, symbol);
481 b.Global(b.Sym(), node, ast::StorageClass::kPrivate);
482 return node;
483 }
484 case SymbolUseKind::GlobalVarArrayElemType: {
485 auto* node = b.ty.type_name(source, symbol);
486 b.Global(b.Sym(), b.ty.array(node, 4), ast::StorageClass::kPrivate);
487 return node;
488 }
489 case SymbolUseKind::GlobalVarArraySizeValue: {
490 auto* node = b.Expr(source, symbol);
491 b.Global(b.Sym(), b.ty.array(b.ty.i32(), node),
492 ast::StorageClass::kPrivate);
493 return node;
494 }
495 case SymbolUseKind::GlobalVarVectorElemType: {
496 auto* node = b.ty.type_name(source, symbol);
497 b.Global(b.Sym(), b.ty.vec3(node), ast::StorageClass::kPrivate);
498 return node;
499 }
500 case SymbolUseKind::GlobalVarMatrixElemType: {
501 auto* node = b.ty.type_name(source, symbol);
502 b.Global(b.Sym(), b.ty.mat3x4(node), ast::StorageClass::kPrivate);
503 return node;
504 }
505 case SymbolUseKind::GlobalVarSampledTexElemType: {
506 auto* node = b.ty.type_name(source, symbol);
507 b.Global(b.Sym(), b.ty.sampled_texture(ast::TextureDimension::k2d, node));
508 return node;
509 }
510 case SymbolUseKind::GlobalVarMultisampledTexElemType: {
511 auto* node = b.ty.type_name(source, symbol);
512 b.Global(b.Sym(),
513 b.ty.multisampled_texture(ast::TextureDimension::k2d, node));
514 return node;
515 }
516 case SymbolUseKind::GlobalVarValue: {
517 auto* node = b.Expr(source, symbol);
518 b.Global(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
519 return node;
520 }
521 case SymbolUseKind::GlobalLetType: {
522 auto* node = b.ty.type_name(source, symbol);
523 b.GlobalConst(b.Sym(), node, b.Expr(1));
524 return node;
525 }
526 case SymbolUseKind::GlobalLetArrayElemType: {
527 auto* node = b.ty.type_name(source, symbol);
528 b.GlobalConst(b.Sym(), b.ty.array(node, 4), b.Expr(1));
529 return node;
530 }
531 case SymbolUseKind::GlobalLetArraySizeValue: {
532 auto* node = b.Expr(source, symbol);
533 b.GlobalConst(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1));
534 return node;
535 }
536 case SymbolUseKind::GlobalLetVectorElemType: {
537 auto* node = b.ty.type_name(source, symbol);
538 b.GlobalConst(b.Sym(), b.ty.vec3(node), b.Expr(1));
539 return node;
540 }
541 case SymbolUseKind::GlobalLetMatrixElemType: {
542 auto* node = b.ty.type_name(source, symbol);
543 b.GlobalConst(b.Sym(), b.ty.mat3x4(node), b.Expr(1));
544 return node;
545 }
546 case SymbolUseKind::GlobalLetValue: {
547 auto* node = b.Expr(source, symbol);
548 b.GlobalConst(b.Sym(), b.ty.i32(), node);
549 return node;
550 }
551 case SymbolUseKind::AliasType: {
552 auto* node = b.ty.type_name(source, symbol);
553 b.Alias(b.Sym(), node);
554 return node;
555 }
556 case SymbolUseKind::StructMemberType: {
557 auto* node = b.ty.type_name(source, symbol);
558 b.Structure(b.Sym(), {b.Member("m", node)});
559 return node;
560 }
561 case SymbolUseKind::CallFunction: {
562 auto* node = b.Expr(source, symbol);
563 statements.emplace_back(b.CallStmt(b.Call(node)));
564 return node;
565 }
566 case SymbolUseKind::ParameterType: {
567 auto* node = b.ty.type_name(source, symbol);
568 parameters.emplace_back(b.Param(b.Sym(), node));
569 return node;
570 }
571 case SymbolUseKind::LocalVarType: {
572 auto* node = b.ty.type_name(source, symbol);
573 statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
574 return node;
575 }
576 case SymbolUseKind::LocalVarArrayElemType: {
577 auto* node = b.ty.type_name(source, symbol);
578 statements.emplace_back(
579 b.Decl(b.Var(b.Sym(), b.ty.array(node, 4), b.Expr(1))));
580 return node;
581 }
582 case SymbolUseKind::LocalVarArraySizeValue: {
583 auto* node = b.Expr(source, symbol);
584 statements.emplace_back(
585 b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1))));
586 return node;
587 }
588 case SymbolUseKind::LocalVarVectorElemType: {
589 auto* node = b.ty.type_name(source, symbol);
590 statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
591 return node;
592 }
593 case SymbolUseKind::LocalVarMatrixElemType: {
594 auto* node = b.ty.type_name(source, symbol);
595 statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
596 return node;
597 }
598 case SymbolUseKind::LocalVarValue: {
599 auto* node = b.Expr(source, symbol);
600 statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
601 return node;
602 }
603 case SymbolUseKind::LocalLetType: {
604 auto* node = b.ty.type_name(source, symbol);
605 statements.emplace_back(b.Decl(b.Const(b.Sym(), node, b.Expr(1))));
606 return node;
607 }
608 case SymbolUseKind::LocalLetValue: {
609 auto* node = b.Expr(source, symbol);
610 statements.emplace_back(b.Decl(b.Const(b.Sym(), b.ty.i32(), node)));
611 return node;
612 }
613 case SymbolUseKind::NestedLocalVarType: {
614 auto* node = b.ty.type_name(source, symbol);
615 nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
616 return node;
617 }
618 case SymbolUseKind::NestedLocalVarValue: {
619 auto* node = b.Expr(source, symbol);
620 nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
621 return node;
622 }
623 case SymbolUseKind::NestedLocalLetType: {
624 auto* node = b.ty.type_name(source, symbol);
625 nested_statements.emplace_back(b.Decl(b.Const(b.Sym(), node, b.Expr(1))));
626 return node;
627 }
628 case SymbolUseKind::NestedLocalLetValue: {
629 auto* node = b.Expr(source, symbol);
630 nested_statements.emplace_back(
631 b.Decl(b.Const(b.Sym(), b.ty.i32(), node)));
632 return node;
633 }
634 case SymbolUseKind::WorkgroupSizeValue: {
635 auto* node = b.Expr(source, symbol);
636 func_decos.emplace_back(b.WorkgroupSize(1, node, 2));
637 return node;
638 }
639 }
640 return nullptr;
641 }
642
Build()643 void SymbolTestHelper::Build() {
644 auto& b = *builder;
645 if (!nested_statements.empty()) {
646 statements.emplace_back(b.Block(nested_statements));
647 nested_statements.clear();
648 }
649 if (!parameters.empty() || !statements.empty() || !func_decos.empty()) {
650 b.Func("func", parameters, b.ty.void_(), statements, func_decos);
651 parameters.clear();
652 statements.clear();
653 func_decos.clear();
654 }
655 }
656
657 ////////////////////////////////////////////////////////////////////////////////
658 // Used-before-declarated tests
659 ////////////////////////////////////////////////////////////////////////////////
660 namespace used_before_decl_tests {
661
662 class ResolverDependencyGraphUsedBeforeDeclTest
663 : public ResolverDependencyGraphTest {
664 public:
ResolverDependencyGraphUsedBeforeDeclTest()665 ResolverDependencyGraphUsedBeforeDeclTest() {
666 allow_out_of_order_decls = false;
667 }
668 };
669
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,FuncCall)670 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, FuncCall) {
671 // fn A() { B(); }
672 // fn B() {}
673
674 Func("A", {}, ty.void_(), {CallStmt(Call(Expr(Source{{12, 34}}, "B")))});
675 Func(Source{{56, 78}}, "B", {}, ty.void_(), {Return()});
676
677 Build(R"(12:34 error: function 'B' used before it has been declared
678 56:78 note: function 'B' declared here)");
679 }
680
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,TypeConstructed)681 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeConstructed) {
682 // fn F() {
683 // { _ = T(); }
684 // }
685 // type T = i32;
686
687 Func("F", {}, ty.void_(),
688 {Block(Ignore(Construct(ty.type_name(Source{{12, 34}}, "T"))))});
689 Alias(Source{{56, 78}}, "T", ty.i32());
690
691 Build(R"(12:34 error: alias 'T' used before it has been declared
692 56:78 note: alias 'T' declared here)");
693 }
694
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,TypeUsedByLocal)695 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByLocal) {
696 // fn F() {
697 // { var v : T; }
698 // }
699 // type T = i32;
700
701 Func("F", {}, ty.void_(),
702 {Block(Decl(Var("v", ty.type_name(Source{{12, 34}}, "T"))))});
703 Alias(Source{{56, 78}}, "T", ty.i32());
704
705 Build(R"(12:34 error: alias 'T' used before it has been declared
706 56:78 note: alias 'T' declared here)");
707 }
708
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,TypeUsedByParam)709 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByParam) {
710 // fn F(p : T) {}
711 // type T = i32;
712
713 Func("F", {Param("p", ty.type_name(Source{{12, 34}}, "T"))}, ty.void_(), {});
714 Alias(Source{{56, 78}}, "T", ty.i32());
715
716 Build(R"(12:34 error: alias 'T' used before it has been declared
717 56:78 note: alias 'T' declared here)");
718 }
719
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,TypeUsedAsReturnType)720 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedAsReturnType) {
721 // fn F() -> T {}
722 // type T = i32;
723
724 Func("F", {}, ty.type_name(Source{{12, 34}}, "T"), {});
725 Alias(Source{{56, 78}}, "T", ty.i32());
726
727 Build(R"(12:34 error: alias 'T' used before it has been declared
728 56:78 note: alias 'T' declared here)");
729 }
730
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,TypeByStructMember)731 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeByStructMember) {
732 // struct S { m : T };
733 // type T = i32;
734
735 Structure("S", {Member("m", ty.type_name(Source{{12, 34}}, "T"))});
736 Alias(Source{{56, 78}}, "T", ty.i32());
737
738 Build(R"(12:34 error: alias 'T' used before it has been declared
739 56:78 note: alias 'T' declared here)");
740 }
741
TEST_F(ResolverDependencyGraphUsedBeforeDeclTest,VarUsed)742 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, VarUsed) {
743 // fn F() {
744 // { G = 3.14f; }
745 // }
746 // var G: f32 = 2.1;
747
748 Func("F", ast::VariableList{}, ty.void_(),
749 {Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14f))});
750
751 Global(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate,
752 Expr(2.1f));
753
754 EXPECT_FALSE(r()->Resolve());
755 EXPECT_EQ(r()->error(),
756 R"(12:34 error: var 'G' used before it has been declared
757 56:78 note: var 'G' declared here)");
758 }
759
760 } // namespace used_before_decl_tests
761
762 ////////////////////////////////////////////////////////////////////////////////
763 // Undeclared symbol tests
764 ////////////////////////////////////////////////////////////////////////////////
765 namespace undeclared_tests {
766
767 using ResolverDependencyGraphUndeclaredSymbolTest =
768 ResolverDependencyGraphTestWithParam<SymbolUseKind>;
769
TEST_P(ResolverDependencyGraphUndeclaredSymbolTest,Test)770 TEST_P(ResolverDependencyGraphUndeclaredSymbolTest, Test) {
771 const Symbol symbol = Sym("SYMBOL");
772 const auto use_kind = GetParam();
773
774 // Build a use of a non-existent symbol
775 SymbolTestHelper helper(this);
776 helper.Add(use_kind, symbol, Source{{56, 78}});
777 helper.Build();
778
779 Build("56:78 error: unknown " + DiagString(use_kind) + ": 'SYMBOL'");
780 }
781
782 INSTANTIATE_TEST_SUITE_P(Types,
783 ResolverDependencyGraphUndeclaredSymbolTest,
784 testing::ValuesIn(kTypeUseKinds));
785
786 INSTANTIATE_TEST_SUITE_P(Values,
787 ResolverDependencyGraphUndeclaredSymbolTest,
788 testing::ValuesIn(kValueUseKinds));
789
790 INSTANTIATE_TEST_SUITE_P(Functions,
791 ResolverDependencyGraphUndeclaredSymbolTest,
792 testing::ValuesIn(kFuncUseKinds));
793
794 } // namespace undeclared_tests
795
796 ////////////////////////////////////////////////////////////////////////////////
797 // Self reference by decl
798 ////////////////////////////////////////////////////////////////////////////////
799 namespace undeclared_tests {
800
801 using ResolverDependencyGraphDeclSelfUse = ResolverDependencyGraphTest;
802
TEST_F(ResolverDependencyGraphDeclSelfUse,GlobalVar)803 TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalVar) {
804 const Symbol symbol = Sym("SYMBOL");
805 Global(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123));
806 Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
807 12:34 note: var 'SYMBOL' references var 'SYMBOL' here)");
808 }
809
TEST_F(ResolverDependencyGraphDeclSelfUse,GlobalLet)810 TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalLet) {
811 const Symbol symbol = Sym("SYMBOL");
812 GlobalConst(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123));
813 Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
814 12:34 note: let 'SYMBOL' references let 'SYMBOL' here)");
815 }
816
TEST_F(ResolverDependencyGraphDeclSelfUse,LocalVar)817 TEST_F(ResolverDependencyGraphDeclSelfUse, LocalVar) {
818 const Symbol symbol = Sym("SYMBOL");
819 WrapInFunction(
820 Decl(Var(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123))));
821 Build("12:34 error: unknown identifier: 'SYMBOL'");
822 }
823
TEST_F(ResolverDependencyGraphDeclSelfUse,LocalLet)824 TEST_F(ResolverDependencyGraphDeclSelfUse, LocalLet) {
825 const Symbol symbol = Sym("SYMBOL");
826 WrapInFunction(
827 Decl(Const(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123))));
828 Build("12:34 error: unknown identifier: 'SYMBOL'");
829 }
830
831 } // namespace undeclared_tests
832
833 ////////////////////////////////////////////////////////////////////////////////
834 // Recursive dependency tests
835 ////////////////////////////////////////////////////////////////////////////////
836 namespace recursive_tests {
837
838 using ResolverDependencyGraphCyclicRefTest = ResolverDependencyGraphTest;
839
TEST_F(ResolverDependencyGraphCyclicRefTest,DirectCall)840 TEST_F(ResolverDependencyGraphCyclicRefTest, DirectCall) {
841 // fn main() { main(); }
842
843 Func(Source{{12, 34}}, "main", {}, ty.void_(),
844 {CallStmt(Call(Expr(Source{{56, 78}}, "main")))});
845
846 Build(R"(12:34 error: cyclic dependency found: 'main' -> 'main'
847 56:78 note: function 'main' calls function 'main' here)");
848 }
849
TEST_F(ResolverDependencyGraphCyclicRefTest,IndirectCall)850 TEST_F(ResolverDependencyGraphCyclicRefTest, IndirectCall) {
851 // 1: fn a() { b(); }
852 // 2: fn e() { }
853 // 3: fn d() { e(); b(); }
854 // 4: fn c() { d(); }
855 // 5: fn b() { c(); }
856
857 Func(Source{{1, 1}}, "a", {}, ty.void_(),
858 {CallStmt(Call(Expr(Source{{1, 10}}, "b")))});
859 Func(Source{{2, 1}}, "e", {}, ty.void_(), {});
860 Func(Source{{3, 1}}, "d", {}, ty.void_(),
861 {
862 CallStmt(Call(Expr(Source{{3, 10}}, "e"))),
863 CallStmt(Call(Expr(Source{{3, 10}}, "b"))),
864 });
865 Func(Source{{4, 1}}, "c", {}, ty.void_(),
866 {CallStmt(Call(Expr(Source{{4, 10}}, "d")))});
867 Func(Source{{5, 1}}, "b", {}, ty.void_(),
868 {CallStmt(Call(Expr(Source{{5, 10}}, "c")))});
869
870 Build(R"(5:1 error: cyclic dependency found: 'b' -> 'c' -> 'd' -> 'b'
871 5:10 note: function 'b' calls function 'c' here
872 4:10 note: function 'c' calls function 'd' here
873 3:10 note: function 'd' calls function 'b' here)");
874 }
875
TEST_F(ResolverDependencyGraphCyclicRefTest,Alias_Direct)876 TEST_F(ResolverDependencyGraphCyclicRefTest, Alias_Direct) {
877 // type T = T;
878
879 Alias(Source{{12, 34}}, "T", ty.type_name(Source{{56, 78}}, "T"));
880
881 EXPECT_FALSE(r()->Resolve());
882 EXPECT_EQ(r()->error(),
883 R"(12:34 error: cyclic dependency found: 'T' -> 'T'
884 56:78 note: alias 'T' references alias 'T' here)");
885 }
886
TEST_F(ResolverDependencyGraphCyclicRefTest,Alias_Indirect)887 TEST_F(ResolverDependencyGraphCyclicRefTest, Alias_Indirect) {
888 // 1: type Y = Z;
889 // 2: type X = Y;
890 // 3: type Z = X;
891
892 Alias(Source{{1, 1}}, "Y", ty.type_name(Source{{1, 10}}, "Z"));
893 Alias(Source{{2, 1}}, "X", ty.type_name(Source{{2, 10}}, "Y"));
894 Alias(Source{{3, 1}}, "Z", ty.type_name(Source{{3, 10}}, "X"));
895
896 EXPECT_FALSE(r()->Resolve());
897 EXPECT_EQ(r()->error(),
898 R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
899 1:10 note: alias 'Y' references alias 'Z' here
900 3:10 note: alias 'Z' references alias 'X' here
901 2:10 note: alias 'X' references alias 'Y' here)");
902 }
903
TEST_F(ResolverDependencyGraphCyclicRefTest,Struct_Direct)904 TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Direct) {
905 // struct S {
906 // a: S;
907 // };
908
909 Structure(Source{{12, 34}}, "S",
910 {Member("a", ty.type_name(Source{{56, 78}}, "S"))});
911
912 EXPECT_FALSE(r()->Resolve());
913 EXPECT_EQ(r()->error(),
914 R"(12:34 error: cyclic dependency found: 'S' -> 'S'
915 56:78 note: struct 'S' references struct 'S' here)");
916 }
917
TEST_F(ResolverDependencyGraphCyclicRefTest,Struct_Indirect)918 TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Indirect) {
919 // 1: struct Y { z: Z; };
920 // 2: struct X { y: Y; };
921 // 3: struct Z { x: X; };
922
923 Structure(Source{{1, 1}}, "Y",
924 {Member("z", ty.type_name(Source{{1, 10}}, "Z"))});
925 Structure(Source{{2, 1}}, "X",
926 {Member("y", ty.type_name(Source{{2, 10}}, "Y"))});
927 Structure(Source{{3, 1}}, "Z",
928 {Member("x", ty.type_name(Source{{3, 10}}, "X"))});
929
930 EXPECT_FALSE(r()->Resolve());
931 EXPECT_EQ(r()->error(),
932 R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
933 1:10 note: struct 'Y' references struct 'Z' here
934 3:10 note: struct 'Z' references struct 'X' here
935 2:10 note: struct 'X' references struct 'Y' here)");
936 }
937
TEST_F(ResolverDependencyGraphCyclicRefTest,GlobalVar_Direct)938 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Direct) {
939 // var<private> V : i32 = V;
940
941 Global(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
942
943 EXPECT_FALSE(r()->Resolve());
944 EXPECT_EQ(r()->error(),
945 R"(12:34 error: cyclic dependency found: 'V' -> 'V'
946 56:78 note: var 'V' references var 'V' here)");
947 }
948
TEST_F(ResolverDependencyGraphCyclicRefTest,GlobalLet_Direct)949 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Direct) {
950 // let V : i32 = V;
951
952 GlobalConst(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
953
954 EXPECT_FALSE(r()->Resolve());
955 EXPECT_EQ(r()->error(),
956 R"(12:34 error: cyclic dependency found: 'V' -> 'V'
957 56:78 note: let 'V' references let 'V' here)");
958 }
959
TEST_F(ResolverDependencyGraphCyclicRefTest,GlobalVar_Indirect)960 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Indirect) {
961 // 1: var<private> Y : i32 = Z;
962 // 2: var<private> X : i32 = Y;
963 // 3: var<private> Z : i32 = X;
964
965 Global(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
966 Global(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
967 Global(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
968
969 EXPECT_FALSE(r()->Resolve());
970 EXPECT_EQ(r()->error(),
971 R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
972 1:10 note: var 'Y' references var 'Z' here
973 3:10 note: var 'Z' references var 'X' here
974 2:10 note: var 'X' references var 'Y' here)");
975 }
976
TEST_F(ResolverDependencyGraphCyclicRefTest,GlobalLet_Indirect)977 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Indirect) {
978 // 1: let Y : i32 = Z;
979 // 2: let X : i32 = Y;
980 // 3: let Z : i32 = X;
981
982 GlobalConst(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
983 GlobalConst(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
984 GlobalConst(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
985
986 EXPECT_FALSE(r()->Resolve());
987 EXPECT_EQ(r()->error(),
988 R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
989 1:10 note: let 'Y' references let 'Z' here
990 3:10 note: let 'Z' references let 'X' here
991 2:10 note: let 'X' references let 'Y' here)");
992 }
993
TEST_F(ResolverDependencyGraphCyclicRefTest,Mixed_RecursiveDependencies)994 TEST_F(ResolverDependencyGraphCyclicRefTest, Mixed_RecursiveDependencies) {
995 // 1: fn F() -> R { return Z; }
996 // 2: type A = S;
997 // 3: struct S { a : A };
998 // 4: var Z = L;
999 // 5: type R = A;
1000 // 6: let L : S = Z;
1001
1002 Func(Source{{1, 1}}, "F", {}, ty.type_name(Source{{1, 5}}, "R"),
1003 {Return(Expr(Source{{1, 10}}, "Z"))});
1004 Alias(Source{{2, 1}}, "A", ty.type_name(Source{{2, 10}}, "S"));
1005 Structure(Source{{3, 1}}, "S",
1006 {Member("a", ty.type_name(Source{{3, 10}}, "A"))});
1007 Global(Source{{4, 1}}, "Z", nullptr, Expr(Source{{4, 10}}, "L"));
1008 Alias(Source{{5, 1}}, "R", ty.type_name(Source{{5, 10}}, "A"));
1009 GlobalConst(Source{{6, 1}}, "L", ty.type_name(Source{{5, 5}}, "S"),
1010 Expr(Source{{5, 10}}, "Z"));
1011
1012 EXPECT_FALSE(r()->Resolve());
1013 EXPECT_EQ(r()->error(),
1014 R"(3:1 error: cyclic dependency found: 'S' -> 'A' -> 'S'
1015 3:10 note: struct 'S' references alias 'A' here
1016 2:10 note: alias 'A' references struct 'S' here
1017 4:1 error: cyclic dependency found: 'Z' -> 'L' -> 'Z'
1018 4:10 note: var 'Z' references let 'L' here
1019 5:10 note: let 'L' references var 'Z' here)");
1020 }
1021
1022 } // namespace recursive_tests
1023
1024 ////////////////////////////////////////////////////////////////////////////////
1025 // Symbol Redeclaration tests
1026 ////////////////////////////////////////////////////////////////////////////////
1027 namespace redeclaration_tests {
1028
1029 using ResolverDependencyGraphRedeclarationTest =
1030 ResolverDependencyGraphTestWithParam<
1031 std::tuple<SymbolDeclKind, SymbolDeclKind>>;
1032
TEST_P(ResolverDependencyGraphRedeclarationTest,Test)1033 TEST_P(ResolverDependencyGraphRedeclarationTest, Test) {
1034 const auto symbol = Sym("SYMBOL");
1035
1036 auto a_kind = std::get<0>(GetParam());
1037 auto b_kind = std::get<1>(GetParam());
1038
1039 auto a_source = Source{{12, 34}};
1040 auto b_source = Source{{56, 78}};
1041
1042 if (a_kind != SymbolDeclKind::Parameter &&
1043 b_kind == SymbolDeclKind::Parameter) {
1044 std::swap(a_source, b_source); // Parameters are declared before locals
1045 }
1046
1047 SymbolTestHelper helper(this);
1048 helper.Add(a_kind, symbol, a_source);
1049 helper.Add(b_kind, symbol, b_source);
1050 helper.Build();
1051
1052 bool error = ScopeDepth(a_kind) == ScopeDepth(b_kind);
1053
1054 Build(error ? R"(56:78 error: redeclaration of 'SYMBOL'
1055 12:34 note: 'SYMBOL' previously declared here)"
1056 : "");
1057 }
1058
1059 INSTANTIATE_TEST_SUITE_P(
1060 ResolverTest,
1061 ResolverDependencyGraphRedeclarationTest,
1062 testing::Combine(testing::ValuesIn(kAllSymbolDeclKinds),
1063 testing::ValuesIn(kAllSymbolDeclKinds)));
1064
1065 } // namespace redeclaration_tests
1066
1067 ////////////////////////////////////////////////////////////////////////////////
1068 // Ordered global tests
1069 ////////////////////////////////////////////////////////////////////////////////
1070 namespace ordered_globals {
1071
1072 using ResolverDependencyGraphOrderedGlobalsTest =
1073 ResolverDependencyGraphTestWithParam<
1074 std::tuple<SymbolDeclKind, SymbolUseKind>>;
1075
TEST_P(ResolverDependencyGraphOrderedGlobalsTest,InOrder)1076 TEST_P(ResolverDependencyGraphOrderedGlobalsTest, InOrder) {
1077 const Symbol symbol = Sym("SYMBOL");
1078 const auto decl_kind = std::get<0>(GetParam());
1079 const auto use_kind = std::get<1>(GetParam());
1080
1081 // Declaration before use
1082 SymbolTestHelper helper(this);
1083 helper.Add(decl_kind, symbol, Source{{12, 34}});
1084 helper.Add(use_kind, symbol, Source{{56, 78}});
1085 helper.Build();
1086
1087 ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
1088
1089 auto* decl = AST().GlobalDeclarations()[0];
1090 auto* use = AST().GlobalDeclarations()[1];
1091 EXPECT_THAT(Build().ordered_globals, ElementsAre(decl, use));
1092 }
1093
TEST_P(ResolverDependencyGraphOrderedGlobalsTest,OutOfOrder)1094 TEST_P(ResolverDependencyGraphOrderedGlobalsTest, OutOfOrder) {
1095 const Symbol symbol = Sym("SYMBOL");
1096 const auto decl_kind = std::get<0>(GetParam());
1097 const auto use_kind = std::get<1>(GetParam());
1098
1099 // Use before declaration
1100 SymbolTestHelper helper(this);
1101 helper.Add(use_kind, symbol, Source{{56, 78}});
1102 helper.Build(); // If the use is in a function, then ensure this function is
1103 // built before the symbol declaration
1104 helper.Add(decl_kind, symbol, Source{{12, 34}});
1105 helper.Build();
1106
1107 ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
1108
1109 auto* use = AST().GlobalDeclarations()[0];
1110 auto* decl = AST().GlobalDeclarations()[1];
1111 EXPECT_THAT(Build().ordered_globals, ElementsAre(decl, use));
1112 }
1113
1114 INSTANTIATE_TEST_SUITE_P(Types,
1115 ResolverDependencyGraphOrderedGlobalsTest,
1116 testing::Combine(testing::ValuesIn(kTypeDeclKinds),
1117 testing::ValuesIn(kTypeUseKinds)));
1118
1119 INSTANTIATE_TEST_SUITE_P(
1120 Values,
1121 ResolverDependencyGraphOrderedGlobalsTest,
1122 testing::Combine(testing::ValuesIn(kGlobalValueDeclKinds),
1123 testing::ValuesIn(kValueUseKinds)));
1124
1125 INSTANTIATE_TEST_SUITE_P(Functions,
1126 ResolverDependencyGraphOrderedGlobalsTest,
1127 testing::Combine(testing::ValuesIn(kFuncDeclKinds),
1128 testing::ValuesIn(kFuncUseKinds)));
1129 } // namespace ordered_globals
1130
1131 ////////////////////////////////////////////////////////////////////////////////
1132 // Resolved symbols tests
1133 ////////////////////////////////////////////////////////////////////////////////
1134 namespace resolved_symbols {
1135
1136 using ResolverDependencyGraphResolvedSymbolTest =
1137 ResolverDependencyGraphTestWithParam<
1138 std::tuple<SymbolDeclKind, SymbolUseKind>>;
1139
TEST_P(ResolverDependencyGraphResolvedSymbolTest,Test)1140 TEST_P(ResolverDependencyGraphResolvedSymbolTest, Test) {
1141 const Symbol symbol = Sym("SYMBOL");
1142 const auto decl_kind = std::get<0>(GetParam());
1143 const auto use_kind = std::get<1>(GetParam());
1144
1145 // Build a symbol declaration and a use of that symbol
1146 SymbolTestHelper helper(this);
1147 auto* decl = helper.Add(decl_kind, symbol, Source{{12, 34}});
1148 auto* use = helper.Add(use_kind, symbol, Source{{56, 78}});
1149 helper.Build();
1150
1151 // If the declaration is visible to the use, then we expect the analysis to
1152 // succeed.
1153 bool expect_pass = ScopeDepth(decl_kind) <= ScopeDepth(use_kind);
1154 auto graph =
1155 Build(expect_pass ? "" : "56:78 error: unknown identifier: 'SYMBOL'");
1156
1157 if (expect_pass) {
1158 // Check that the use resolves to the declaration
1159 auto* resolved_symbol = graph.resolved_symbols[use];
1160 EXPECT_EQ(resolved_symbol, decl)
1161 << "resolved: "
1162 << (resolved_symbol ? resolved_symbol->TypeInfo().name : "<null>")
1163 << "\n"
1164 << "decl: " << decl->TypeInfo().name;
1165 }
1166 }
1167
1168 INSTANTIATE_TEST_SUITE_P(Types,
1169 ResolverDependencyGraphResolvedSymbolTest,
1170 testing::Combine(testing::ValuesIn(kTypeDeclKinds),
1171 testing::ValuesIn(kTypeUseKinds)));
1172
1173 INSTANTIATE_TEST_SUITE_P(Values,
1174 ResolverDependencyGraphResolvedSymbolTest,
1175 testing::Combine(testing::ValuesIn(kValueDeclKinds),
1176 testing::ValuesIn(kValueUseKinds)));
1177
1178 INSTANTIATE_TEST_SUITE_P(Functions,
1179 ResolverDependencyGraphResolvedSymbolTest,
1180 testing::Combine(testing::ValuesIn(kFuncDeclKinds),
1181 testing::ValuesIn(kFuncUseKinds)));
1182
1183 } // namespace resolved_symbols
1184
1185 ////////////////////////////////////////////////////////////////////////////////
1186 // Shadowing tests
1187 ////////////////////////////////////////////////////////////////////////////////
1188 namespace shadowing {
1189
1190 using ResolverDependencyShadowTest = ResolverDependencyGraphTestWithParam<
1191 std::tuple<SymbolDeclKind, SymbolDeclKind>>;
1192
TEST_P(ResolverDependencyShadowTest,Test)1193 TEST_P(ResolverDependencyShadowTest, Test) {
1194 const Symbol symbol = Sym("SYMBOL");
1195 const auto outer_kind = std::get<0>(GetParam());
1196 const auto inner_kind = std::get<1>(GetParam());
1197
1198 // Build a symbol declaration and a use of that symbol
1199 SymbolTestHelper helper(this);
1200 auto* outer = helper.Add(outer_kind, symbol, Source{{12, 34}});
1201 helper.Add(inner_kind, symbol, Source{{56, 78}});
1202 auto* inner_var = helper.nested_statements.size()
1203 ? helper.nested_statements[0]
1204 ->As<ast::VariableDeclStatement>()
1205 ->variable
1206 : helper.statements.size()
1207 ? helper.statements[0]
1208 ->As<ast::VariableDeclStatement>()
1209 ->variable
1210 : helper.parameters[0];
1211 helper.Build();
1212
1213 EXPECT_EQ(Build().shadows[inner_var], outer);
1214 }
1215
1216 INSTANTIATE_TEST_SUITE_P(LocalShadowGlobal,
1217 ResolverDependencyShadowTest,
1218 testing::Combine(testing::ValuesIn(kGlobalDeclKinds),
1219 testing::ValuesIn(kLocalDeclKinds)));
1220
1221 INSTANTIATE_TEST_SUITE_P(
1222 NestedLocalShadowLocal,
1223 ResolverDependencyShadowTest,
1224 testing::Combine(testing::Values(SymbolDeclKind::Parameter,
1225 SymbolDeclKind::LocalVar,
1226 SymbolDeclKind::LocalLet),
1227 testing::Values(SymbolDeclKind::NestedLocalVar,
1228 SymbolDeclKind::NestedLocalLet)));
1229
1230 } // namespace shadowing
1231
1232 ////////////////////////////////////////////////////////////////////////////////
1233 // AST traversal tests
1234 ////////////////////////////////////////////////////////////////////////////////
1235 namespace ast_traversal {
1236
1237 using ResolverDependencyGraphTraversalTest = ResolverDependencyGraphTest;
1238
TEST_F(ResolverDependencyGraphTraversalTest,SymbolsReached)1239 TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
1240 const auto value_sym = Sym("VALUE");
1241 const auto type_sym = Sym("TYPE");
1242 const auto func_sym = Sym("FUNC");
1243
1244 const auto* value_decl =
1245 Global(value_sym, ty.i32(), ast::StorageClass::kPrivate);
1246 const auto* type_decl = Alias(type_sym, ty.i32());
1247 const auto* func_decl = Func(func_sym, {}, ty.void_(), {});
1248
1249 struct SymbolUse {
1250 const ast::Node* decl = nullptr;
1251 const ast::Node* use = nullptr;
1252 std::string where = nullptr;
1253 };
1254
1255 std::vector<SymbolUse> symbol_uses;
1256
1257 auto add_use = [&](const ast::Node* decl, auto* use, int line,
1258 const char* kind) {
1259 symbol_uses.emplace_back(SymbolUse{
1260 decl, use,
1261 std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
1262 return use;
1263 };
1264 #define V add_use(value_decl, Expr(value_sym), __LINE__, "V()")
1265 #define T add_use(type_decl, ty.type_name(type_sym), __LINE__, "T()")
1266 #define F add_use(func_decl, Expr(func_sym), __LINE__, "F()")
1267
1268 Alias(Sym(), T);
1269 Structure(Sym(), {Member(Sym(), T)});
1270 Global(Sym(), T, V);
1271 GlobalConst(Sym(), T, V);
1272 Func(Sym(), //
1273 {Param(Sym(), T)}, //
1274 T, // Return type
1275 {
1276 Decl(Var(Sym(), T, V)), //
1277 Decl(Const(Sym(), T, V)), //
1278 CallStmt(Call(F, V)), //
1279 Block( //
1280 Assign(V, V)), //
1281 If(V, //
1282 Block(Assign(V, V)), //
1283 Else(V, //
1284 Block(Assign(V, V)))), //
1285 Ignore(Bitcast(T, V)), //
1286 For(Decl(Var(Sym(), T, V)), //
1287 Equal(V, V), //
1288 Assign(V, V), //
1289 Block( //
1290 Assign(V, V))), //
1291 Loop(Block(Assign(V, V)), //
1292 Block(Assign(V, V))), //
1293 Switch(V, //
1294 Case(Expr(1), //
1295 Block(Assign(V, V))), //
1296 Case(Expr(2), //
1297 Block(Fallthrough())), //
1298 DefaultCase(Block(Assign(V, V)))), //
1299 Return(V), //
1300 Break(), //
1301 Discard(), //
1302 }); //
1303 // Exercise type traversal
1304 Global(Sym(), ty.atomic(T));
1305 Global(Sym(), ty.bool_());
1306 Global(Sym(), ty.i32());
1307 Global(Sym(), ty.u32());
1308 Global(Sym(), ty.f32());
1309 Global(Sym(), ty.array(T, V, 4));
1310 Global(Sym(), ty.vec3(T));
1311 Global(Sym(), ty.mat3x2(T));
1312 Global(Sym(), ty.pointer(T, ast::StorageClass::kPrivate));
1313 Global(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
1314 Global(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
1315 Global(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
1316 Global(Sym(), ty.external_texture());
1317 Global(Sym(), ty.multisampled_texture(ast::TextureDimension::k2d, T));
1318 Global(Sym(), ty.storage_texture(ast::TextureDimension::k2d,
1319 ast::ImageFormat::kR16Float,
1320 ast::Access::kRead)); //
1321 Global(Sym(), ty.sampler(ast::SamplerKind::kSampler));
1322 Func(Sym(), {}, ty.void_(), {});
1323 #undef V
1324 #undef T
1325 #undef F
1326
1327 auto graph = Build();
1328 for (auto use : symbol_uses) {
1329 auto* resolved_symbol = graph.resolved_symbols[use.use];
1330 EXPECT_EQ(resolved_symbol, use.decl) << use.where;
1331 }
1332 }
1333
TEST_F(ResolverDependencyGraphTraversalTest,InferredType)1334 TEST_F(ResolverDependencyGraphTraversalTest, InferredType) {
1335 // Check that the nullptr of the var / let type doesn't make things explode
1336 Global("a", nullptr, Expr(1));
1337 GlobalConst("b", nullptr, Expr(1));
1338 WrapInFunction(Var("c", nullptr, Expr(1)), //
1339 Const("d", nullptr, Expr(1)));
1340 Build();
1341 }
1342
1343 // Reproduces an unbalanced stack push / pop bug in
1344 // DependencyAnalysis::SortGlobals(), found by clusterfuzz.
1345 // See: crbug.com/chromium/1273451
TEST_F(ResolverDependencyGraphTraversalTest,chromium_1273451)1346 TEST_F(ResolverDependencyGraphTraversalTest, chromium_1273451) {
1347 Structure("A", {Member("a", ty.i32())});
1348 Structure("B", {Member("b", ty.i32())});
1349 Func("f", {Param("a", ty.type_name("A"))}, ty.type_name("B"),
1350 {
1351 Return(Construct(ty.type_name("B"))),
1352 });
1353 Build();
1354 }
1355
1356 } // namespace ast_traversal
1357
1358 } // namespace
1359 } // namespace resolver
1360 } // namespace tint
1361