blob: 0a43290b1a403f97e8dd53da253f443e6fb0a8c5 [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001// Copyright 2021 The Dawn & Tint Authors
Ryan Harrisondbc13af2022-02-21 15:19:07 +00002//
Austin Engcc2516a2023-10-17 20:57:54 +00003// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
Ryan Harrisondbc13af2022-02-21 15:19:07 +00005//
Austin Engcc2516a2023-10-17 20:57:54 +00006// 1. Redistributions of source code must retain the above copyright notice, this
7// list of conditions and the following disclaimer.
Ryan Harrisondbc13af2022-02-21 15:19:07 +00008//
Austin Engcc2516a2023-10-17 20:57:54 +00009// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12//
13// 3. Neither the name of the copyright holder nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Ryan Harrisondbc13af2022-02-21 15:19:07 +000027
Ben Claytoncd52f382023-08-07 13:11:08 +000028#include "src/tint/lang/core/builtin_value.h"
dan sinclair99181d82023-07-20 01:14:15 +000029#include "src/tint/lang/wgsl/ast/builtin_attribute.h"
30#include "src/tint/lang/wgsl/ast/location_attribute.h"
31#include "src/tint/lang/wgsl/ast/return_statement.h"
32#include "src/tint/lang/wgsl/ast/stage_attribute.h"
dan sinclair9d97f222023-07-24 17:11:53 +000033#include "src/tint/lang/wgsl/resolver/resolver.h"
Ben Claytond368f2c2023-08-01 00:37:35 +000034#include "src/tint/lang/wgsl/resolver/resolver_helper_test.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000035
36#include "gmock/gmock.h"
37
dan sinclaird2093792022-04-07 17:45:45 +000038namespace tint::resolver {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000039namespace {
40
Ben Claytona87e5d62023-08-15 14:56:16 +000041using namespace tint::core::fluent_types; // NOLINT
dan sinclairce6dffe2023-08-14 21:01:40 +000042using namespace tint::core::number_suffixes; // NOLINT
Ben Clayton66805b02023-06-14 22:00:01 +000043
Ryan Harrisondbc13af2022-02-21 15:19:07 +000044// Helpers and typedefs
45template <typename T>
46using DataType = builder::DataType<T>;
47template <typename T>
Ryan Harrisondbc13af2022-02-21 15:19:07 +000048using alias = builder::alias<T>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000049
dan sinclair41e4d9a2022-05-01 14:40:55 +000050class ResolverEntryPointValidationTest : public TestHelper, public testing::Test {};
Ryan Harrisondbc13af2022-02-21 15:19:07 +000051
52TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
dan sinclairb29892b2022-06-07 13:55:34 +000053 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +000054 // fn main() -> @location(0) f32 { return 1.0; }
dan sinclairbae54e72023-07-28 15:01:54 +000055 Func(Source{{12, 34}}, "main", tint::Empty, ty.f32(),
56 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +000057 Return(1_f),
58 },
dan sinclairbae54e72023-07-28 15:01:54 +000059 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +000060 Stage(ast::PipelineStage::kFragment),
61 },
dan sinclairbae54e72023-07-28 15:01:54 +000062 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +000063 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +000064 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +000065
dan sinclair41e4d9a2022-05-01 14:40:55 +000066 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000067}
68
69TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Builtin) {
dan sinclairb29892b2022-06-07 13:55:34 +000070 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +000071 // fn main() -> @builtin(position) vec4<f32> { return vec4<f32>(); }
dan sinclairbae54e72023-07-28 15:01:54 +000072 Func(Source{{12, 34}}, "main", tint::Empty, ty.vec4<f32>(),
73 Vector{
Ben Clayton66805b02023-06-14 22:00:01 +000074 Return(Call<vec4<f32>>()),
Ben Clayton783b1692022-08-02 17:03:35 +000075 },
dan sinclairbae54e72023-07-28 15:01:54 +000076 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +000077 Stage(ast::PipelineStage::kVertex),
78 },
dan sinclairbae54e72023-07-28 15:01:54 +000079 Vector{
Ben Claytoncd52f382023-08-07 13:11:08 +000080 Builtin(core::BuiltinValue::kPosition),
Ben Clayton783b1692022-08-02 17:03:35 +000081 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +000082
dan sinclair41e4d9a2022-05-01 14:40:55 +000083 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000084}
85
86TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Missing) {
dan sinclairb29892b2022-06-07 13:55:34 +000087 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +000088 // fn main() -> f32 {
89 // return 1.0;
90 // }
dan sinclairbae54e72023-07-28 15:01:54 +000091 Func(Source{{12, 34}}, "main", tint::Empty, ty.vec4<f32>(),
92 Vector{
Ben Clayton66805b02023-06-14 22:00:01 +000093 Return(Call<vec4<f32>>()),
Ben Clayton783b1692022-08-02 17:03:35 +000094 },
dan sinclairbae54e72023-07-28 15:01:54 +000095 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +000096 Stage(ast::PipelineStage::kVertex),
97 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +000098
dan sinclair41e4d9a2022-05-01 14:40:55 +000099 EXPECT_FALSE(r()->Resolve());
Ben Clayton4d3ff972023-02-21 17:33:54 +0000100 EXPECT_EQ(r()->error(), R"(12:34 error: missing entry point IO attribute on return type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000101}
102
103TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
dan sinclairb29892b2022-06-07 13:55:34 +0000104 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +0000105 // fn main() -> @location(0) @builtin(position) vec4<f32> {
106 // return vec4<f32>();
107 // }
dan sinclairbae54e72023-07-28 15:01:54 +0000108 Func(Source{{12, 34}}, "main", tint::Empty, ty.vec4<f32>(),
109 Vector{
Ben Clayton66805b02023-06-14 22:00:01 +0000110 Return(Call<vec4<f32>>()),
Ben Clayton783b1692022-08-02 17:03:35 +0000111 },
dan sinclairbae54e72023-07-28 15:01:54 +0000112 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000113 Stage(ast::PipelineStage::kVertex),
114 },
dan sinclairbae54e72023-07-28 15:01:54 +0000115 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000116 Location(Source{{13, 43}}, 0_a),
Ben Claytoncd52f382023-08-07 13:11:08 +0000117 Builtin(Source{{14, 52}}, core::BuiltinValue::kPosition),
Ben Clayton783b1692022-08-02 17:03:35 +0000118 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000119
dan sinclair41e4d9a2022-05-01 14:40:55 +0000120 EXPECT_FALSE(r()->Resolve());
121 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ben Clayton710b62f2024-02-26 20:24:06 +000012213:43 note: previously consumed '@location')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000123}
124
125TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000126 // struct Output {
127 // @location(0) a : f32;
128 // @builtin(frag_depth) b : f32;
129 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000130 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000131 // fn main() -> Output {
132 // return Output();
133 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000134 auto* output = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000135 "Output", Vector{
136 Member("a", ty.f32(), Vector{Location(0_a)}),
Ben Claytoncd52f382023-08-07 13:11:08 +0000137 Member("b", ty.f32(), Vector{Builtin(core::BuiltinValue::kFragDepth)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000138 });
139 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
140 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000141 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000142 },
dan sinclairbae54e72023-07-28 15:01:54 +0000143 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000144 Stage(ast::PipelineStage::kFragment),
145 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000146
dan sinclair41e4d9a2022-05-01 14:40:55 +0000147 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000148}
149
dan sinclair41e4d9a2022-05-01 14:40:55 +0000150TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMultipleAttributes) {
151 // struct Output {
152 // @location(0) @builtin(frag_depth) a : f32;
153 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000154 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000155 // fn main() -> Output {
156 // return Output();
157 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000158 auto* output = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000159 "Output", Vector{
160 Member("a", ty.f32(),
161 Vector{Location(Source{{13, 43}}, 0_a),
Ben Claytoncd52f382023-08-07 13:11:08 +0000162 Builtin(Source{{14, 52}}, core::BuiltinValue::kFragDepth)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000163 });
164 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
165 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000166 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000167 },
dan sinclairbae54e72023-07-28 15:01:54 +0000168 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000169 Stage(ast::PipelineStage::kFragment),
170 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000171
dan sinclair41e4d9a2022-05-01 14:40:55 +0000172 EXPECT_FALSE(r()->Resolve());
173 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ben Clayton710b62f2024-02-26 20:24:06 +000017413:43 note: previously consumed '@location'
Ben Clayton4fe330f2022-10-13 13:33:25 +000017512:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000176}
177
dan sinclair41e4d9a2022-05-01 14:40:55 +0000178TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMissingAttribute) {
179 // struct Output {
180 // @location(0) a : f32;
181 // b : f32;
182 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000183 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000184 // fn main() -> Output {
185 // return Output();
186 // }
dan sinclairbae54e72023-07-28 15:01:54 +0000187 auto* output =
188 Structure("Output", Vector{
189 Member(Source{{13, 43}}, "a", ty.f32(), Vector{Location(0_a)}),
190 Member(Source{{14, 52}}, "b", ty.f32(), {}),
191 });
192 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
193 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000194 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000195 },
dan sinclairbae54e72023-07-28 15:01:54 +0000196 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000197 Stage(ast::PipelineStage::kFragment),
198 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000199
dan sinclair41e4d9a2022-05-01 14:40:55 +0000200 EXPECT_FALSE(r()->Resolve());
201 EXPECT_EQ(r()->error(),
202 R"(14:52 error: missing entry point IO attribute
Ben Clayton4fe330f2022-10-13 13:33:25 +000020312:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000204}
205
206TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000207 // struct Output {
208 // @builtin(frag_depth) a : f32;
209 // @builtin(frag_depth) b : f32;
210 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000211 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000212 // fn main() -> Output {
213 // return Output();
214 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000215 auto* output = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000216 "Output", Vector{
Ben Claytoncd52f382023-08-07 13:11:08 +0000217 Member("a", ty.f32(), Vector{Builtin(core::BuiltinValue::kFragDepth)}),
218 Member("b", ty.f32(), Vector{Builtin(core::BuiltinValue::kFragDepth)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000219 });
220 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
221 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000222 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000223 },
dan sinclairbae54e72023-07-28 15:01:54 +0000224 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000225 Stage(ast::PipelineStage::kFragment),
226 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000227
dan sinclair41e4d9a2022-05-01 14:40:55 +0000228 EXPECT_FALSE(r()->Resolve());
Ben Clayton4d3ff972023-02-21 17:33:54 +0000229 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000230 R"(12:34 error: '@builtin(frag_depth)' appears multiple times as pipeline output
Ben Clayton4fe330f2022-10-13 13:33:25 +000023112:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000232}
233
234TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Location) {
dan sinclairb29892b2022-06-07 13:55:34 +0000235 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000236 // fn main(@location(0) param : f32) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000237 auto* param = Param("param", ty.f32(),
dan sinclairbae54e72023-07-28 15:01:54 +0000238 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000239 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000240 });
241 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000242 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000243 param,
244 },
dan sinclairbae54e72023-07-28 15:01:54 +0000245 ty.void_(), tint::Empty,
246 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000247 Stage(ast::PipelineStage::kFragment),
248 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000249
dan sinclair41e4d9a2022-05-01 14:40:55 +0000250 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000251}
252
253TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
dan sinclairb29892b2022-06-07 13:55:34 +0000254 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000255 // fn main(param : f32) {}
256 auto* param = Param(Source{{13, 43}}, "param", ty.vec4<f32>());
Ben Clayton783b1692022-08-02 17:03:35 +0000257 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000258 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000259 param,
260 },
dan sinclairbae54e72023-07-28 15:01:54 +0000261 ty.void_(), tint::Empty,
262 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000263 Stage(ast::PipelineStage::kFragment),
264 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000265
dan sinclair41e4d9a2022-05-01 14:40:55 +0000266 EXPECT_FALSE(r()->Resolve());
Ben Clayton4d3ff972023-02-21 17:33:54 +0000267 EXPECT_EQ(r()->error(), R"(13:43 error: missing entry point IO attribute on parameter)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000268}
269
270TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
dan sinclairb29892b2022-06-07 13:55:34 +0000271 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000272 // fn main(@location(0) @builtin(sample_index) param : u32) {}
Ben Claytonf3302292022-07-27 18:48:06 +0000273 auto* param = Param("param", ty.u32(),
dan sinclairbae54e72023-07-28 15:01:54 +0000274 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000275 Location(Source{{13, 43}}, 0_a),
Ben Claytoncd52f382023-08-07 13:11:08 +0000276 Builtin(Source{{14, 52}}, core::BuiltinValue::kSampleIndex),
Ben Clayton783b1692022-08-02 17:03:35 +0000277 });
278 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000279 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000280 param,
281 },
dan sinclairbae54e72023-07-28 15:01:54 +0000282 ty.void_(), tint::Empty,
283 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000284 Stage(ast::PipelineStage::kFragment),
285 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000286
dan sinclair41e4d9a2022-05-01 14:40:55 +0000287 EXPECT_FALSE(r()->Resolve());
288 EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
Ben Clayton710b62f2024-02-26 20:24:06 +000028913:43 note: previously consumed '@location')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000290}
291
292TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000293 // struct Input {
294 // @location(0) a : f32;
295 // @builtin(sample_index) b : u32;
296 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000297 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000298 // fn main(param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000299 auto* input = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000300 "Input", Vector{
301 Member("a", ty.f32(), Vector{Location(0_a)}),
Ben Claytoncd52f382023-08-07 13:11:08 +0000302 Member("b", ty.u32(), Vector{Builtin(core::BuiltinValue::kSampleIndex)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000303 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000304 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000305 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000306 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000307 param,
308 },
dan sinclairbae54e72023-07-28 15:01:54 +0000309 ty.void_(), tint::Empty,
310 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000311 Stage(ast::PipelineStage::kFragment),
312 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000313
dan sinclair41e4d9a2022-05-01 14:40:55 +0000314 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000315}
316
dan sinclair41e4d9a2022-05-01 14:40:55 +0000317TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMultipleAttributes) {
318 // struct Input {
319 // @location(0) @builtin(sample_index) a : u32;
320 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000321 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000322 // fn main(param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000323 auto* input = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000324 "Input", Vector{
325 Member("a", ty.u32(),
326 Vector{Location(Source{{13, 43}}, 0_a),
Ben Claytoncd52f382023-08-07 13:11:08 +0000327 Builtin(Source{{14, 52}}, core::BuiltinValue::kSampleIndex)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000328 });
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",
dan sinclairbae54e72023-07-28 15:01:54 +0000331 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000332 param,
333 },
dan sinclairbae54e72023-07-28 15:01:54 +0000334 ty.void_(), tint::Empty,
335 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000336 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
Ben Clayton710b62f2024-02-26 20:24:06 +000034113:43 note: previously consumed '@location'
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 sinclairbae54e72023-07-28 15:01:54 +0000352 auto* input =
353 Structure("Input", Vector{
354 Member(Source{{13, 43}}, "a", ty.f32(), 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",
dan sinclairbae54e72023-07-28 15:01:54 +0000359 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000360 param,
361 },
dan sinclairbae54e72023-07-28 15:01:54 +0000362 ty.void_(), tint::Empty,
363 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000364 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(),
dan sinclairbae54e72023-07-28 15:01:54 +0000377 Vector{
Ben Claytoncd52f382023-08-07 13:11:08 +0000378 Builtin(core::BuiltinValue::kSampleIndex),
Ben Clayton783b1692022-08-02 17:03:35 +0000379 });
380 auto* param_b = Param("param_b", ty.u32(),
dan sinclairbae54e72023-07-28 15:01:54 +0000381 Vector{
Ben Claytoncd52f382023-08-07 13:11:08 +0000382 Builtin(core::BuiltinValue::kSampleIndex),
Ben Clayton783b1692022-08-02 17:03:35 +0000383 });
384 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000385 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000386 param_a,
387 param_b,
388 },
dan sinclairbae54e72023-07-28 15:01:54 +0000389 ty.void_(), tint::Empty,
390 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000391 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(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000396 "12:34 error: '@builtin(sample_index)' appears multiple times as pipeline input");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000397}
398
399TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000400 // struct InputA {
401 // @builtin(sample_index) a : u32;
402 // };
403 // struct InputB {
404 // @builtin(sample_index) a : u32;
405 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000406 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000407 // fn main(param_a : InputA, param_b : InputB) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000408 auto* input_a = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000409 "InputA", Vector{
Ben Claytoncd52f382023-08-07 13:11:08 +0000410 Member("a", ty.u32(), Vector{Builtin(core::BuiltinValue::kSampleIndex)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000411 });
Ben Clayton783b1692022-08-02 17:03:35 +0000412 auto* input_b = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000413 "InputB", Vector{
Ben Claytoncd52f382023-08-07 13:11:08 +0000414 Member("a", ty.u32(), Vector{Builtin(core::BuiltinValue::kSampleIndex)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000415 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000416 auto* param_a = Param("param_a", ty.Of(input_a));
417 auto* param_b = Param("param_b", ty.Of(input_b));
Ben Clayton783b1692022-08-02 17:03:35 +0000418 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000419 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000420 param_a,
421 param_b,
422 },
dan sinclairbae54e72023-07-28 15:01:54 +0000423 ty.void_(), tint::Empty,
424 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000425 Stage(ast::PipelineStage::kFragment),
426 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000427
dan sinclair41e4d9a2022-05-01 14:40:55 +0000428 EXPECT_FALSE(r()->Resolve());
Ben Clayton4d3ff972023-02-21 17:33:54 +0000429 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000430 R"(12:34 error: '@builtin(sample_index)' appears multiple times as pipeline input
Ben Clayton4fe330f2022-10-13 13:33:25 +000043112:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000432}
433
434TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
dan sinclairb29892b2022-06-07 13:55:34 +0000435 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +0000436 // fn main() {}
dan sinclairbae54e72023-07-28 15:01:54 +0000437 Func(Source{{12, 34}}, "main", tint::Empty, ty.void_(), tint::Empty,
438 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000439 Stage(ast::PipelineStage::kVertex),
440 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000441
dan sinclair41e4d9a2022-05-01 14:40:55 +0000442 EXPECT_FALSE(r()->Resolve());
443 EXPECT_EQ(r()->error(),
444 "12:34 error: a vertex shader must include the 'position' builtin "
445 "in its return type");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000446}
447
dan sinclair4abf28e2022-08-02 15:55:35 +0000448TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithEnable) {
449 // enable chromium_experimental_push_constant;
450 // var<push_constant> a : u32;
Ben Clayton11653892023-09-19 19:15:59 +0000451 Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
Ben Claytoncd52f382023-08-07 13:11:08 +0000452 GlobalVar("a", ty.u32(), core::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000453
454 EXPECT_TRUE(r()->Resolve());
455}
456
457TEST_F(ResolverEntryPointValidationTest, PushConstantDisallowedWithoutEnable) {
458 // var<push_constant> a : u32;
Ben Claytoncd52f382023-08-07 13:11:08 +0000459 GlobalVar(Source{{1, 2}}, "a", ty.u32(), core::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000460
461 EXPECT_FALSE(r()->Resolve());
462 EXPECT_EQ(r()->error(),
dan sinclairff7cf212022-10-03 14:05:23 +0000463 "1:2 error: use of variable address space 'push_constant' requires enabling "
dan sinclair4abf28e2022-08-02 15:55:35 +0000464 "extension 'chromium_experimental_push_constant'");
465}
466
dan sinclairff7cf212022-10-03 14:05:23 +0000467TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithIgnoreAddressSpaceAttribute) {
468 // var<push_constant> a : u32; // With ast::DisabledValidation::kIgnoreAddressSpace
Ben Claytoncd52f382023-08-07 13:11:08 +0000469 GlobalVar("a", ty.u32(), core::AddressSpace::kPushConstant,
dan sinclairbae54e72023-07-28 15:01:54 +0000470 Vector{Disable(ast::DisabledValidation::kIgnoreAddressSpace)});
dan sinclair4abf28e2022-08-02 15:55:35 +0000471
472 EXPECT_TRUE(r()->Resolve());
473}
474
475TEST_F(ResolverEntryPointValidationTest, PushConstantOneVariableUsedInEntryPoint) {
476 // enable chromium_experimental_push_constant;
477 // var<push_constant> a : u32;
478 // @compute @workgroup_size(1) fn main() {
479 // _ = a;
480 // }
Ben Clayton11653892023-09-19 19:15:59 +0000481 Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
Ben Claytoncd52f382023-08-07 13:11:08 +0000482 GlobalVar("a", ty.u32(), core::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000483
dan sinclairbae54e72023-07-28 15:01:54 +0000484 Func("main", {}, ty.void_(), Vector{Assign(Phony(), "a")},
Ben Clayton4e800c42023-09-11 16:50:59 +0000485 Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_a)});
dan sinclair4abf28e2022-08-02 15:55:35 +0000486
487 EXPECT_TRUE(r()->Resolve());
488}
489
490TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInEntryPoint) {
491 // enable chromium_experimental_push_constant;
492 // var<push_constant> a : u32;
493 // var<push_constant> b : u32;
494 // @compute @workgroup_size(1) fn main() {
495 // _ = a;
496 // _ = b;
497 // }
Ben Clayton11653892023-09-19 19:15:59 +0000498 Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
Ben Claytoncd52f382023-08-07 13:11:08 +0000499 GlobalVar(Source{{1, 2}}, "a", ty.u32(), core::AddressSpace::kPushConstant);
500 GlobalVar(Source{{3, 4}}, "b", ty.u32(), core::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000501
dan sinclairbae54e72023-07-28 15:01:54 +0000502 Func(Source{{5, 6}}, "main", {}, ty.void_(), Vector{Assign(Phony(), "a"), Assign(Phony(), "b")},
Ben Clayton4e800c42023-09-11 16:50:59 +0000503 Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_a)});
dan sinclair4abf28e2022-08-02 15:55:35 +0000504
505 EXPECT_FALSE(r()->Resolve());
506 EXPECT_EQ(r()->error(),
507 R"(5:6 error: entry point 'main' uses two different 'push_constant' variables.
5083:4 note: first 'push_constant' variable declaration is here
5091:2 note: second 'push_constant' variable declaration is here)");
510}
511
512TEST_F(ResolverEntryPointValidationTest,
513 PushConstantTwoVariablesUsedInEntryPointWithFunctionGraph) {
514 // enable chromium_experimental_push_constant;
515 // var<push_constant> a : u32;
516 // var<push_constant> b : u32;
517 // fn uses_a() {
518 // _ = a;
519 // }
520 // fn uses_b() {
521 // _ = b;
522 // }
523 // @compute @workgroup_size(1) fn main() {
524 // uses_a();
525 // uses_b();
526 // }
Ben Clayton11653892023-09-19 19:15:59 +0000527 Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
Ben Claytoncd52f382023-08-07 13:11:08 +0000528 GlobalVar(Source{{1, 2}}, "a", ty.u32(), core::AddressSpace::kPushConstant);
529 GlobalVar(Source{{3, 4}}, "b", ty.u32(), core::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000530
dan sinclairbae54e72023-07-28 15:01:54 +0000531 Func(Source{{5, 6}}, "uses_a", {}, ty.void_(), Vector{Assign(Phony(), "a")});
532 Func(Source{{7, 8}}, "uses_b", {}, ty.void_(), Vector{Assign(Phony(), "b")});
dan sinclair4abf28e2022-08-02 15:55:35 +0000533
534 Func(Source{{9, 10}}, "main", {}, ty.void_(),
dan sinclairbae54e72023-07-28 15:01:54 +0000535 Vector{CallStmt(Call("uses_a")), CallStmt(Call("uses_b"))},
Ben Clayton4e800c42023-09-11 16:50:59 +0000536 Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_a)});
dan sinclair4abf28e2022-08-02 15:55:35 +0000537
538 EXPECT_FALSE(r()->Resolve());
539 EXPECT_EQ(r()->error(),
540 R"(9:10 error: entry point 'main' uses two different 'push_constant' variables.
5413:4 note: first 'push_constant' variable declaration is here
5427:8 note: called by function 'uses_b'
5439:10 note: called by entry point 'main'
5441:2 note: second 'push_constant' variable declaration is here
5455:6 note: called by function 'uses_a'
5469:10 note: called by entry point 'main')");
547}
548
549TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInDifferentEntryPoint) {
550 // enable chromium_experimental_push_constant;
551 // var<push_constant> a : u32;
552 // var<push_constant> b : u32;
553 // @compute @workgroup_size(1) fn uses_a() {
554 // _ = a;
555 // }
556 // @compute @workgroup_size(1) fn uses_b() {
557 // _ = a;
558 // }
Ben Clayton11653892023-09-19 19:15:59 +0000559 Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
Ben Claytoncd52f382023-08-07 13:11:08 +0000560 GlobalVar("a", ty.u32(), core::AddressSpace::kPushConstant);
561 GlobalVar("b", ty.u32(), core::AddressSpace::kPushConstant);
dan sinclair4abf28e2022-08-02 15:55:35 +0000562
dan sinclairbae54e72023-07-28 15:01:54 +0000563 Func("uses_a", {}, ty.void_(), Vector{Assign(Phony(), "a")},
Ben Clayton4e800c42023-09-11 16:50:59 +0000564 Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_a)});
dan sinclairbae54e72023-07-28 15:01:54 +0000565 Func("uses_b", {}, ty.void_(), Vector{Assign(Phony(), "b")},
Ben Clayton4e800c42023-09-11 16:50:59 +0000566 Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_a)});
dan sinclair4abf28e2022-08-02 15:55:35 +0000567
568 EXPECT_TRUE(r()->Resolve());
569}
570
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000571namespace TypeValidationTests {
572struct Params {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000573 builder::ast_type_func_ptr create_ast_type;
574 bool is_valid;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000575};
576
577template <typename T>
578constexpr Params ParamsFor(bool is_valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000579 return Params{DataType<T>::AST, is_valid};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000580}
581
582using TypeValidationTest = resolver::ResolverTestWithParam<Params>;
583
584static constexpr Params cases[] = {
585 ParamsFor<f32>(true), //
586 ParamsFor<i32>(true), //
587 ParamsFor<u32>(true), //
588 ParamsFor<bool>(false), //
589 ParamsFor<vec2<f32>>(true), //
590 ParamsFor<vec3<f32>>(true), //
591 ParamsFor<vec4<f32>>(true), //
592 ParamsFor<mat2x2<f32>>(false), //
593 ParamsFor<mat3x3<f32>>(false), //
594 ParamsFor<mat4x4<f32>>(false), //
595 ParamsFor<alias<f32>>(true), //
596 ParamsFor<alias<i32>>(true), //
597 ParamsFor<alias<u32>>(true), //
598 ParamsFor<alias<bool>>(false), //
Zhaoming Jiang6198bea2022-12-07 04:33:24 +0000599 ParamsFor<f16>(true), //
600 ParamsFor<vec2<f16>>(true), //
601 ParamsFor<vec3<f16>>(true), //
602 ParamsFor<vec4<f16>>(true), //
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000603 ParamsFor<mat2x2<f16>>(false), //
604 ParamsFor<mat3x3<f16>>(false), //
605 ParamsFor<mat4x4<f16>>(false), //
Zhaoming Jiang6198bea2022-12-07 04:33:24 +0000606 ParamsFor<alias<f16>>(true), //
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000607};
608
609TEST_P(TypeValidationTest, BareInputs) {
dan sinclairb29892b2022-06-07 13:55:34 +0000610 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000611 // fn main(@location(0) @interpolate(flat) a : *) {}
612 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000613
Ben Clayton11653892023-09-19 19:15:59 +0000614 Enable(wgsl::Extension::kF16);
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000615
Ben Clayton783b1692022-08-02 17:03:35 +0000616 auto* a = Param("a", params.create_ast_type(*this),
dan sinclairbae54e72023-07-28 15:01:54 +0000617 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000618 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000619 Flat(),
620 });
621 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000622 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000623 a,
624 },
dan sinclairbae54e72023-07-28 15:01:54 +0000625 ty.void_(), tint::Empty,
626 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000627 Stage(ast::PipelineStage::kFragment),
628 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000629
dan sinclair41e4d9a2022-05-01 14:40:55 +0000630 if (params.is_valid) {
631 EXPECT_TRUE(r()->Resolve()) << r()->error();
632 } else {
633 EXPECT_FALSE(r()->Resolve());
634 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000635}
636
637TEST_P(TypeValidationTest, StructInputs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000638 // struct Input {
639 // @location(0) @interpolate(flat) a : *;
640 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000641 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000642 // fn main(a : Input) {}
643 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000644
Ben Clayton11653892023-09-19 19:15:59 +0000645 Enable(wgsl::Extension::kF16);
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000646
dan sinclairbae54e72023-07-28 15:01:54 +0000647 auto* input = Structure(
648 "Input", Vector{
649 Member("a", params.create_ast_type(*this), Vector{Location(0_a), Flat()}),
650 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000651 auto* a = Param("a", ty.Of(input), {});
Ben Clayton783b1692022-08-02 17:03:35 +0000652 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000653 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000654 a,
655 },
dan sinclairbae54e72023-07-28 15:01:54 +0000656 ty.void_(), tint::Empty,
657 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000658 Stage(ast::PipelineStage::kFragment),
659 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000660
dan sinclair41e4d9a2022-05-01 14:40:55 +0000661 if (params.is_valid) {
662 EXPECT_TRUE(r()->Resolve()) << r()->error();
663 } else {
664 EXPECT_FALSE(r()->Resolve());
665 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000666}
667
668TEST_P(TypeValidationTest, BareOutputs) {
dan sinclairb29892b2022-06-07 13:55:34 +0000669 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000670 // fn main() -> @location(0) * {
671 // return *();
672 // }
673 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000674
Ben Clayton11653892023-09-19 19:15:59 +0000675 Enable(wgsl::Extension::kF16);
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000676
dan sinclairbae54e72023-07-28 15:01:54 +0000677 Func(Source{{12, 34}}, "main", tint::Empty, params.create_ast_type(*this),
678 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000679 Return(Call(params.create_ast_type(*this))),
Ben Clayton783b1692022-08-02 17:03:35 +0000680 },
dan sinclairbae54e72023-07-28 15:01:54 +0000681 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000682 Stage(ast::PipelineStage::kFragment),
683 },
dan sinclairbae54e72023-07-28 15:01:54 +0000684 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000685 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000686 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000687
dan sinclair41e4d9a2022-05-01 14:40:55 +0000688 if (params.is_valid) {
689 EXPECT_TRUE(r()->Resolve()) << r()->error();
690 } else {
691 EXPECT_FALSE(r()->Resolve());
692 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000693}
694
695TEST_P(TypeValidationTest, StructOutputs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000696 // struct Output {
697 // @location(0) a : *;
698 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000699 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000700 // fn main() -> Output {
701 // return Output();
702 // }
703 auto params = GetParam();
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000704
Ben Clayton11653892023-09-19 19:15:59 +0000705 Enable(wgsl::Extension::kF16);
Zhaoming Jiang9c711742022-07-08 19:35:05 +0000706
dan sinclairbae54e72023-07-28 15:01:54 +0000707 auto* output =
708 Structure("Output", Vector{
709 Member("a", params.create_ast_type(*this), Vector{Location(0_a)}),
710 });
711 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
712 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000713 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000714 },
dan sinclairbae54e72023-07-28 15:01:54 +0000715 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000716 Stage(ast::PipelineStage::kFragment),
717 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000718
dan sinclair41e4d9a2022-05-01 14:40:55 +0000719 if (params.is_valid) {
720 EXPECT_TRUE(r()->Resolve()) << r()->error();
721 } else {
722 EXPECT_FALSE(r()->Resolve());
723 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000724}
725INSTANTIATE_TEST_SUITE_P(ResolverEntryPointValidationTest,
726 TypeValidationTest,
727 testing::ValuesIn(cases));
728
729} // namespace TypeValidationTests
730
731namespace LocationAttributeTests {
732namespace {
733using LocationAttributeTests = ResolverTest;
734
735TEST_F(LocationAttributeTests, Pass) {
dan sinclairb29892b2022-06-07 13:55:34 +0000736 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000737 // fn frag_main(@location(0) @interpolate(flat) a: i32) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000738
Ben Clayton783b1692022-08-02 17:03:35 +0000739 auto* p = Param(Source{{12, 34}}, "a", ty.i32(),
dan sinclairbae54e72023-07-28 15:01:54 +0000740 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000741 Location(0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000742 Flat(),
743 });
744 Func("frag_main",
dan sinclairbae54e72023-07-28 15:01:54 +0000745 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000746 p,
747 },
dan sinclairbae54e72023-07-28 15:01:54 +0000748 ty.void_(), tint::Empty,
749 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000750 Stage(ast::PipelineStage::kFragment),
751 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000752
dan sinclair41e4d9a2022-05-01 14:40:55 +0000753 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000754}
755
756TEST_F(LocationAttributeTests, BadType_Input_bool) {
dan sinclairb29892b2022-06-07 13:55:34 +0000757 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000758 // fn frag_main(@location(0) a: bool) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000759
Ben Clayton783b1692022-08-02 17:03:35 +0000760 auto* p = Param(Source{{12, 34}}, "a", ty.bool_(),
dan sinclairbae54e72023-07-28 15:01:54 +0000761 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000762 Location(Source{{34, 56}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000763 });
764 Func("frag_main",
dan sinclairbae54e72023-07-28 15:01:54 +0000765 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000766 p,
767 },
dan sinclairbae54e72023-07-28 15:01:54 +0000768 ty.void_(), tint::Empty,
769 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000770 Stage(ast::PipelineStage::kFragment),
771 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000772
dan sinclair41e4d9a2022-05-01 14:40:55 +0000773 EXPECT_FALSE(r()->Resolve());
774 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000775 R"(12:34 error: cannot apply '@location' to declaration of type 'bool'
77634:56 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000777}
778
779TEST_F(LocationAttributeTests, BadType_Output_Array) {
dan sinclairb29892b2022-06-07 13:55:34 +0000780 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000781 // fn frag_main()->@location(0) array<f32, 2> { return array<f32, 2>(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000782
dan sinclairbae54e72023-07-28 15:01:54 +0000783 Func(Source{{12, 34}}, "frag_main", tint::Empty, ty.array<f32, 2>(),
784 Vector{
Ben Clayton66805b02023-06-14 22:00:01 +0000785 Return(Call<array<f32, 2>>()),
Ben Clayton783b1692022-08-02 17:03:35 +0000786 },
dan sinclairbae54e72023-07-28 15:01:54 +0000787 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000788 Stage(ast::PipelineStage::kFragment),
789 },
dan sinclairbae54e72023-07-28 15:01:54 +0000790 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000791 Location(Source{{34, 56}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000792 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000793
dan sinclair41e4d9a2022-05-01 14:40:55 +0000794 EXPECT_FALSE(r()->Resolve());
795 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000796 R"(12:34 error: cannot apply '@location' to declaration of type 'array<f32, 2>'
79734:56 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000798}
799
800TEST_F(LocationAttributeTests, BadType_Input_Struct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000801 // struct Input {
802 // a : f32;
803 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000804 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000805 // fn main(@location(0) param : Input) {}
dan sinclairbae54e72023-07-28 15:01:54 +0000806 auto* input = Structure("Input", Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000807 Member("a", ty.f32()),
808 });
809 auto* param = Param(Source{{12, 34}}, "param", ty.Of(input),
dan sinclairbae54e72023-07-28 15:01:54 +0000810 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000811 Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000812 });
813 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000814 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000815 param,
816 },
dan sinclairbae54e72023-07-28 15:01:54 +0000817 ty.void_(), tint::Empty,
818 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000819 Stage(ast::PipelineStage::kFragment),
820 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000821
dan sinclair41e4d9a2022-05-01 14:40:55 +0000822 EXPECT_FALSE(r()->Resolve());
823 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000824 R"(12:34 error: cannot apply '@location' to declaration of type 'Input'
82513:43 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000826}
827
828TEST_F(LocationAttributeTests, BadType_Input_Struct_NestedStruct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000829 // struct Inner {
830 // @location(0) b : f32;
831 // };
832 // struct Input {
833 // a : Inner;
834 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000835 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000836 // fn main(param : Input) {}
dan sinclairbae54e72023-07-28 15:01:54 +0000837 auto* inner =
838 Structure("Inner", Vector{
839 Member(Source{{13, 43}}, "a", ty.f32(), Vector{Location(0_a)}),
840 });
841 auto* input = Structure("Input", Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000842 Member(Source{{14, 52}}, "a", ty.Of(inner)),
843 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000844 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000845 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000846 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000847 param,
848 },
dan sinclairbae54e72023-07-28 15:01:54 +0000849 ty.void_(), tint::Empty,
850 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000851 Stage(ast::PipelineStage::kFragment),
852 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000853
dan sinclair41e4d9a2022-05-01 14:40:55 +0000854 EXPECT_FALSE(r()->Resolve());
855 EXPECT_EQ(r()->error(),
Ben Clayton4d3ff972023-02-21 17:33:54 +0000856 R"(14:52 error: nested structures cannot be used for entry point IO
85712:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000858}
859
860TEST_F(LocationAttributeTests, BadType_Input_Struct_RuntimeArray) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000861 // struct Input {
862 // @location(0) a : array<f32>;
863 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000864 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000865 // fn main(param : Input) {}
Ben Clayton783b1692022-08-02 17:03:35 +0000866 auto* input = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000867 "Input", Vector{
868 Member(Source{{13, 43}}, "a", ty.array<f32>(), Vector{Location(0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +0000869 });
dan sinclair41e4d9a2022-05-01 14:40:55 +0000870 auto* param = Param("param", ty.Of(input));
Ben Clayton783b1692022-08-02 17:03:35 +0000871 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +0000872 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000873 param,
874 },
dan sinclairbae54e72023-07-28 15:01:54 +0000875 ty.void_(), tint::Empty,
876 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000877 Stage(ast::PipelineStage::kFragment),
878 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000879
dan sinclair41e4d9a2022-05-01 14:40:55 +0000880 EXPECT_FALSE(r()->Resolve());
881 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000882 R"(13:43 error: cannot apply '@location' to declaration of type 'array<f32>'
883note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000884}
885
886TEST_F(LocationAttributeTests, BadMemberType_Input) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000887 // struct S { @location(0) m: array<i32>; };
dan sinclairb29892b2022-06-07 13:55:34 +0000888 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000889 // fn frag_main( a: S) {}
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000890
dan sinclair41e4d9a2022-05-01 14:40:55 +0000891 auto* m = Member(Source{{34, 56}}, "m", ty.array<i32>(),
dan sinclairbae54e72023-07-28 15:01:54 +0000892 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000893 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +0000894 });
dan sinclairbae54e72023-07-28 15:01:54 +0000895 auto* s = Structure("S", Vector{m});
dan sinclair41e4d9a2022-05-01 14:40:55 +0000896 auto* p = Param("a", ty.Of(s));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000897
Ben Clayton783b1692022-08-02 17:03:35 +0000898 Func("frag_main",
dan sinclairbae54e72023-07-28 15:01:54 +0000899 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000900 p,
901 },
dan sinclairbae54e72023-07-28 15:01:54 +0000902 ty.void_(), tint::Empty,
903 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000904 Stage(ast::PipelineStage::kFragment),
905 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000906
dan sinclair41e4d9a2022-05-01 14:40:55 +0000907 EXPECT_FALSE(r()->Resolve());
908 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000909 R"(34:56 error: cannot apply '@location' to declaration of type 'array<i32>'
91012:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000911}
912
913TEST_F(LocationAttributeTests, BadMemberType_Output) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000914 // struct S { @location(0) m: atomic<i32>; };
dan sinclairb29892b2022-06-07 13:55:34 +0000915 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000916 // fn frag_main() -> S {}
917 auto* m = Member(Source{{34, 56}}, "m", ty.atomic<i32>(),
dan sinclairbae54e72023-07-28 15:01:54 +0000918 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000919 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +0000920 });
dan sinclairbae54e72023-07-28 15:01:54 +0000921 auto* s = Structure("S", Vector{m});
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000922
dan sinclairbae54e72023-07-28 15:01:54 +0000923 Func("frag_main", tint::Empty, ty.Of(s),
924 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000925 Return(Call(ty.Of(s))),
Ben Clayton783b1692022-08-02 17:03:35 +0000926 },
dan sinclairbae54e72023-07-28 15:01:54 +0000927 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000928 Stage(ast::PipelineStage::kFragment),
929 },
930 {});
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000931
dan sinclair41e4d9a2022-05-01 14:40:55 +0000932 EXPECT_FALSE(r()->Resolve());
933 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000934 R"(34:56 error: cannot apply '@location' to declaration of type 'atomic<i32>'
93512:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000936}
937
938TEST_F(LocationAttributeTests, BadMemberType_Unused) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000939 // struct S { @location(0) m: mat3x2<f32>; };
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000940
dan sinclair41e4d9a2022-05-01 14:40:55 +0000941 auto* m = Member(Source{{34, 56}}, "m", ty.mat3x2<f32>(),
dan sinclairbae54e72023-07-28 15:01:54 +0000942 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000943 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +0000944 });
dan sinclairbae54e72023-07-28 15:01:54 +0000945 Structure("S", Vector{m});
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000946
dan sinclair41e4d9a2022-05-01 14:40:55 +0000947 EXPECT_FALSE(r()->Resolve());
948 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +0000949 R"(34:56 error: cannot apply '@location' to declaration of type 'mat3x2<f32>'
95012:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000951}
952
953TEST_F(LocationAttributeTests, ReturnType_Struct_Valid) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000954 // struct Output {
955 // @location(0) a : f32;
956 // @builtin(frag_depth) b : f32;
957 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000958 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +0000959 // fn main() -> Output {
960 // return Output();
961 // }
Ben Clayton783b1692022-08-02 17:03:35 +0000962 auto* output = Structure(
dan sinclairbae54e72023-07-28 15:01:54 +0000963 "Output", Vector{
964 Member("a", ty.f32(), Vector{Location(0_a)}),
Ben Claytoncd52f382023-08-07 13:11:08 +0000965 Member("b", ty.f32(), Vector{Builtin(core::BuiltinValue::kFragDepth)}),
dan sinclairbae54e72023-07-28 15:01:54 +0000966 });
967 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
968 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000969 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000970 },
dan sinclairbae54e72023-07-28 15:01:54 +0000971 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000972 Stage(ast::PipelineStage::kFragment),
973 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000974
dan sinclair41e4d9a2022-05-01 14:40:55 +0000975 EXPECT_TRUE(r()->Resolve()) << r()->error();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000976}
977
978TEST_F(LocationAttributeTests, ReturnType_Struct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000979 // struct Output {
980 // a : f32;
981 // };
dan sinclairb29892b2022-06-07 13:55:34 +0000982 // @vertex
dan sinclair41e4d9a2022-05-01 14:40:55 +0000983 // fn main() -> @location(0) Output {
984 // return Output();
985 // }
dan sinclairbae54e72023-07-28 15:01:54 +0000986 auto* output = Structure("Output", Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000987 Member("a", ty.f32()),
988 });
dan sinclairbae54e72023-07-28 15:01:54 +0000989 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
990 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +0000991 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +0000992 },
dan sinclairbae54e72023-07-28 15:01:54 +0000993 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +0000994 Stage(ast::PipelineStage::kVertex),
995 },
dan sinclairbae54e72023-07-28 15:01:54 +0000996 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +0000997 Location(Source{{13, 43}}, 0_a),
Ben Clayton783b1692022-08-02 17:03:35 +0000998 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000999
dan sinclair41e4d9a2022-05-01 14:40:55 +00001000 EXPECT_FALSE(r()->Resolve());
Ben Clayton710b62f2024-02-26 20:24:06 +00001001 EXPECT_EQ(r()->error(), R"(12:34 error: cannot apply '@location' to declaration of type 'Output'
100213:43 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001003}
1004
1005TEST_F(LocationAttributeTests, ReturnType_Struct_NestedStruct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001006 // struct Inner {
1007 // @location(0) b : f32;
1008 // };
1009 // struct Output {
1010 // a : Inner;
1011 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001012 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001013 // fn main() -> Output { return Output(); }
dan sinclairbae54e72023-07-28 15:01:54 +00001014 auto* inner =
1015 Structure("Inner", Vector{
1016 Member(Source{{13, 43}}, "a", ty.f32(), Vector{Location(0_a)}),
1017 });
1018 auto* output = Structure("Output", Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001019 Member(Source{{14, 52}}, "a", ty.Of(inner)),
1020 });
dan sinclairbae54e72023-07-28 15:01:54 +00001021 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
1022 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +00001023 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +00001024 },
dan sinclairbae54e72023-07-28 15:01:54 +00001025 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001026 Stage(ast::PipelineStage::kFragment),
1027 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001028
dan sinclair41e4d9a2022-05-01 14:40:55 +00001029 EXPECT_FALSE(r()->Resolve());
1030 EXPECT_EQ(r()->error(),
Ben Clayton4d3ff972023-02-21 17:33:54 +00001031 R"(14:52 error: nested structures cannot be used for entry point IO
103212:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001033}
1034
1035TEST_F(LocationAttributeTests, ReturnType_Struct_RuntimeArray) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001036 // struct Output {
1037 // @location(0) a : array<f32>;
1038 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001039 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001040 // fn main() -> Output {
1041 // return Output();
1042 // }
dan sinclairbae54e72023-07-28 15:01:54 +00001043 auto* output = Structure("Output", Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001044 Member(Source{{13, 43}}, "a", ty.array<f32>(),
dan sinclairbae54e72023-07-28 15:01:54 +00001045 Vector{Location(Source{{12, 34}}, 0_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +00001046 });
dan sinclairbae54e72023-07-28 15:01:54 +00001047 Func(Source{{12, 34}}, "main", tint::Empty, ty.Of(output),
1048 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +00001049 Return(Call(ty.Of(output))),
Ben Clayton783b1692022-08-02 17:03:35 +00001050 },
dan sinclairbae54e72023-07-28 15:01:54 +00001051 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001052 Stage(ast::PipelineStage::kFragment),
1053 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001054
dan sinclair41e4d9a2022-05-01 14:40:55 +00001055 EXPECT_FALSE(r()->Resolve());
1056 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +00001057 R"(13:43 error: cannot apply '@location' to declaration of type 'array<f32>'
105812:34 note: '@location' must only be applied to declarations of numeric scalar or numeric vector type)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001059}
1060
1061TEST_F(LocationAttributeTests, ComputeShaderLocation_Input) {
dan sinclairbae54e72023-07-28 15:01:54 +00001062 Func("main", tint::Empty, ty.i32(),
1063 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001064 Return(Expr(1_i)),
1065 },
dan sinclairbae54e72023-07-28 15:01:54 +00001066 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001067 Stage(ast::PipelineStage::kCompute),
1068 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1069 },
dan sinclairbae54e72023-07-28 15:01:54 +00001070 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001071 Location(Source{{12, 34}}, 1_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001072 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001073
dan sinclair41e4d9a2022-05-01 14:40:55 +00001074 EXPECT_FALSE(r()->Resolve());
Ben Clayton710b62f2024-02-26 20:24:06 +00001075 EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001076}
1077
1078TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
Ben Clayton783b1692022-08-02 17:03:35 +00001079 auto* input = Param("input", ty.i32(),
dan sinclairbae54e72023-07-28 15:01:54 +00001080 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001081 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +00001082 });
dan sinclairbae54e72023-07-28 15:01:54 +00001083 Func("main", Vector{input}, ty.void_(), tint::Empty,
1084 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001085 Stage(ast::PipelineStage::kCompute),
1086 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1087 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001088
dan sinclair41e4d9a2022-05-01 14:40:55 +00001089 EXPECT_FALSE(r()->Resolve());
Ben Clayton710b62f2024-02-26 20:24:06 +00001090 EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001091}
1092
1093TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
Ben Clayton783b1692022-08-02 17:03:35 +00001094 auto* m = Member("m", ty.i32(),
dan sinclairbae54e72023-07-28 15:01:54 +00001095 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001096 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +00001097 });
dan sinclairbae54e72023-07-28 15:01:54 +00001098 auto* s = Structure("S", Vector{m});
1099 Func(Source{{56, 78}}, "main", tint::Empty, ty.Of(s),
1100 Vector{
Ben Clayton01ac21c2023-02-07 16:14:25 +00001101 Return(Expr(Call(ty.Of(s)))),
Ben Clayton783b1692022-08-02 17:03:35 +00001102 },
dan sinclairbae54e72023-07-28 15:01:54 +00001103 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001104 Stage(ast::PipelineStage::kCompute),
1105 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1106 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001107
dan sinclair41e4d9a2022-05-01 14:40:55 +00001108 EXPECT_FALSE(r()->Resolve());
Ben Clayton710b62f2024-02-26 20:24:06 +00001109 EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders
111056:78 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001111}
1112
1113TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Input) {
Ben Clayton783b1692022-08-02 17:03:35 +00001114 auto* m = Member("m", ty.i32(),
dan sinclairbae54e72023-07-28 15:01:54 +00001115 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001116 Location(Source{{12, 34}}, 0_u),
Ben Clayton783b1692022-08-02 17:03:35 +00001117 });
dan sinclairbae54e72023-07-28 15:01:54 +00001118 auto* s = Structure("S", Vector{m});
dan sinclair41e4d9a2022-05-01 14:40:55 +00001119 auto* input = Param("input", ty.Of(s));
dan sinclairbae54e72023-07-28 15:01:54 +00001120 Func(Source{{56, 78}}, "main", Vector{input}, ty.void_(), tint::Empty,
1121 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001122 Stage(ast::PipelineStage::kCompute),
1123 create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i)),
1124 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001125
dan sinclair41e4d9a2022-05-01 14:40:55 +00001126 EXPECT_FALSE(r()->Resolve());
Ben Clayton710b62f2024-02-26 20:24:06 +00001127 EXPECT_EQ(r()->error(), R"(12:34 error: '@location' cannot be used by compute shaders
112856:78 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001129}
1130
1131TEST_F(LocationAttributeTests, Duplicate_input) {
dan sinclairb29892b2022-06-07 13:55:34 +00001132 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001133 // fn main(@location(1) param_a : f32,
1134 // @location(1) param_b : f32) {}
Ben Clayton783b1692022-08-02 17:03:35 +00001135 auto* param_a = Param("param_a", ty.f32(),
dan sinclairbae54e72023-07-28 15:01:54 +00001136 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001137 Location(1_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001138 });
1139 auto* param_b = Param("param_b", ty.f32(),
dan sinclairbae54e72023-07-28 15:01:54 +00001140 Vector{
dan sinclairf9eeed62022-09-07 22:25:24 +00001141 Location(Source{{12, 34}}, 1_a),
Ben Clayton783b1692022-08-02 17:03:35 +00001142 });
1143 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +00001144 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001145 param_a,
1146 param_b,
1147 },
dan sinclairbae54e72023-07-28 15:01:54 +00001148 ty.void_(), tint::Empty,
1149 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001150 Stage(ast::PipelineStage::kFragment),
1151 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001152
dan sinclair41e4d9a2022-05-01 14:40:55 +00001153 EXPECT_FALSE(r()->Resolve());
Ben Clayton710b62f2024-02-26 20:24:06 +00001154 EXPECT_EQ(r()->error(), R"(12:34 error: '@location(1)' appears multiple times)");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001155}
1156
1157TEST_F(LocationAttributeTests, Duplicate_struct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001158 // struct InputA {
1159 // @location(1) a : f32;
1160 // };
1161 // struct InputB {
1162 // @location(1) a : f32;
1163 // };
dan sinclairb29892b2022-06-07 13:55:34 +00001164 // @fragment
dan sinclair41e4d9a2022-05-01 14:40:55 +00001165 // fn main(param_a : InputA, param_b : InputB) {}
dan sinclairbae54e72023-07-28 15:01:54 +00001166 auto* input_a = Structure("InputA", Vector{
1167 Member("a", ty.f32(), Vector{Location(1_a)}),
Ben Clayton783b1692022-08-02 17:03:35 +00001168 });
dan sinclairbae54e72023-07-28 15:01:54 +00001169 auto* input_b =
1170 Structure("InputB", Vector{
1171 Member("a", ty.f32(), Vector{Location(Source{{34, 56}}, 1_a)}),
1172 });
dan sinclair41e4d9a2022-05-01 14:40:55 +00001173 auto* param_a = Param("param_a", ty.Of(input_a));
1174 auto* param_b = Param("param_b", ty.Of(input_b));
Ben Clayton783b1692022-08-02 17:03:35 +00001175 Func(Source{{12, 34}}, "main",
dan sinclairbae54e72023-07-28 15:01:54 +00001176 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001177 param_a,
1178 param_b,
1179 },
dan sinclairbae54e72023-07-28 15:01:54 +00001180 ty.void_(), tint::Empty,
1181 Vector{
Ben Clayton783b1692022-08-02 17:03:35 +00001182 Stage(ast::PipelineStage::kFragment),
1183 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001184
dan sinclair41e4d9a2022-05-01 14:40:55 +00001185 EXPECT_FALSE(r()->Resolve());
1186 EXPECT_EQ(r()->error(),
Ben Clayton710b62f2024-02-26 20:24:06 +00001187 R"(34:56 error: '@location(1)' appears multiple times
Ben Clayton4d3ff972023-02-21 17:33:54 +0000118812:34 note: while analyzing entry point 'main')");
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001189}
1190
1191} // namespace
1192} // namespace LocationAttributeTests
1193
1194} // namespace
dan sinclaird2093792022-04-07 17:45:45 +00001195} // namespace tint::resolver