blob: 79b41d7b662e0f887c939fbca2795619c49f456d [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// Copyright 2021 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "src/tint/ast/builtin_attribute.h"
16#include "src/tint/ast/location_attribute.h"
17#include "src/tint/ast/return_statement.h"
18#include "src/tint/ast/stage_attribute.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000019#include "src/tint/resolver/resolver.h"
20#include "src/tint/resolver/resolver_test_helper.h"
21
22#include "gmock/gmock.h"
23
Ben Clayton0ce9ab02022-05-05 20:23:40 +000024using namespace tint::number_suffixes; // NOLINT
25
dan sinclaird2093792022-04-07 17:45:45 +000026namespace tint::resolver {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000027namespace {
28
29// Helpers and typedefs
30template <typename T>
31using DataType = builder::DataType<T>;
32template <typename T>
33using vec2 = builder::vec2<T>;
34template <typename T>
35using vec3 = builder::vec3<T>;
36template <typename T>
37using vec4 = builder::vec4<T>;
38template <typename T>
39using mat2x2 = builder::mat2x2<T>;
40template <typename T>
41using mat3x3 = builder::mat3x3<T>;
42template <typename T>
43using mat4x4 = builder::mat4x4<T>;
44template <typename T>
45using alias = builder::alias<T>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000046
dan sinclair41e4d9a2022-05-01 14:40:55 +000047class ResolverEntryPointValidationTest : public TestHelper, public testing::Test {};
Ryan Harrisondbc13af2022-02-21 15:19:07 +000048
49TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
dan sinclairb29892b2022-06-07 13:55:34 +000050 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +000051 // fn main() -> @location(0) f32 { return 1.0; }
Ben Clayton783b1692022-08-02 17:03:35 +000052 Func(Source{{12, 34}}, "main", utils::Empty, ty.f32(),
53 utils::Vector{
54 Return(1_f),
55 },
56 utils::Vector{
57 Stage(ast::PipelineStage::kFragment),
58 },
59 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +000060 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +000061 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +000062
dan sinclair41e4d9a2022-05-01 14:40:55 +000063 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000064}
65
66TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Builtin) {
dan sinclairb29892b2022-06-07 13:55:34 +000067 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +000068 // fn main() -> @builtin(position) vec4<f32> { return vec4<f32>(); }
Ben Clayton783b1692022-08-02 17:03:35 +000069 Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
70 utils::Vector{
71 Return(Construct(ty.vec4<f32>())),
72 },
73 utils::Vector{
74 Stage(ast::PipelineStage::kVertex),
75 },
76 utils::Vector{
77 Builtin(ast::BuiltinValue::kPosition),
78 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +000079
dan sinclair41e4d9a2022-05-01 14:40:55 +000080 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000081}
82
83TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Missing) {
dan sinclairb29892b2022-06-07 13:55:34 +000084 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +000085 // fn main() -> f32 {
86 // return 1.0;
87 // }
Ben Clayton783b1692022-08-02 17:03:35 +000088 Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
89 utils::Vector{
90 Return(Construct(ty.vec4<f32>())),
91 },
92 utils::Vector{
93 Stage(ast::PipelineStage::kVertex),
94 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +000095
dan sinclair41e4d9a2022-05-01 14:40:55 +000096 EXPECT_FALSE(r()->Resolve());
97 EXPECT_EQ(r()->error(), "12:34 error: missing entry point IO attribute on return type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +000098}
99
100TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
dan sinclairb29892b2022-06-07 13:55:34 +0000101 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +0000102 // fn main() -> @location(0) @builtin(position) vec4<f32> {
103 // return vec4<f32>();
104 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000105 Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
106 utils::Vector{
107 Return(Construct(ty.vec4<f32>())),
108 },
109 utils::Vector{
110 Stage(ast::PipelineStage::kVertex),
111 },
112 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000113 Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000114 Builtin(Source{{14, 52}}, ast::BuiltinValue::kPosition),
115 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000116
dan sinclair41e4d9a2022-05-01 14:40:55 +0000117 EXPECT_FALSE(r()->Resolve());
118 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ryan Harrisondbc13af2022-02-21 15:19:07 +000011913:43 note: previously consumed location(0))");
120}
121
122TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000123 // struct Output {
124 // @location(0) a : f32;
125 // @builtin(frag_depth) b : f32;
126 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000127 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000128 // fn main() -> Output {
129 // return Output();
130 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000131 auto* output = Structure(
132 "Output", utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000133 Member("a", ty.f32(), utils::Vector{Location(0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +0000134 Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
135 });
136 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
137 utils::Vector{
138 Return(Construct(ty.Of(output))),
139 },
140 utils::Vector{
141 Stage(ast::PipelineStage::kFragment),
142 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000143
dan sinclair41e4d9a2022-05-01 14:40:55 +0000144 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000145}
146
dan sinclair41e4d9a2022-05-01 14:40:55 +0000147TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMultipleAttributes) {
148 // struct Output {
149 // @location(0) @builtin(frag_depth) a : f32;
150 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000151 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000152 // fn main() -> Output {
153 // return Output();
154 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000155 auto* output = Structure(
156 "Output",
157 utils::Vector{
158 Member("a", ty.f32(),
dan sinclairf9eeed62022-09-07 22:25:24 +0000159 utils::Vector{Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000160 Builtin(Source{{14, 52}}, ast::BuiltinValue::kFragDepth)}),
161 });
162 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
163 utils::Vector{
164 Return(Construct(ty.Of(output))),
165 },
166 utils::Vector{
167 Stage(ast::PipelineStage::kFragment),
168 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000169
dan sinclair41e4d9a2022-05-01 14:40:55 +0000170 EXPECT_FALSE(r()->Resolve());
171 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ryan Harrisondbc13af2022-02-21 15:19:07 +000017213:43 note: previously consumed location(0)
Ben Clayton4fe330f2022-10-13 13:33:25 +000017312:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000174}
175
dan sinclair41e4d9a2022-05-01 14:40:55 +0000176TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMissingAttribute) {
177 // struct Output {
178 // @location(0) a : f32;
179 // b : f32;
180 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000181 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000182 // fn main() -> Output {
183 // return Output();
184 // }
dan sinclairf9eeed62022-09-07 22:25:24 +0000185 auto* output = Structure(
186 "Output", utils::Vector{
187 Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0_a)}),
188 Member(Source{{14, 52}}, "b", ty.f32(), {}),
189 });
Ben Clayton783b1692022-08-02 17:03:35 +0000190 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
191 utils::Vector{
192 Return(Construct(ty.Of(output))),
193 },
194 utils::Vector{
195 Stage(ast::PipelineStage::kFragment),
196 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000197
dan sinclair41e4d9a2022-05-01 14:40:55 +0000198 EXPECT_FALSE(r()->Resolve());
199 EXPECT_EQ(r()->error(),
200 R"(14:52 error: missing entry point IO attribute
Ben Clayton4fe330f2022-10-13 13:33:25 +000020112:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000202}
203
204TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000205 // struct Output {
206 // @builtin(frag_depth) a : f32;
207 // @builtin(frag_depth) b : f32;
208 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000209 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000210 // fn main() -> Output {
211 // return Output();
212 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000213 auto* output = Structure(
214 "Output", utils::Vector{
215 Member("a", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
216 Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
217 });
218 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
219 utils::Vector{
220 Return(Construct(ty.Of(output))),
221 },
222 utils::Vector{
223 Stage(ast::PipelineStage::kFragment),
224 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000225
dan sinclair41e4d9a2022-05-01 14:40:55 +0000226 EXPECT_FALSE(r()->Resolve());
227 EXPECT_EQ(
228 r()->error(),
229 R"(12:34 error: builtin(frag_depth) attribute appears multiple times as pipeline output
Ben Clayton4fe330f2022-10-13 13:33:25 +000023012:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000231}
232
233TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Location) {
dan sinclairb29892b2022-06-07 13:55:34 +0000234 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000235 // fn main(@location(0) param : f32) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000236 auto* param = Param("param", ty.f32(),
237 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000238 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000239 });
240 Func(Source{{12, 34}}, "main",
241 utils::Vector{
242 param,
243 },
244 ty.void_(), utils::Empty,
245 utils::Vector{
246 Stage(ast::PipelineStage::kFragment),
247 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000248
dan sinclair41e4d9a2022-05-01 14:40:55 +0000249 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000250}
251
252TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
dan sinclairb29892b2022-06-07 13:55:34 +0000253 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000254 // fn main(param : f32) {}
255 auto* param = Param(Source{{13, 43}}, "param", ty.vec4<f32>());
Ben Clayton783b1692022-08-02 17:03:35 +0000256 Func(Source{{12, 34}}, "main",
257 utils::Vector{
258 param,
259 },
260 ty.void_(), utils::Empty,
261 utils::Vector{
262 Stage(ast::PipelineStage::kFragment),
263 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000264
dan sinclair41e4d9a2022-05-01 14:40:55 +0000265 EXPECT_FALSE(r()->Resolve());
266 EXPECT_EQ(r()->error(), "13:43 error: missing entry point IO attribute on parameter");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000267}
268
269TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
dan sinclairb29892b2022-06-07 13:55:34 +0000270 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000271 // fn main(@location(0) @builtin(sample_index) param : u32) {}
Ben Claytonf3302292022-07-27 18:48:06 +0000272 auto* param = Param("param", ty.u32(),
Ben Clayton783b1692022-08-02 17:03:35 +0000273 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000274 Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000275 Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex),
276 });
277 Func(Source{{12, 34}}, "main",
278 utils::Vector{
279 param,
280 },
281 ty.void_(), utils::Empty,
282 utils::Vector{
283 Stage(ast::PipelineStage::kFragment),
284 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000285
dan sinclair41e4d9a2022-05-01 14:40:55 +0000286 EXPECT_FALSE(r()->Resolve());
287 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ryan Harrisondbc13af2022-02-21 15:19:07 +000028813:43 note: previously consumed location(0))");
289}
290
291TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000292 // struct Input {
293 // @location(0) a : f32;
294 // @builtin(sample_index) b : u32;
295 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000296 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000297 // fn main(param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000298 auto* input = Structure(
299 "Input", utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000300 Member("a", ty.f32(), utils::Vector{Location(0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +0000301 Member("b", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
302 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000303 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000304 Func(Source{{12, 34}}, "main",
305 utils::Vector{
306 param,
307 },
308 ty.void_(), utils::Empty,
309 utils::Vector{
310 Stage(ast::PipelineStage::kFragment),
311 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000312
dan sinclair41e4d9a2022-05-01 14:40:55 +0000313 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000314}
315
dan sinclair41e4d9a2022-05-01 14:40:55 +0000316TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMultipleAttributes) {
317 // struct Input {
318 // @location(0) @builtin(sample_index) a : u32;
319 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000320 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000321 // fn main(param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000322 auto* input = Structure(
323 "Input",
324 utils::Vector{
325 Member("a", ty.u32(),
dan sinclairf9eeed62022-09-07 22:25:24 +0000326 utils::Vector{Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000327 Builtin(Source{{14, 52}}, ast::BuiltinValue::kSampleIndex)}),
328 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000329 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000330 Func(Source{{12, 34}}, "main",
331 utils::Vector{
332 param,
333 },
334 ty.void_(), utils::Empty,
335 utils::Vector{
336 Stage(ast::PipelineStage::kFragment),
337 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000338
dan sinclair41e4d9a2022-05-01 14:40:55 +0000339 EXPECT_FALSE(r()->Resolve());
340 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ryan Harrisondbc13af2022-02-21 15:19:07 +000034113:43 note: previously consumed location(0)
Ben Clayton4fe330f2022-10-13 13:33:25 +000034212:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000343}
344
dan sinclair41e4d9a2022-05-01 14:40:55 +0000345TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMissingAttribute) {
346 // struct Input {
347 // @location(0) a : f32;
348 // b : f32;
349 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000350 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000351 // fn main(param : Input) {}
dan sinclairf9eeed62022-09-07 22:25:24 +0000352 auto* input = Structure(
353 "Input", utils::Vector{
354 Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0_a)}),
355 Member(Source{{14, 52}}, "b", ty.f32(), {}),
356 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000357 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000358 Func(Source{{12, 34}}, "main",
359 utils::Vector{
360 param,
361 },
362 ty.void_(), utils::Empty,
363 utils::Vector{
364 Stage(ast::PipelineStage::kFragment),
365 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000366
dan sinclair41e4d9a2022-05-01 14:40:55 +0000367 EXPECT_FALSE(r()->Resolve());
368 EXPECT_EQ(r()->error(), R"(14:52 error: missing entry point IO attribute
Ben Clayton4fe330f2022-10-13 13:33:25 +000036912:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000370}
371
372TEST_F(ResolverEntryPointValidationTest, Parameter_DuplicateBuiltins) {
dan sinclairb29892b2022-06-07 13:55:34 +0000373 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000374 // fn main(@builtin(sample_index) param_a : u32,
375 // @builtin(sample_index) param_b : u32) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000376 auto* param_a = Param("param_a", ty.u32(),
377 utils::Vector{
378 Builtin(ast::BuiltinValue::kSampleIndex),
379 });
380 auto* param_b = Param("param_b", ty.u32(),
381 utils::Vector{
382 Builtin(ast::BuiltinValue::kSampleIndex),
383 });
384 Func(Source{{12, 34}}, "main",
385 utils::Vector{
386 param_a,
387 param_b,
388 },
389 ty.void_(), utils::Empty,
390 utils::Vector{
391 Stage(ast::PipelineStage::kFragment),
392 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000393
dan sinclair41e4d9a2022-05-01 14:40:55 +0000394 EXPECT_FALSE(r()->Resolve());
395 EXPECT_EQ(r()->error(),
396 "12:34 error: builtin(sample_index) attribute appears multiple times as "
397 "pipeline input");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000398}
399
400TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000401 // struct InputA {
402 // @builtin(sample_index) a : u32;
403 // };
404 // struct InputB {
405 // @builtin(sample_index) a : u32;
406 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000407 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000408 // fn main(param_a : InputA, param_b : InputB) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000409 auto* input_a = Structure(
410 "InputA",
411 utils::Vector{
412 Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
413 });
414 auto* input_b = Structure(
415 "InputB",
416 utils::Vector{
417 Member("a", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kSampleIndex)}),
418 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000419 auto* param_a = Param("param_a", ty.Of(input_a));
420 auto* param_b = Param("param_b", ty.Of(input_b));
Ben Clayton783b1692022-08-02 17:03:35 +0000421 Func(Source{{12, 34}}, "main",
422 utils::Vector{
423 param_a,
424 param_b,
425 },
426 ty.void_(), utils::Empty,
427 utils::Vector{
428 Stage(ast::PipelineStage::kFragment),
429 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000430
dan sinclair41e4d9a2022-05-01 14:40:55 +0000431 EXPECT_FALSE(r()->Resolve());
432 EXPECT_EQ(
433 r()->error(),
434 R"(12:34 error: builtin(sample_index) attribute appears multiple times as pipeline input
Ben Clayton4fe330f2022-10-13 13:33:25 +000043512:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000436}
437
438TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
dan sinclairb29892b2022-06-07 13:55:34 +0000439 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +0000440 // fn main() {}
Ben Clayton783b1692022-08-02 17:03:35 +0000441 Func(Source{{12, 34}}, "main", utils::Empty, ty.void_(), utils::Empty,
442 utils::Vector{
443 Stage(ast::PipelineStage::kVertex),
444 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000445
dan sinclair41e4d9a2022-05-01 14:40:55 +0000446 EXPECT_FALSE(r()->Resolve());
447 EXPECT_EQ(r()->error(),
448 "12:34 error: a vertex shader must include the 'position' builtin "
449 "in its return type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000450}
451
dan sinclair4abf28e2022-08-02 15:55:35 +0000452TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithEnable) {
453 // enable chromium_experimental_push_constant;
454 // var<push_constant> a : u32;
455 Enable(ast::Extension::kChromiumExperimentalPushConstant);
dan sinclairff7cf212022-10-03 14:05:23 +0000456 GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000457
458 EXPECT_TRUE(r()->Resolve());
459}
460
461TEST_F(ResolverEntryPointValidationTest, PushConstantDisallowedWithoutEnable) {
462 // var<push_constant> a : u32;
dan sinclairff7cf212022-10-03 14:05:23 +0000463 GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000464
465 EXPECT_FALSE(r()->Resolve());
466 EXPECT_EQ(r()->error(),
dan sinclairff7cf212022-10-03 14:05:23 +0000467 "1:2 error: use of variable address space 'push_constant' requires enabling "
dan sinclair4abf28e2022-08-02 15:55:35 +0000468 "extension 'chromium_experimental_push_constant'");
469}
470
dan sinclairff7cf212022-10-03 14:05:23 +0000471TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithIgnoreAddressSpaceAttribute) {
472 // var<push_constant> a : u32; // With ast::DisabledValidation::kIgnoreAddressSpace
473 GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant,
474 utils::Vector{Disable(ast::DisabledValidation::kIgnoreAddressSpace)});
dan sinclair4abf28e2022-08-02 15:55:35 +0000475
476 EXPECT_TRUE(r()->Resolve());
477}
478
479TEST_F(ResolverEntryPointValidationTest, PushConstantOneVariableUsedInEntryPoint) {
480 // enable chromium_experimental_push_constant;
481 // var<push_constant> a : u32;
482 // @compute @workgroup_size(1) fn main() {
483 // _ = a;
484 // }
485 Enable(ast::Extension::kChromiumExperimentalPushConstant);
dan sinclairff7cf212022-10-03 14:05:23 +0000486 GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000487
dan sinclairab5fc1c2022-08-02 19:43:14 +0000488 Func("main", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
489 utils::Vector{Stage(ast::PipelineStage::kCompute),
490 create<ast::WorkgroupAttribute>(Expr(1_i))});
dan sinclair4abf28e2022-08-02 15:55:35 +0000491
492 EXPECT_TRUE(r()->Resolve());
493}
494
495TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInEntryPoint) {
496 // enable chromium_experimental_push_constant;
497 // var<push_constant> a : u32;
498 // var<push_constant> b : u32;
499 // @compute @workgroup_size(1) fn main() {
500 // _ = a;
501 // _ = b;
502 // }
503 Enable(ast::Extension::kChromiumExperimentalPushConstant);
dan sinclairff7cf212022-10-03 14:05:23 +0000504 GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::AddressSpace::kPushConstant);
505 GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000506
dan sinclairab5fc1c2022-08-02 19:43:14 +0000507 Func(Source{{5, 6}}, "main", {}, ty.void_(),
508 utils::Vector{Assign(Phony(), "a"), Assign(Phony(), "b")},
509 utils::Vector{Stage(ast::PipelineStage::kCompute),
510 create<ast::WorkgroupAttribute>(Expr(1_i))});
dan sinclair4abf28e2022-08-02 15:55:35 +0000511
512 EXPECT_FALSE(r()->Resolve());
513 EXPECT_EQ(r()->error(),
514 R"(5:6 error: entry point 'main' uses two different 'push_constant' variables.
5153:4 note: first 'push_constant' variable declaration is here
5161:2 note: second 'push_constant' variable declaration is here)");
517}
518
519TEST_F(ResolverEntryPointValidationTest,
520 PushConstantTwoVariablesUsedInEntryPointWithFunctionGraph) {
521 // enable chromium_experimental_push_constant;
522 // var<push_constant> a : u32;
523 // var<push_constant> b : u32;
524 // fn uses_a() {
525 // _ = a;
526 // }
527 // fn uses_b() {
528 // _ = b;
529 // }
530 // @compute @workgroup_size(1) fn main() {
531 // uses_a();
532 // uses_b();
533 // }
534 Enable(ast::Extension::kChromiumExperimentalPushConstant);
dan sinclairff7cf212022-10-03 14:05:23 +0000535 GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::AddressSpace::kPushConstant);
536 GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000537
dan sinclairab5fc1c2022-08-02 19:43:14 +0000538 Func(Source{{5, 6}}, "uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")});
539 Func(Source{{7, 8}}, "uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")});
dan sinclair4abf28e2022-08-02 15:55:35 +0000540
541 Func(Source{{9, 10}}, "main", {}, ty.void_(),
dan sinclairab5fc1c2022-08-02 19:43:14 +0000542 utils::Vector{CallStmt(Call("uses_a")), CallStmt(Call("uses_b"))},
543 utils::Vector{Stage(ast::PipelineStage::kCompute),
544 create<ast::WorkgroupAttribute>(Expr(1_i))});
dan sinclair4abf28e2022-08-02 15:55:35 +0000545
546 EXPECT_FALSE(r()->Resolve());
547 EXPECT_EQ(r()->error(),
548 R"(9:10 error: entry point 'main' uses two different 'push_constant' variables.
5493:4 note: first 'push_constant' variable declaration is here
5507:8 note: called by function 'uses_b'
5519:10 note: called by entry point 'main'
5521:2 note: second 'push_constant' variable declaration is here
5535:6 note: called by function 'uses_a'
5549:10 note: called by entry point 'main')");
555}
556
557TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInDifferentEntryPoint) {
558 // enable chromium_experimental_push_constant;
559 // var<push_constant> a : u32;
560 // var<push_constant> b : u32;
561 // @compute @workgroup_size(1) fn uses_a() {
562 // _ = a;
563 // }
564 // @compute @workgroup_size(1) fn uses_b() {
565 // _ = a;
566 // }
567 Enable(ast::Extension::kChromiumExperimentalPushConstant);
dan sinclairff7cf212022-10-03 14:05:23 +0000568 GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant);
569 GlobalVar("b", ty.u32(), ast::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000570
dan sinclairab5fc1c2022-08-02 19:43:14 +0000571 Func("uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
572 utils::Vector{Stage(ast::PipelineStage::kCompute),
573 create<ast::WorkgroupAttribute>(Expr(1_i))});
574 Func("uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")},
575 utils::Vector{Stage(ast::PipelineStage::kCompute),
576 create<ast::WorkgroupAttribute>(Expr(1_i))});
dan sinclair4abf28e2022-08-02 15:55:35 +0000577
578 EXPECT_TRUE(r()->Resolve());
579}
580
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000581namespace TypeValidationTests {
582struct Params {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000583 builder::ast_type_func_ptr create_ast_type;
584 bool is_valid;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000585};
586
587template <typename T>
588constexpr Params ParamsFor(bool is_valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000589 return Params{DataType<T>::AST, is_valid};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000590}
591
592using TypeValidationTest = resolver::ResolverTestWithParam<Params>;
593
594static constexpr Params cases[] = {
595 ParamsFor<f32>(true), //
596 ParamsFor<i32>(true), //
597 ParamsFor<u32>(true), //
598 ParamsFor<bool>(false), //
599 ParamsFor<vec2<f32>>(true), //
600 ParamsFor<vec3<f32>>(true), //
601 ParamsFor<vec4<f32>>(true), //
602 ParamsFor<mat2x2<f32>>(false), //
603 ParamsFor<mat3x3<f32>>(false), //
604 ParamsFor<mat4x4<f32>>(false), //
605 ParamsFor<alias<f32>>(true), //
606 ParamsFor<alias<i32>>(true), //
607 ParamsFor<alias<u32>>(true), //
608 ParamsFor<alias<bool>>(false), //
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000609 // Currently entry point IO of f16 types are not implemented yet.
610 // TODO(tint:1473, tint:1502): Change f16 and vecN<f16> cases to valid after f16 is supported in
611 // entry point IO.
612 ParamsFor<f16>(false), //
613 ParamsFor<vec2<f16>>(false), //
614 ParamsFor<vec3<f16>>(false), //
615 ParamsFor<vec4<f16>>(false), //
616 ParamsFor<mat2x2<f16>>(false), //
617 ParamsFor<mat3x3<f16>>(false), //
618 ParamsFor<mat4x4<f16>>(false), //
619 ParamsFor<alias<f16>>(false), //
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000620};
621
622TEST_P(TypeValidationTest, BareInputs) {
dan sinclairb29892b2022-06-07 13:55:34 +0000623 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000624 // fn main(@location(0) @interpolate(flat) a : *) {}
625 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000626
627 Enable(ast::Extension::kF16);
628
Ben Clayton783b1692022-08-02 17:03:35 +0000629 auto* a = Param("a", params.create_ast_type(*this),
630 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000631 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000632 Flat(),
633 });
634 Func(Source{{12, 34}}, "main",
635 utils::Vector{
636 a,
637 },
638 ty.void_(), utils::Empty,
639 utils::Vector{
640 Stage(ast::PipelineStage::kFragment),
641 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000642
dan sinclair41e4d9a2022-05-01 14:40:55 +0000643 if (params.is_valid) {
644 EXPECT_TRUE(r()->Resolve()) << r()->error();
645 } else {
646 EXPECT_FALSE(r()->Resolve());
647 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000648}
649
650TEST_P(TypeValidationTest, StructInputs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000651 // struct Input {
652 // @location(0) @interpolate(flat) a : *;
653 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000654 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000655 // fn main(a : Input) {}
656 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000657
658 Enable(ast::Extension::kF16);
659
dan sinclairf9eeed62022-09-07 22:25:24 +0000660 auto* input = Structure("Input", utils::Vector{
661 Member("a", params.create_ast_type(*this),
662 utils::Vector{Location(0_a), Flat()}),
663 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000664 auto* a = Param("a", ty.Of(input), {});
Ben Clayton783b1692022-08-02 17:03:35 +0000665 Func(Source{{12, 34}}, "main",
666 utils::Vector{
667 a,
668 },
669 ty.void_(), utils::Empty,
670 utils::Vector{
671 Stage(ast::PipelineStage::kFragment),
672 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000673
dan sinclair41e4d9a2022-05-01 14:40:55 +0000674 if (params.is_valid) {
675 EXPECT_TRUE(r()->Resolve()) << r()->error();
676 } else {
677 EXPECT_FALSE(r()->Resolve());
678 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000679}
680
681TEST_P(TypeValidationTest, BareOutputs) {
dan sinclairb29892b2022-06-07 13:55:34 +0000682 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000683 // fn main() -> @location(0) * {
684 // return *();
685 // }
686 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000687
688 Enable(ast::Extension::kF16);
689
Ben Clayton783b1692022-08-02 17:03:35 +0000690 Func(Source{{12, 34}}, "main", utils::Empty, params.create_ast_type(*this),
691 utils::Vector{
692 Return(Construct(params.create_ast_type(*this))),
693 },
694 utils::Vector{
695 Stage(ast::PipelineStage::kFragment),
696 },
697 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000698 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000699 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000700
dan sinclair41e4d9a2022-05-01 14:40:55 +0000701 if (params.is_valid) {
702 EXPECT_TRUE(r()->Resolve()) << r()->error();
703 } else {
704 EXPECT_FALSE(r()->Resolve());
705 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000706}
707
708TEST_P(TypeValidationTest, StructOutputs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000709 // struct Output {
710 // @location(0) a : *;
711 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000712 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000713 // fn main() -> Output {
714 // return Output();
715 // }
716 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000717
718 Enable(ast::Extension::kF16);
719
Ben Clayton783b1692022-08-02 17:03:35 +0000720 auto* output = Structure(
721 "Output", utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000722 Member("a", params.create_ast_type(*this), utils::Vector{Location(0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +0000723 });
724 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
725 utils::Vector{
726 Return(Construct(ty.Of(output))),
727 },
728 utils::Vector{
729 Stage(ast::PipelineStage::kFragment),
730 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000731
dan sinclair41e4d9a2022-05-01 14:40:55 +0000732 if (params.is_valid) {
733 EXPECT_TRUE(r()->Resolve()) << r()->error();
734 } else {
735 EXPECT_FALSE(r()->Resolve());
736 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000737}
738INSTANTIATE_TEST_SUITE_P(ResolverEntryPointValidationTest,
739 TypeValidationTest,
740 testing::ValuesIn(cases));
741
742} // namespace TypeValidationTests
743
744namespace LocationAttributeTests {
745namespace {
746using LocationAttributeTests = ResolverTest;
747
748TEST_F(LocationAttributeTests, Pass) {
dan sinclairb29892b2022-06-07 13:55:34 +0000749 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000750 // fn frag_main(@location(0) @interpolate(flat) a: i32) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000751
Ben Clayton783b1692022-08-02 17:03:35 +0000752 auto* p = Param(Source{{12, 34}}, "a", ty.i32(),
753 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000754 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000755 Flat(),
756 });
757 Func("frag_main",
758 utils::Vector{
759 p,
760 },
761 ty.void_(), utils::Empty,
762 utils::Vector{
763 Stage(ast::PipelineStage::kFragment),
764 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000765
dan sinclair41e4d9a2022-05-01 14:40:55 +0000766 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000767}
768
769TEST_F(LocationAttributeTests, BadType_Input_bool) {
dan sinclairb29892b2022-06-07 13:55:34 +0000770 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000771 // fn frag_main(@location(0) a: bool) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000772
Ben Clayton783b1692022-08-02 17:03:35 +0000773 auto* p = Param(Source{{12, 34}}, "a", ty.bool_(),
774 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000775 Location(Source{{34, 56}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000776 });
777 Func("frag_main",
778 utils::Vector{
779 p,
780 },
781 ty.void_(), utils::Empty,
782 utils::Vector{
783 Stage(ast::PipelineStage::kFragment),
784 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000785
dan sinclair41e4d9a2022-05-01 14:40:55 +0000786 EXPECT_FALSE(r()->Resolve());
787 EXPECT_EQ(r()->error(),
788 "12:34 error: cannot apply 'location' attribute to declaration of "
789 "type 'bool'\n"
790 "34:56 note: 'location' attribute must only be applied to "
791 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000792}
793
794TEST_F(LocationAttributeTests, BadType_Output_Array) {
dan sinclairb29892b2022-06-07 13:55:34 +0000795 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000796 // fn frag_main()->@location(0) array<f32, 2> { return array<f32, 2>(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000797
Ben Clayton783b1692022-08-02 17:03:35 +0000798 Func(Source{{12, 34}}, "frag_main", utils::Empty, ty.array<f32, 2>(),
799 utils::Vector{
800 Return(Construct(ty.array<f32, 2>())),
801 },
802 utils::Vector{
803 Stage(ast::PipelineStage::kFragment),
804 },
805 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000806 Location(Source{{34, 56}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000807 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000808
dan sinclair41e4d9a2022-05-01 14:40:55 +0000809 EXPECT_FALSE(r()->Resolve());
810 EXPECT_EQ(r()->error(),
811 "12:34 error: cannot apply 'location' attribute to declaration of "
812 "type 'array<f32, 2>'\n"
813 "34:56 note: 'location' attribute must only be applied to "
814 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000815}
816
817TEST_F(LocationAttributeTests, BadType_Input_Struct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000818 // struct Input {
819 // a : f32;
820 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000821 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000822 // fn main(@location(0) param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000823 auto* input = Structure("Input", utils::Vector{
824 Member("a", ty.f32()),
825 });
826 auto* param = Param(Source{{12, 34}}, "param", ty.Of(input),
827 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000828 Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000829 });
830 Func(Source{{12, 34}}, "main",
831 utils::Vector{
832 param,
833 },
834 ty.void_(), utils::Empty,
835 utils::Vector{
836 Stage(ast::PipelineStage::kFragment),
837 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000838
dan sinclair41e4d9a2022-05-01 14:40:55 +0000839 EXPECT_FALSE(r()->Resolve());
840 EXPECT_EQ(r()->error(),
841 "12:34 error: cannot apply 'location' attribute to declaration of "
842 "type 'Input'\n"
843 "13:43 note: 'location' attribute must only be applied to "
844 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000845}
846
847TEST_F(LocationAttributeTests, BadType_Input_Struct_NestedStruct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000848 // struct Inner {
849 // @location(0) b : f32;
850 // };
851 // struct Input {
852 // a : Inner;
853 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000854 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000855 // fn main(param : Input) {}
dan sinclairf9eeed62022-09-07 22:25:24 +0000856 auto* inner = Structure(
857 "Inner", utils::Vector{
858 Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0_a)}),
859 });
Ben Clayton783b1692022-08-02 17:03:35 +0000860 auto* input = Structure("Input", utils::Vector{
861 Member(Source{{14, 52}}, "a", ty.Of(inner)),
862 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000863 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000864 Func(Source{{12, 34}}, "main",
865 utils::Vector{
866 param,
867 },
868 ty.void_(), utils::Empty,
869 utils::Vector{
870 Stage(ast::PipelineStage::kFragment),
871 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000872
dan sinclair41e4d9a2022-05-01 14:40:55 +0000873 EXPECT_FALSE(r()->Resolve());
874 EXPECT_EQ(r()->error(),
875 "14:52 error: nested structures cannot be used for entry point IO\n"
Ben Clayton4fe330f2022-10-13 13:33:25 +0000876 "12:34 note: while analyzing entry point 'main'");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000877}
878
879TEST_F(LocationAttributeTests, BadType_Input_Struct_RuntimeArray) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000880 // struct Input {
881 // @location(0) a : array<f32>;
882 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000883 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000884 // fn main(param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000885 auto* input = Structure(
886 "Input", utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000887 Member(Source{{13, 43}}, "a", ty.array<f32>(), utils::Vector{Location(0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +0000888 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000889 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000890 Func(Source{{12, 34}}, "main",
891 utils::Vector{
892 param,
893 },
894 ty.void_(), utils::Empty,
895 utils::Vector{
896 Stage(ast::PipelineStage::kFragment),
897 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000898
dan sinclair41e4d9a2022-05-01 14:40:55 +0000899 EXPECT_FALSE(r()->Resolve());
900 EXPECT_EQ(r()->error(),
901 "13:43 error: cannot apply 'location' attribute to declaration of "
902 "type 'array<f32>'\n"
903 "note: 'location' attribute must only be applied to declarations "
904 "of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000905}
906
907TEST_F(LocationAttributeTests, BadMemberType_Input) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000908 // struct S { @location(0) m: array<i32>; };
dan sinclairb29892b2022-06-07 13:55:34 +0000909 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000910 // fn frag_main( a: S) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000911
dan sinclair41e4d9a2022-05-01 14:40:55 +0000912 auto* m = Member(Source{{34, 56}}, "m", ty.array<i32>(),
Ben Clayton783b1692022-08-02 17:03:35 +0000913 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000914 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +0000915 });
916 auto* s = Structure("S", utils::Vector{m});
dan sinclair41e4d9a2022-05-01 14:40:55 +0000917 auto* p = Param("a", ty.Of(s));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000918
Ben Clayton783b1692022-08-02 17:03:35 +0000919 Func("frag_main",
920 utils::Vector{
921 p,
922 },
923 ty.void_(), utils::Empty,
924 utils::Vector{
925 Stage(ast::PipelineStage::kFragment),
926 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000927
dan sinclair41e4d9a2022-05-01 14:40:55 +0000928 EXPECT_FALSE(r()->Resolve());
929 EXPECT_EQ(r()->error(),
930 "34:56 error: cannot apply 'location' attribute to declaration of "
931 "type 'array<i32>'\n"
932 "12:34 note: 'location' attribute must only be applied to "
933 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000934}
935
936TEST_F(LocationAttributeTests, BadMemberType_Output) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000937 // struct S { @location(0) m: atomic<i32>; };
dan sinclairb29892b2022-06-07 13:55:34 +0000938 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000939 // fn frag_main() -> S {}
940 auto* m = Member(Source{{34, 56}}, "m", ty.atomic<i32>(),
Ben Clayton783b1692022-08-02 17:03:35 +0000941 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000942 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +0000943 });
944 auto* s = Structure("S", utils::Vector{m});
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000945
Ben Clayton783b1692022-08-02 17:03:35 +0000946 Func("frag_main", utils::Empty, ty.Of(s),
947 utils::Vector{
948 Return(Construct(ty.Of(s))),
949 },
950 utils::Vector{
951 Stage(ast::PipelineStage::kFragment),
952 },
953 {});
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000954
dan sinclair41e4d9a2022-05-01 14:40:55 +0000955 EXPECT_FALSE(r()->Resolve());
956 EXPECT_EQ(r()->error(),
957 "34:56 error: cannot apply 'location' attribute to declaration of "
958 "type 'atomic<i32>'\n"
959 "12:34 note: 'location' attribute must only be applied to "
960 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000961}
962
963TEST_F(LocationAttributeTests, BadMemberType_Unused) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000964 // struct S { @location(0) m: mat3x2<f32>; };
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000965
dan sinclair41e4d9a2022-05-01 14:40:55 +0000966 auto* m = Member(Source{{34, 56}}, "m", ty.mat3x2<f32>(),
Ben Clayton783b1692022-08-02 17:03:35 +0000967 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000968 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +0000969 });
970 Structure("S", utils::Vector{m});
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000971
dan sinclair41e4d9a2022-05-01 14:40:55 +0000972 EXPECT_FALSE(r()->Resolve());
973 EXPECT_EQ(r()->error(),
974 "34:56 error: cannot apply 'location' attribute to declaration of "
975 "type 'mat3x2<f32>'\n"
976 "12:34 note: 'location' attribute must only be applied to "
977 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000978}
979
980TEST_F(LocationAttributeTests, ReturnType_Struct_Valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000981 // struct Output {
982 // @location(0) a : f32;
983 // @builtin(frag_depth) b : f32;
984 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000985 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000986 // fn main() -> Output {
987 // return Output();
988 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000989 auto* output = Structure(
990 "Output", utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000991 Member("a", ty.f32(), utils::Vector{Location(0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +0000992 Member("b", ty.f32(), utils::Vector{Builtin(ast::BuiltinValue::kFragDepth)}),
993 });
994 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
995 utils::Vector{
996 Return(Construct(ty.Of(output))),
997 },
998 utils::Vector{
999 Stage(ast::PipelineStage::kFragment),
1000 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001001
dan sinclair41e4d9a2022-05-01 14:40:55 +00001002 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001003}
1004
1005TEST_F(LocationAttributeTests, ReturnType_Struct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001006 // struct Output {
1007 // a : f32;
1008 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001009 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +00001010 // fn main() -> @location(0) Output {
1011 // return Output();
1012 // }
Ben Clayton783b1692022-08-02 17:03:35 +00001013 auto* output = Structure("Output", utils::Vector{
1014 Member("a", ty.f32()),
1015 });
1016 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
1017 utils::Vector{
1018 Return(Construct(ty.Of(output))),
1019 },
1020 utils::Vector{
1021 Stage(ast::PipelineStage::kVertex),
1022 },
1023 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001024 Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001025 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001026
dan sinclair41e4d9a2022-05-01 14:40:55 +00001027 EXPECT_FALSE(r()->Resolve());
1028 EXPECT_EQ(r()->error(),
1029 "12:34 error: cannot apply 'location' attribute to declaration of "
1030 "type 'Output'\n"
1031 "13:43 note: 'location' attribute must only be applied to "
1032 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001033}
1034
1035TEST_F(LocationAttributeTests, ReturnType_Struct_NestedStruct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001036 // struct Inner {
1037 // @location(0) b : f32;
1038 // };
1039 // struct Output {
1040 // a : Inner;
1041 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001042 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001043 // fn main() -> Output { return Output(); }
dan sinclairf9eeed62022-09-07 22:25:24 +00001044 auto* inner = Structure(
1045 "Inner", utils::Vector{
1046 Member(Source{{13, 43}}, "a", ty.f32(), utils::Vector{Location(0_a)}),
1047 });
Ben Clayton783b1692022-08-02 17:03:35 +00001048 auto* output = Structure("Output", utils::Vector{
1049 Member(Source{{14, 52}}, "a", ty.Of(inner)),
1050 });
1051 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
1052 utils::Vector{
1053 Return(Construct(ty.Of(output))),
1054 },
1055 utils::Vector{
1056 Stage(ast::PipelineStage::kFragment),
1057 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001058
dan sinclair41e4d9a2022-05-01 14:40:55 +00001059 EXPECT_FALSE(r()->Resolve());
1060 EXPECT_EQ(r()->error(),
1061 "14:52 error: nested structures cannot be used for entry point IO\n"
Ben Clayton4fe330f2022-10-13 13:33:25 +00001062 "12:34 note: while analyzing entry point 'main'");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001063}
1064
1065TEST_F(LocationAttributeTests, ReturnType_Struct_RuntimeArray) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001066 // struct Output {
1067 // @location(0) a : array<f32>;
1068 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001069 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001070 // fn main() -> Output {
1071 // return Output();
1072 // }
Ben Clayton783b1692022-08-02 17:03:35 +00001073 auto* output = Structure("Output", utils::Vector{
1074 Member(Source{{13, 43}}, "a", ty.array<f32>(),
dan sinclairf9eeed62022-09-07 22:25:24 +00001075 utils::Vector{Location(Source{{12, 34}}, 0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +00001076 });
1077 Func(Source{{12, 34}}, "main", utils::Empty, ty.Of(output),
1078 utils::Vector{
1079 Return(Construct(ty.Of(output))),
1080 },
1081 utils::Vector{
1082 Stage(ast::PipelineStage::kFragment),
1083 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001084
dan sinclair41e4d9a2022-05-01 14:40:55 +00001085 EXPECT_FALSE(r()->Resolve());
1086 EXPECT_EQ(r()->error(),
1087 "13:43 error: cannot apply 'location' attribute to declaration of "
1088 "type 'array<f32>'\n"
1089 "12:34 note: 'location' attribute must only be applied to "
1090 "declarations of numeric scalar or numeric vector type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001091}
1092
1093TEST_F(LocationAttributeTests, ComputeShaderLocation_Input) {
Ben Clayton783b1692022-08-02 17:03:35 +00001094 Func("main", utils::Empty, ty.i32(),
1095 utils::Vector{
1096 Return(Expr(1_i)),
1097 },
1098 utils::Vector{
1099 Stage(ast::PipelineStage::kCompute),
1100 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1101 },
1102 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001103 Location(Source{{12, 34}}, 1_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001104 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001105
dan sinclair41e4d9a2022-05-01 14:40:55 +00001106 EXPECT_FALSE(r()->Resolve());
1107 EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader output");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001108}
1109
1110TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
Ben Clayton783b1692022-08-02 17:03:35 +00001111 auto* input = Param("input", ty.i32(),
1112 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001113 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +00001114 });
1115 Func("main", utils::Vector{input}, ty.void_(), utils::Empty,
1116 utils::Vector{
1117 Stage(ast::PipelineStage::kCompute),
1118 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1119 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001120
dan sinclair41e4d9a2022-05-01 14:40:55 +00001121 EXPECT_FALSE(r()->Resolve());
1122 EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader inputs");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001123}
1124
1125TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
Ben Clayton783b1692022-08-02 17:03:35 +00001126 auto* m = Member("m", ty.i32(),
1127 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001128 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +00001129 });
1130 auto* s = Structure("S", utils::Vector{m});
1131 Func(Source{{56, 78}}, "main", utils::Empty, ty.Of(s),
1132 utils::Vector{
1133 Return(Expr(Construct(ty.Of(s)))),
1134 },
1135 utils::Vector{
1136 Stage(ast::PipelineStage::kCompute),
1137 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1138 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001139
dan sinclair41e4d9a2022-05-01 14:40:55 +00001140 EXPECT_FALSE(r()->Resolve());
1141 EXPECT_EQ(r()->error(),
1142 "12:34 error: attribute is not valid for compute shader output\n"
Ben Clayton4fe330f2022-10-13 13:33:25 +00001143 "56:78 note: while analyzing entry point 'main'");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001144}
1145
1146TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Input) {
Ben Clayton783b1692022-08-02 17:03:35 +00001147 auto* m = Member("m", ty.i32(),
1148 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001149 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +00001150 });
1151 auto* s = Structure("S", utils::Vector{m});
dan sinclair41e4d9a2022-05-01 14:40:55 +00001152 auto* input = Param("input", ty.Of(s));
Ben Clayton783b1692022-08-02 17:03:35 +00001153 Func(Source{{56, 78}}, "main", utils::Vector{input}, ty.void_(), utils::Empty,
1154 utils::Vector{
1155 Stage(ast::PipelineStage::kCompute),
1156 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1157 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001158
dan sinclair41e4d9a2022-05-01 14:40:55 +00001159 EXPECT_FALSE(r()->Resolve());
1160 EXPECT_EQ(r()->error(),
1161 "12:34 error: attribute is not valid for compute shader inputs\n"
Ben Clayton4fe330f2022-10-13 13:33:25 +00001162 "56:78 note: while analyzing entry point 'main'");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001163}
1164
1165TEST_F(LocationAttributeTests, Duplicate_input) {
dan sinclairb29892b2022-06-07 13:55:34 +00001166 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001167 // fn main(@location(1) param_a : f32,
1168 // @location(1) param_b : f32) {}
Ben Clayton783b1692022-08-02 17:03:35 +00001169 auto* param_a = Param("param_a", ty.f32(),
1170 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001171 Location(1_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001172 });
1173 auto* param_b = Param("param_b", ty.f32(),
1174 utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001175 Location(Source{{12, 34}}, 1_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001176 });
1177 Func(Source{{12, 34}}, "main",
1178 utils::Vector{
1179 param_a,
1180 param_b,
1181 },
1182 ty.void_(), utils::Empty,
1183 utils::Vector{
1184 Stage(ast::PipelineStage::kFragment),
1185 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001186
dan sinclair41e4d9a2022-05-01 14:40:55 +00001187 EXPECT_FALSE(r()->Resolve());
1188 EXPECT_EQ(r()->error(), "12:34 error: location(1) attribute appears multiple times");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001189}
1190
1191TEST_F(LocationAttributeTests, Duplicate_struct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001192 // struct InputA {
1193 // @location(1) a : f32;
1194 // };
1195 // struct InputB {
1196 // @location(1) a : f32;
1197 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001198 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001199 // fn main(param_a : InputA, param_b : InputB) {}
Ben Clayton783b1692022-08-02 17:03:35 +00001200 auto* input_a = Structure("InputA", utils::Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001201 Member("a", ty.f32(), utils::Vector{Location(1_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +00001202 });
dan sinclairf9eeed62022-09-07 22:25:24 +00001203 auto* input_b = Structure(
1204 "InputB", utils::Vector{
1205 Member("a", ty.f32(), utils::Vector{Location(Source{{34, 56}}, 1_a)}),
1206 });
dan sinclair41e4d9a2022-05-01 14:40:55 +00001207 auto* param_a = Param("param_a", ty.Of(input_a));
1208 auto* param_b = Param("param_b", ty.Of(input_b));
Ben Clayton783b1692022-08-02 17:03:35 +00001209 Func(Source{{12, 34}}, "main",
1210 utils::Vector{
1211 param_a,
1212 param_b,
1213 },
1214 ty.void_(), utils::Empty,
1215 utils::Vector{
1216 Stage(ast::PipelineStage::kFragment),
1217 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001218
dan sinclair41e4d9a2022-05-01 14:40:55 +00001219 EXPECT_FALSE(r()->Resolve());
1220 EXPECT_EQ(r()->error(),
1221 "34:56 error: location(1) attribute appears multiple times\n"
Ben Clayton4fe330f2022-10-13 13:33:25 +00001222 "12:34 note: while analyzing entry point 'main'");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001223}
1224
1225} // namespace
1226} // namespace LocationAttributeTests
1227
1228} // namespace
dan sinclaird2093792022-04-07 17:45:45 +00001229} // namespace tint::resolver