• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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