wgsl: Replace [[decoration]] with @decoration

Deprecate the old syntax. Migrate everything to the new syntax.

Bug: tint:1382
Change-Id: Ide12b2e927b17dc93b9714c7049090864cc568d3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/77260
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: David Neto <dneto@google.com>
This commit is contained in:
Ben Clayton
2022-01-19 22:46:57 +00:00
committed by Tint LUCI CQ
parent 8f1d5224ee
commit 01e4b6fc18
3200 changed files with 15906 additions and 15215 deletions

View File

@@ -27,7 +27,7 @@ using ResolverAssignmentValidationTest = ResolverTest;
TEST_F(ResolverAssignmentValidationTest, ReadOnlyBuffer) {
// [[block]] struct S { m : i32 };
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<storage,read> a : S;
auto* s = Structure("S", {Member("m", ty.i32())},
{create<ast::StructBlockDecoration>()});
@@ -251,7 +251,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) {
TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Atomic) {
// [[block]] struct S { a : atomic<i32>; };
// [[group(0), binding(0)]] var<storage, read_write> v : S;
// @group(0) @binding(0) var<storage, read_write> v : S;
// v.a = v.a;
auto* s = Structure("S", {Member("a", ty.atomic(ty.i32()))},
@@ -273,7 +273,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Atomic) {
TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_RuntimeArray) {
// [[block]] struct S { a : array<f32>; };
// [[group(0), binding(0)]] var<storage, read_write> v : S;
// @group(0) @binding(0) var<storage, read_write> v : S;
// v.a = v.a;
auto* s = Structure("S", {Member("a", ty.array(ty.f32()))},
@@ -299,7 +299,7 @@ TEST_F(ResolverAssignmentValidationTest,
// struct S {
// arr: array<i32>;
// };
// [[group(0), binding(0)]] var<storage, read_write> s : S;
// @group(0) @binding(0) var<storage, read_write> s : S;
// fn f() {
// _ = s;
// }
@@ -320,7 +320,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_DynamicArray_Fail) {
// struct S {
// arr: array<i32>;
// };
// [[group(0), binding(0)]] var<storage, read_write> s : S;
// @group(0) @binding(0) var<storage, read_write> s : S;
// fn f() {
// _ = s.arr;
// }
@@ -347,10 +347,10 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_Pass) {
// struct U {
// i: i32;
// };
// [[group(0), binding(0)]] var tex texture_2d;
// [[group(0), binding(1)]] var smp sampler;
// [[group(0), binding(2)]] var<uniform> u : U;
// [[group(0), binding(3)]] var<storage, read_write> s : S;
// @group(0) @binding(0) var tex texture_2d;
// @group(0) @binding(1) var smp sampler;
// @group(0) @binding(2) var<uniform> u : U;
// @group(0) @binding(3) var<storage, read_write> s : S;
// var<workgroup> wg : array<f32, 10>
// fn f() {
// _ = 1;

View File

@@ -201,10 +201,10 @@ INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
testing::ValuesIn(cases));
TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInput_Fail) {
// [[stage(fragment)]]
// @stage(fragment)
// fn fs_main(
// [[builtin(frag_depth)]] fd: f32,
// ) -> [[location(0)]] f32 { return 1.0; }
// @builtin(frag_depth) fd: f32,
// ) -> @location(0) f32 { return 1.0; }
auto* fd = Param(
"fd", ty.f32(),
ast::DecorationList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
@@ -219,10 +219,10 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInput_Fail) {
TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInputStruct_Fail) {
// struct MyInputs {
// [[builtin(frag_depth)]] ff: f32;
// @builtin(frag_depth) ff: f32;
// };
// [[stage(fragment)]]
// fn fragShader(arg: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
auto* s = Structure(
"MyInputs", {Member("frag_depth", ty.f32(),
@@ -240,9 +240,9 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInputStruct_Fail) {
TEST_F(ResolverBuiltinsValidationTest, StructBuiltinInsideEntryPoint_Ignored) {
// struct S {
// [[builtin(vertex_index)]] idx: u32;
// @builtin(vertex_index) idx: u32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn fragShader() { var s : S; }
Structure("S",
@@ -257,10 +257,10 @@ TEST_F(ResolverBuiltinsValidationTest, StructBuiltinInsideEntryPoint_Ignored) {
TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_Struct_Fail) {
// struct MyInputs {
// [[builtin(kPosition)]] p: vec4<u32>;
// @builtin(kPosition) p: vec4<u32>;
// };
// [[stage(fragment)]]
// fn fragShader(is_front: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
auto* m = Member(
"position", ty.vec4<u32>(),
@@ -275,8 +275,8 @@ TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_Struct_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
// [[stage(vertex)]]
// fn main() -> [[builtin(position)]] f32 { return 1.0; }
// @stage(vertex)
// fn main() -> @builtin(position) f32 { return 1.0; }
Func("main", {}, ty.f32(), {Return(1.0f)},
{Stage(ast::PipelineStage::kVertex)},
{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
@@ -288,10 +288,10 @@ TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
// struct MyInputs {
// [[builtin(kFragDepth)]] p: i32;
// @builtin(kFragDepth) p: i32;
// };
// [[stage(fragment)]]
// fn fragShader(is_front: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
auto* m = Member(
"frag_depth", ty.i32(),
@@ -307,10 +307,10 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
// struct MyInputs {
// [[builtin(sample_mask)]] m: f32;
// @builtin(sample_mask) m: f32;
// };
// [[stage(fragment)]]
// fn fragShader(is_front: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
auto* s = Structure(
"MyInputs", {Member("m", ty.f32(),
@@ -325,8 +325,8 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
// [[stage(fragment)]]
// fn main() -> [[builtin(sample_mask)]] i32 { return 1; }
// @stage(fragment)
// fn main() -> @builtin(sample_mask) i32 { return 1; }
Func("main", {}, ty.i32(), {Return(1)},
{Stage(ast::PipelineStage::kFragment)},
{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
@@ -337,10 +337,10 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
// [[stage(fragment)]]
// @stage(fragment)
// fn fs_main(
// [[builtin(sample_mask)]] arg: bool
// ) -> [[location(0)]] f32 { return 1.0; }
// @builtin(sample_mask) arg: bool
// ) -> @location(0) f32 { return 1.0; }
auto* arg = Param("arg", ty.bool_(),
ast::DecorationList{
Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
@@ -354,10 +354,10 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Struct_Fail) {
// struct MyInputs {
// [[builtin(sample_index)]] m: f32;
// @builtin(sample_index) m: f32;
// };
// [[stage(fragment)]]
// fn fragShader(is_front: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
auto* s = Structure(
"MyInputs", {Member("m", ty.f32(),
@@ -372,10 +372,10 @@ TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Struct_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Fail) {
// [[stage(fragment)]]
// @stage(fragment)
// fn fs_main(
// [[builtin(sample_index)]] arg: bool
// ) -> [[location(0)]] f32 { return 1.0; }
// @builtin(sample_index) arg: bool
// ) -> @location(0) f32 { return 1.0; }
auto* arg = Param("arg", ty.bool_(),
ast::DecorationList{
Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)});
@@ -388,10 +388,10 @@ TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, PositionIsNotF32_Fail) {
// [[stage(fragment)]]
// @stage(fragment)
// fn fs_main(
// [[builtin(kPosition)]] p: vec3<f32>,
// ) -> [[location(0)]] f32 { return 1.0; }
// @builtin(kPosition) p: vec3<f32>,
// ) -> @location(0) f32 { return 1.0; }
auto* p = Param(
"p", ty.vec3<f32>(),
ast::DecorationList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
@@ -404,8 +404,8 @@ TEST_F(ResolverBuiltinsValidationTest, PositionIsNotF32_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, FragDepthIsNotF32_Fail) {
// [[stage(fragment)]]
// fn fs_main() -> [[builtin(kFragDepth)]] f32 { var fd: i32; return fd; }
// @stage(fragment)
// fn fs_main() -> @builtin(kFragDepth) f32 { var fd: i32; return fd; }
auto* fd = Var("fd", ty.i32());
Func(
"fs_main", {}, ty.i32(), {Decl(fd), Return(fd)},
@@ -417,11 +417,11 @@ TEST_F(ResolverBuiltinsValidationTest, FragDepthIsNotF32_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, VertexIndexIsNotU32_Fail) {
// [[stage(vertex)]]
// @stage(vertex)
// fn main(
// [[builtin(kVertexIndex)]] vi : f32,
// [[builtin(kPosition)]] p :vec4<f32>
// ) -> [[builtin(kPosition)]] vec4<f32> { return vec4<f32>(); }
// @builtin(kVertexIndex) vi : f32,
// @builtin(kPosition) p :vec4<f32>
// ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
auto* p = Param("p", ty.vec4<f32>(),
ast::DecorationList{Builtin(ast::Builtin::kPosition)});
auto* vi = Param("vi", ty.f32(),
@@ -436,11 +436,11 @@ TEST_F(ResolverBuiltinsValidationTest, VertexIndexIsNotU32_Fail) {
}
TEST_F(ResolverBuiltinsValidationTest, InstanceIndexIsNotU32) {
// [[stage(vertex)]]
// @stage(vertex)
// fn main(
// [[builtin(kInstanceIndex)]] ii : f32,
// [[builtin(kPosition)]] p :vec4<f32>
// ) -> [[builtin(kPosition)]] vec4<f32> { return vec4<f32>(); }
// @builtin(kInstanceIndex) ii : f32,
// @builtin(kPosition) p :vec4<f32>
// ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
auto* p = Param("p", ty.vec4<f32>(),
ast::DecorationList{Builtin(ast::Builtin::kPosition)});
auto* ii = Param("ii", ty.f32(),
@@ -455,13 +455,13 @@ TEST_F(ResolverBuiltinsValidationTest, InstanceIndexIsNotU32) {
}
TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltin_Pass) {
// [[stage(fragment)]]
// @stage(fragment)
// fn fs_main(
// [[builtin(kPosition)]] p: vec4<f32>,
// [[builtin(front_facing)]] ff: bool,
// [[builtin(sample_index)]] si: u32,
// [[builtin(sample_mask)]] sm : u32
// ) -> [[builtin(frag_depth)]] f32 { var fd: f32; return fd; }
// @builtin(kPosition) p: vec4<f32>,
// @builtin(front_facing) ff: bool,
// @builtin(sample_index) si: u32,
// @builtin(sample_mask) sm : u32
// ) -> @builtin(frag_depth) f32 { var fd: f32; return fd; }
auto* p = Param("p", ty.vec4<f32>(),
ast::DecorationList{Builtin(ast::Builtin::kPosition)});
auto* ff = Param("ff", ty.bool_(),
@@ -479,11 +479,11 @@ TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltin_Pass) {
}
TEST_F(ResolverBuiltinsValidationTest, VertexBuiltin_Pass) {
// [[stage(vertex)]]
// @stage(vertex)
// fn main(
// [[builtin(vertex_index)]] vi : u32,
// [[builtin(instance_index)]] ii : u32,
// ) -> [[builtin(position)]] vec4<f32> { var p :vec4<f32>; return p; }
// @builtin(vertex_index) vi : u32,
// @builtin(instance_index) ii : u32,
// ) -> @builtin(position) vec4<f32> { var p :vec4<f32>; return p; }
auto* vi = Param("vi", ty.u32(),
ast::DecorationList{
Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
@@ -504,13 +504,13 @@ TEST_F(ResolverBuiltinsValidationTest, VertexBuiltin_Pass) {
}
TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_Pass) {
// [[stage(compute), workgroup_size(1)]]
// @stage(compute) @workgroup_size(1)
// fn main(
// [[builtin(local_invocationId)]] li_id: vec3<u32>,
// [[builtin(local_invocationIndex)]] li_index: u32,
// [[builtin(global_invocationId)]] gi: vec3<u32>,
// [[builtin(workgroup_id)]] wi: vec3<u32>,
// [[builtin(num_workgroups)]] nwgs: vec3<u32>,
// @builtin(local_invocationId) li_id: vec3<u32>,
// @builtin(local_invocationIndex) li_index: u32,
// @builtin(global_invocationId) gi: vec3<u32>,
// @builtin(workgroup_id) wi: vec3<u32>,
// @builtin(num_workgroups) nwgs: vec3<u32>,
// ) {}
auto* li_id =
@@ -618,13 +618,13 @@ TEST_F(ResolverBuiltinsValidationTest,
TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltinStruct_Pass) {
// Struct MyInputs {
// [[builtin(kPosition)]] p: vec4<f32>;
// [[builtin(frag_depth)]] fd: f32;
// [[builtin(sample_index)]] si: u32;
// [[builtin(sample_mask)]] sm : u32;;
// @builtin(kPosition) p: vec4<f32>;
// @builtin(frag_depth) fd: f32;
// @builtin(sample_index) si: u32;
// @builtin(sample_mask) sm : u32;;
// };
// [[stage(fragment)]]
// fn fragShader(arg: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
auto* s = Structure(
"MyInputs",
@@ -642,10 +642,10 @@ TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltinStruct_Pass) {
}
TEST_F(ResolverBuiltinsValidationTest, FrontFacingParamIsNotBool_Fail) {
// [[stage(fragment)]]
// @stage(fragment)
// fn fs_main(
// [[builtin(front_facing)]] is_front: i32;
// ) -> [[location(0)]] f32 { return 1.0; }
// @builtin(front_facing) is_front: i32;
// ) -> @location(0) f32 { return 1.0; }
auto* is_front = Param("is_front", ty.i32(),
ast::DecorationList{Builtin(
@@ -661,10 +661,10 @@ TEST_F(ResolverBuiltinsValidationTest, FrontFacingParamIsNotBool_Fail) {
TEST_F(ResolverBuiltinsValidationTest, FrontFacingMemberIsNotBool_Fail) {
// struct MyInputs {
// [[builtin(front_facing)]] pos: f32;
// @builtin(front_facing) pos: f32;
// };
// [[stage(fragment)]]
// fn fragShader(is_front: MyInputs) -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
auto* s = Structure(
"MyInputs", {Member("pos", ty.f32(),

View File

@@ -172,7 +172,7 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
// fn bar(p: ptr<function, i32>) {
// foo(p);
// }
// [[stage(fragment)]]
// @stage(fragment)
// fn main() {
// var v: i32;
// bar(&v);
@@ -195,7 +195,7 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
TEST_F(ResolverCallValidationTest, LetPointer) {
// fn x(p : ptr<function, i32>) -> i32 {}
// [[stage(fragment)]]
// @stage(fragment)
// fn main() {
// var v: i32;
// let p: ptr<function, i32> = &v;
@@ -227,7 +227,7 @@ TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
// let p: ptr<private, i32> = &v;
// fn foo(p : ptr<private, i32>) -> i32 {}
// var v: i32;
// [[stage(fragment)]]
// @stage(fragment)
// fn main() {
// var c: i32 = foo(p);
// }

View File

@@ -973,9 +973,9 @@ TEST_F(ResourceDecorationTest, UniformBufferMissingBinding) {
Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kUniform);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: resource variables require [[group]] and [[binding]] "
"decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: resource variables require @group and @binding decorations)");
}
TEST_F(ResourceDecorationTest, StorageBufferMissingBinding) {
@@ -985,9 +985,9 @@ TEST_F(ResourceDecorationTest, StorageBufferMissingBinding) {
ast::Access::kRead);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: resource variables require [[group]] and [[binding]] "
"decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: resource variables require @group and @binding decorations)");
}
TEST_F(ResourceDecorationTest, TextureMissingBinding) {
@@ -995,9 +995,9 @@ TEST_F(ResourceDecorationTest, TextureMissingBinding) {
ast::StorageClass::kNone);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: resource variables require [[group]] and [[binding]] "
"decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: resource variables require @group and @binding decorations)");
}
TEST_F(ResourceDecorationTest, SamplerMissingBinding) {
@@ -1005,9 +1005,9 @@ TEST_F(ResourceDecorationTest, SamplerMissingBinding) {
ast::StorageClass::kNone);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: resource variables require [[group]] and [[binding]] "
"decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: resource variables require @group and @binding decorations)");
}
TEST_F(ResourceDecorationTest, BindingPairMissingBinding) {
@@ -1018,9 +1018,9 @@ TEST_F(ResourceDecorationTest, BindingPairMissingBinding) {
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: resource variables require [[group]] and [[binding]] "
"decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: resource variables require @group and @binding decorations)");
}
TEST_F(ResourceDecorationTest, BindingPairMissingGroup) {
@@ -1031,9 +1031,9 @@ TEST_F(ResourceDecorationTest, BindingPairMissingGroup) {
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: resource variables require [[group]] and [[binding]] "
"decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: resource variables require @group and @binding decorations)");
}
TEST_F(ResourceDecorationTest, BindingPointUsedTwiceByEntryPoint) {
@@ -1064,7 +1064,7 @@ TEST_F(ResourceDecorationTest, BindingPointUsedTwiceByEntryPoint) {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: entry point 'F' references multiple variables that use the same resource binding [[group(2), binding(1)]]
R"(56:78 error: entry point 'F' references multiple variables that use the same resource binding @group(2), @binding(1)
12:34 note: first resource binding usage declared here)");
}
@@ -1108,9 +1108,9 @@ TEST_F(ResourceDecorationTest, BindingPointOnNonResource) {
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: non-resource variables must not have [[group]] or "
"[[binding]] decorations");
EXPECT_EQ(
r()->error(),
R"(12:34 error: non-resource variables must not have @group or @binding decorations)");
}
} // namespace
@@ -1368,9 +1368,9 @@ TEST_F(InterpolateTest, MissingLocationAttribute_Parameter) {
ast::DecorationList{Stage(ast::PipelineStage::kFragment)});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: interpolate attribute must only be used with "
"[[location]]");
EXPECT_EQ(
r()->error(),
R"(12:34 error: interpolate attribute must only be used with @location)");
}
TEST_F(InterpolateTest, MissingLocationAttribute_ReturnType) {
@@ -1381,9 +1381,9 @@ TEST_F(InterpolateTest, MissingLocationAttribute_ReturnType) {
ast::InterpolationSampling::kNone)});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: interpolate attribute must only be used with "
"[[location]]");
EXPECT_EQ(
r()->error(),
R"(12:34 error: interpolate attribute must only be used with @location)");
}
TEST_F(InterpolateTest, MissingLocationAttribute_Struct) {
@@ -1393,9 +1393,9 @@ TEST_F(InterpolateTest, MissingLocationAttribute_Struct) {
ast::InterpolationSampling::kNone)})});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: interpolate attribute must only be used with "
"[[location]]");
EXPECT_EQ(
r()->error(),
R"(12:34 error: interpolate attribute must only be used with @location)");
}
} // namespace

View File

@@ -51,8 +51,8 @@ class ResolverEntryPointValidationTest : public TestHelper,
public testing::Test {};
TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
// [[stage(fragment)]]
// fn main() -> [[location(0)]] f32 { return 1.0; }
// @stage(fragment)
// fn main() -> @location(0) f32 { return 1.0; }
Func(Source{{12, 34}}, "main", {}, ty.f32(), {Return(1.0f)},
{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
@@ -60,8 +60,8 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
}
TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Builtin) {
// [[stage(vertex)]]
// fn main() -> [[builtin(position)]] vec4<f32> { return vec4<f32>(); }
// @stage(vertex)
// fn main() -> @builtin(position) vec4<f32> { return vec4<f32>(); }
Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(),
{Return(Construct(ty.vec4<f32>()))},
{Stage(ast::PipelineStage::kVertex)},
@@ -71,7 +71,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Builtin) {
}
TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Missing) {
// [[stage(vertex)]]
// @stage(vertex)
// fn main() -> f32 {
// return 1.0;
// }
@@ -85,8 +85,8 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Missing) {
}
TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
// [[stage(vertex)]]
// fn main() -> [[location(0)]] [[builtin(position)]] vec4<f32> {
// @stage(vertex)
// fn main() -> @location(0) @builtin(position) vec4<f32> {
// return vec4<f32>();
// }
Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(),
@@ -102,10 +102,10 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
// struct Output {
// [[location(0)]] a : f32;
// [[builtin(frag_depth)]] b : f32;
// @location(0) a : f32;
// @builtin(frag_depth) b : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -122,9 +122,9 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
TEST_F(ResolverEntryPointValidationTest,
ReturnType_Struct_MemberMultipleAttributes) {
// struct Output {
// [[location(0)]] [[builtin(frag_depth)]] a : f32;
// @location(0) @builtin(frag_depth) a : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -146,10 +146,10 @@ TEST_F(ResolverEntryPointValidationTest,
TEST_F(ResolverEntryPointValidationTest,
ReturnType_Struct_MemberMissingAttribute) {
// struct Output {
// [[location(0)]] a : f32;
// @location(0) a : f32;
// b : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -168,10 +168,10 @@ TEST_F(ResolverEntryPointValidationTest,
TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
// struct Output {
// [[builtin(frag_depth)]] a : f32;
// [[builtin(frag_depth)]] b : f32;
// @builtin(frag_depth) a : f32;
// @builtin(frag_depth) b : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -190,8 +190,8 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
}
TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Location) {
// [[stage(fragment)]]
// fn main([[location(0)]] param : f32) {}
// @stage(fragment)
// fn main(@location(0) param : f32) {}
auto* param = Param("param", ty.f32(), {Location(0)});
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
{Stage(ast::PipelineStage::kFragment)});
@@ -200,7 +200,7 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Location) {
}
TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param : f32) {}
auto* param = Param(Source{{13, 43}}, "param", ty.vec4<f32>());
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
@@ -212,8 +212,8 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
}
TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
// [[stage(fragment)]]
// fn main([[location(0)]] [[builtin(sample_index)]] param : u32) {}
// @stage(fragment)
// fn main(@location(0) @builtin(sample_index) param : u32) {}
auto* param = Param("param", ty.u32(),
{Location(Source{{13, 43}}, 0),
Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)});
@@ -227,10 +227,10 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
// struct Input {
// [[location(0)]] a : f32;
// [[builtin(sample_index)]] b : u32;
// @location(0) a : f32;
// @builtin(sample_index) b : u32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param : Input) {}
auto* input = Structure(
"Input", {Member("a", ty.f32(), {Location(0)}),
@@ -245,9 +245,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
TEST_F(ResolverEntryPointValidationTest,
Parameter_Struct_MemberMultipleAttributes) {
// struct Input {
// [[location(0)]] [[builtin(sample_index)]] a : u32;
// @location(0) @builtin(sample_index) a : u32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param : Input) {}
auto* input = Structure(
"Input",
@@ -267,10 +267,10 @@ TEST_F(ResolverEntryPointValidationTest,
TEST_F(ResolverEntryPointValidationTest,
Parameter_Struct_MemberMissingAttribute) {
// struct Input {
// [[location(0)]] a : f32;
// @location(0) a : f32;
// b : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param : Input) {}
auto* input = Structure(
"Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
@@ -285,9 +285,9 @@ TEST_F(ResolverEntryPointValidationTest,
}
TEST_F(ResolverEntryPointValidationTest, Parameter_DuplicateBuiltins) {
// [[stage(fragment)]]
// fn main([[builtin(sample_index)]] param_a : u32,
// [[builtin(sample_index)]] param_b : u32) {}
// @stage(fragment)
// fn main(@builtin(sample_index) param_a : u32,
// @builtin(sample_index) param_b : u32) {}
auto* param_a =
Param("param_a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
auto* param_b =
@@ -304,12 +304,12 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_DuplicateBuiltins) {
TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
// struct InputA {
// [[builtin(sample_index)]] a : u32;
// @builtin(sample_index) a : u32;
// };
// struct InputB {
// [[builtin(sample_index)]] a : u32;
// @builtin(sample_index) a : u32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param_a : InputA, param_b : InputB) {}
auto* input_a = Structure(
"InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
@@ -328,7 +328,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
}
TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
// [[stage(vertex)]]
// @stage(vertex)
// fn main() {}
Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
{Stage(ast::PipelineStage::kVertex)});
@@ -370,8 +370,8 @@ static constexpr Params cases[] = {
};
TEST_P(TypeValidationTest, BareInputs) {
// [[stage(fragment)]]
// fn main([[location(0)]] a : *) {}
// @stage(fragment)
// fn main(@location(0) a : *) {}
auto params = GetParam();
auto* a = Param("a", params.create_ast_type(*this), {Location(0)});
Func(Source{{12, 34}}, "main", {a}, ty.void_(), {},
@@ -386,9 +386,9 @@ TEST_P(TypeValidationTest, BareInputs) {
TEST_P(TypeValidationTest, StructInputs) {
// struct Input {
// [[location(0)]] a : *;
// @location(0) a : *;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(a : Input) {}
auto params = GetParam();
auto* input = Structure(
@@ -405,8 +405,8 @@ TEST_P(TypeValidationTest, StructInputs) {
}
TEST_P(TypeValidationTest, BareOutputs) {
// [[stage(fragment)]]
// fn main() -> [[location(0)]] * {
// @stage(fragment)
// fn main() -> @location(0) * {
// return *();
// }
auto params = GetParam();
@@ -423,9 +423,9 @@ TEST_P(TypeValidationTest, BareOutputs) {
TEST_P(TypeValidationTest, StructOutputs) {
// struct Output {
// [[location(0)]] a : *;
// @location(0) a : *;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -453,8 +453,8 @@ namespace {
using LocationDecorationTests = ResolverTest;
TEST_F(LocationDecorationTests, Pass) {
// [[stage(fragment)]]
// fn frag_main([[location(0)]] a: i32) {}
// @stage(fragment)
// fn frag_main(@location(0) a: i32) {}
auto* p = Param(Source{{12, 34}}, "a", ty.i32(), {Location(0)});
Func("frag_main", {p}, ty.void_(), {},
@@ -464,8 +464,8 @@ TEST_F(LocationDecorationTests, Pass) {
}
TEST_F(LocationDecorationTests, BadType_Input_bool) {
// [[stage(fragment)]]
// fn frag_main([[location(0)]] a: bool) {}
// @stage(fragment)
// fn frag_main(@location(0) a: bool) {}
auto* p =
Param(Source{{12, 34}}, "a", ty.bool_(), {Location(Source{{34, 56}}, 0)});
@@ -481,8 +481,8 @@ TEST_F(LocationDecorationTests, BadType_Input_bool) {
}
TEST_F(LocationDecorationTests, BadType_Output_Array) {
// [[stage(fragment)]]
// fn frag_main()->[[location(0)]] array<f32, 2> { return array<f32, 2>(); }
// @stage(fragment)
// fn frag_main()->@location(0) array<f32, 2> { return array<f32, 2>(); }
Func(Source{{12, 34}}, "frag_main", {}, ty.array<f32, 2>(),
{Return(Construct(ty.array<f32, 2>()))},
@@ -500,8 +500,8 @@ TEST_F(LocationDecorationTests, BadType_Input_Struct) {
// struct Input {
// a : f32;
// };
// [[stage(fragment)]]
// fn main([[location(0)]] param : Input) {}
// @stage(fragment)
// fn main(@location(0) param : Input) {}
auto* input = Structure("Input", {Member("a", ty.f32())});
auto* param = Param(Source{{12, 34}}, "param", ty.Of(input),
{Location(Source{{13, 43}}, 0)});
@@ -518,12 +518,12 @@ TEST_F(LocationDecorationTests, BadType_Input_Struct) {
TEST_F(LocationDecorationTests, BadType_Input_Struct_NestedStruct) {
// struct Inner {
// [[location(0)]] b : f32;
// @location(0) b : f32;
// };
// struct Input {
// a : Inner;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param : Input) {}
auto* inner = Structure(
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
@@ -542,9 +542,9 @@ TEST_F(LocationDecorationTests, BadType_Input_Struct_NestedStruct) {
TEST_F(LocationDecorationTests, BadType_Input_Struct_RuntimeArray) {
// [[block]]
// struct Input {
// [[location(0)]] a : array<f32>;
// @location(0) a : array<f32>;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param : Input) {}
auto* input = Structure(
"Input",
@@ -564,8 +564,8 @@ TEST_F(LocationDecorationTests, BadType_Input_Struct_RuntimeArray) {
TEST_F(LocationDecorationTests, BadMemberType_Input) {
// [[block]]
// struct S { [[location(0)]] m: array<i32>; };
// [[stage(fragment)]]
// struct S { @location(0) m: array<i32>; };
// @stage(fragment)
// fn frag_main( a: S) {}
auto* m = Member(Source{{34, 56}}, "m", ty.array<i32>(),
@@ -585,8 +585,8 @@ TEST_F(LocationDecorationTests, BadMemberType_Input) {
}
TEST_F(LocationDecorationTests, BadMemberType_Output) {
// struct S { [[location(0)]] m: atomic<i32>; };
// [[stage(fragment)]]
// struct S { @location(0) m: atomic<i32>; };
// @stage(fragment)
// fn frag_main() -> S {}
auto* m = Member(Source{{34, 56}}, "m", ty.atomic<i32>(),
ast::DecorationList{Location(Source{{12, 34}}, 0u)});
@@ -604,7 +604,7 @@ TEST_F(LocationDecorationTests, BadMemberType_Output) {
}
TEST_F(LocationDecorationTests, BadMemberType_Unused) {
// struct S { [[location(0)]] m: mat3x2<f32>; };
// struct S { @location(0) m: mat3x2<f32>; };
auto* m = Member(Source{{34, 56}}, "m", ty.mat3x2<f32>(),
ast::DecorationList{Location(Source{{12, 34}}, 0u)});
@@ -620,10 +620,10 @@ TEST_F(LocationDecorationTests, BadMemberType_Unused) {
TEST_F(LocationDecorationTests, ReturnType_Struct_Valid) {
// struct Output {
// [[location(0)]] a : f32;
// [[builtin(frag_depth)]] b : f32;
// @location(0) a : f32;
// @builtin(frag_depth) b : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -641,8 +641,8 @@ TEST_F(LocationDecorationTests, ReturnType_Struct) {
// struct Output {
// a : f32;
// };
// [[stage(vertex)]]
// fn main() -> [[location(0)]] Output {
// @stage(vertex)
// fn main() -> @location(0) Output {
// return Output();
// }
auto* output = Structure("Output", {Member("a", ty.f32())});
@@ -660,12 +660,12 @@ TEST_F(LocationDecorationTests, ReturnType_Struct) {
TEST_F(LocationDecorationTests, ReturnType_Struct_NestedStruct) {
// struct Inner {
// [[location(0)]] b : f32;
// @location(0) b : f32;
// };
// struct Output {
// a : Inner;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output { return Output(); }
auto* inner = Structure(
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
@@ -684,9 +684,9 @@ TEST_F(LocationDecorationTests, ReturnType_Struct_NestedStruct) {
TEST_F(LocationDecorationTests, ReturnType_Struct_RuntimeArray) {
// [[block]]
// struct Output {
// [[location(0)]] a : array<f32>;
// @location(0) a : array<f32>;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main() -> Output {
// return Output();
// }
@@ -760,9 +760,9 @@ TEST_F(LocationDecorationTests, ComputeShaderLocationStructMember_Input) {
}
TEST_F(LocationDecorationTests, Duplicate_input) {
// [[stage(fragment)]]
// fn main([[location(1)]] param_a : f32,
// [[location(1)]] param_b : f32) {}
// @stage(fragment)
// fn main(@location(1) param_a : f32,
// @location(1) param_b : f32) {}
auto* param_a = Param("param_a", ty.f32(), {Location(1)});
auto* param_b = Param("param_b", ty.f32(), {Location(Source{{12, 34}}, 1)});
Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
@@ -775,12 +775,12 @@ TEST_F(LocationDecorationTests, Duplicate_input) {
TEST_F(LocationDecorationTests, Duplicate_struct) {
// struct InputA {
// [[location(1)]] a : f32;
// @location(1) a : f32;
// };
// struct InputB {
// [[location(1)]] a : f32;
// @location(1) a : f32;
// };
// [[stage(fragment)]]
// @stage(fragment)
// fn main(param_a : InputA, param_b : InputB) {}
auto* input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
auto* input_b = Structure(

View File

@@ -353,7 +353,7 @@ TEST_F(ResolverFunctionValidationTest,
}
TEST_F(ResolverFunctionValidationTest, CannotCallEntryPoint) {
// [[stage(compute), workgroup_size(1)]] fn entrypoint() {}
// @stage(compute) @workgroup_size(1) fn entrypoint() {}
// fn func() { return entrypoint(); }
Func("entrypoint", ast::VariableList{}, ty.void_(), {},
{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
@@ -371,8 +371,8 @@ TEST_F(ResolverFunctionValidationTest, CannotCallEntryPoint) {
}
TEST_F(ResolverFunctionValidationTest, PipelineStage_MustBeUnique_Fail) {
// [[stage(fragment)]]
// [[stage(vertex)]]
// @stage(fragment)
// @stage(vertex)
// fn main() { return; }
Func(Source{{12, 34}}, "main", ast::VariableList{}, ty.void_(),
ast::StatementList{
@@ -440,7 +440,7 @@ TEST_F(ResolverFunctionValidationTest, FunctionParamsConst) {
TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_ConstU32) {
// let x = 4u;
// let x = 8u;
// [[stage(compute), workgroup_size(x, y, 16u)]]
// @stage(compute) @workgroup_size(x, y, 16u)
// fn main() {}
auto* x = GlobalConst("x", ty.u32(), Expr(4u));
auto* y = GlobalConst("y", ty.u32(), Expr(8u));

View File

@@ -36,7 +36,7 @@ TEST_F(ResolverIntrinsicValidationTest,
}
TEST_F(ResolverIntrinsicValidationTest, InvalidPipelineStageDirect) {
// [[stage(compute), workgroup_size(1)]] fn func { return dpdx(1.0); }
// @stage(compute) @workgroup_size(1) fn func { return dpdx(1.0); }
auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
ast::ExpressionList{Expr(1.0f)});
@@ -53,7 +53,7 @@ TEST_F(ResolverIntrinsicValidationTest, InvalidPipelineStageIndirect) {
// fn f0 { return dpdx(1.0); }
// fn f1 { f0(); }
// fn f2 { f1(); }
// [[stage(compute), workgroup_size(1)]] fn main { return f2(); }
// @stage(compute) @workgroup_size(1) fn main { return f2(); }
auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
ast::ExpressionList{Expr(1.0f)});

View File

@@ -53,7 +53,7 @@ TEST_F(ResolverPtrRefValidationTest, AddressOfLet) {
}
TEST_F(ResolverPtrRefValidationTest, AddressOfHandle) {
// [[group(0), binding(0)]] var t: texture_3d<f32>;
// @group(0) @binding(0) var t: texture_3d<f32>;
// &t
Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()),
GroupAndBinding(0u, 0u));
@@ -95,7 +95,7 @@ TEST_F(ResolverPtrRefValidationTest, AddressOfVectorComponent_IndexAccessor) {
}
TEST_F(ResolverPtrRefValidationTest, IndirectOfAddressOfHandle) {
// [[group(0), binding(0)]] var t: texture_3d<f32>;
// @group(0) @binding(0) var t: texture_3d<f32>;
// *&t
Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()),
GroupAndBinding(0u, 0u));
@@ -142,7 +142,7 @@ TEST_F(ResolverPtrRefValidationTest, InferredPtrAccessMismatch) {
// [[block]] struct S {
// inner: Inner;
// }
// [[group(0), binding(0)]] var<storage, read_write> s : S;
// @group(0) @binding(0) var<storage, read_write> s : S;
// fn f() {
// let p : pointer<storage, i32> = &s.inner.arr[2];
// }

View File

@@ -2151,7 +2151,7 @@ sem::Array* Resolver::Array(const ast::Array* arr) {
return nullptr;
}
// Look for explicit stride via [[stride(n)]] decoration
// Look for explicit stride via @stride(n) decoration
uint32_t explicit_stride = 0;
for (auto* deco : arr->decorations) {
Mark(deco);

View File

@@ -920,7 +920,7 @@ TEST_F(ResolverTest, Function_CallSites) {
}
TEST_F(ResolverTest, Function_WorkgroupSize_NotSet) {
// [[stage(compute), workgroup_size(1)]]
// @stage(compute) @workgroup_size(1)
// fn main() {}
auto* func = Func("main", ast::VariableList{}, ty.void_(), {}, {});
@@ -938,7 +938,7 @@ TEST_F(ResolverTest, Function_WorkgroupSize_NotSet) {
}
TEST_F(ResolverTest, Function_WorkgroupSize_Literals) {
// [[stage(compute), workgroup_size(8, 2, 3)]]
// @stage(compute) @workgroup_size(8, 2, 3)
// fn main() {}
auto* func =
Func("main", ast::VariableList{}, ty.void_(), {},
@@ -961,7 +961,7 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Consts) {
// let width = 16;
// let height = 8;
// let depth = 2;
// [[stage(compute), workgroup_size(width, height, depth)]]
// @stage(compute) @workgroup_size(width, height, depth)
// fn main() {}
GlobalConst("width", ty.i32(), Expr(16));
GlobalConst("height", ty.i32(), Expr(8));
@@ -986,7 +986,7 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Consts) {
TEST_F(ResolverTest, Function_WorkgroupSize_Consts_NestedInitializer) {
// let width = i32(i32(i32(8)));
// let height = i32(i32(i32(4)));
// [[stage(compute), workgroup_size(width, height)]]
// @stage(compute) @workgroup_size(width, height)
// fn main() {}
GlobalConst("width", ty.i32(),
Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 8))));
@@ -1010,10 +1010,10 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Consts_NestedInitializer) {
}
TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts) {
// [[override(0)]] let width = 16;
// [[override(1)]] let height = 8;
// [[override(2)]] let depth = 2;
// [[stage(compute), workgroup_size(width, height, depth)]]
// @override(0) let width = 16;
// @override(1) let height = 8;
// @override(2) let depth = 2;
// @stage(compute) @workgroup_size(width, height, depth)
// fn main() {}
auto* width = GlobalConst("width", ty.i32(), Expr(16), {Override(0)});
auto* height = GlobalConst("height", ty.i32(), Expr(8), {Override(1)});
@@ -1036,10 +1036,10 @@ TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts) {
}
TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts_NoInit) {
// [[override(0)]] let width : i32;
// [[override(1)]] let height : i32;
// [[override(2)]] let depth : i32;
// [[stage(compute), workgroup_size(width, height, depth)]]
// @override(0) let width : i32;
// @override(1) let height : i32;
// @override(2) let depth : i32;
// @stage(compute) @workgroup_size(width, height, depth)
// fn main() {}
auto* width = GlobalConst("width", ty.i32(), nullptr, {Override(0)});
auto* height = GlobalConst("height", ty.i32(), nullptr, {Override(1)});
@@ -1062,9 +1062,9 @@ TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts_NoInit) {
}
TEST_F(ResolverTest, Function_WorkgroupSize_Mixed) {
// [[override(1)]] let height = 2;
// @override(1) let height = 2;
// let depth = 3;
// [[stage(compute), workgroup_size(8, height, depth)]]
// @stage(compute) @workgroup_size(8, height, depth)
// fn main() {}
auto* height = GlobalConst("height", ty.i32(), Expr(2), {Override(0)});
GlobalConst("depth", ty.i32(), Expr(3));
@@ -1816,8 +1816,8 @@ TEST_F(ResolverTest, Access_SetForStorageBuffer) {
}
TEST_F(ResolverTest, BindingPoint_SetForResources) {
// [[group(1), binding(2)]] var s1 : sampler;
// [[group(3), binding(4)]] var s2 : sampler;
// @group(1) @binding(2) var s1 : sampler;
// @group(3) @binding(4) var s2 : sampler;
auto* s1 = Global(Sym(), ty.sampler(ast::SamplerKind::kSampler),
ast::DecorationList{create<ast::GroupDecoration>(1),
create<ast::BindingDecoration>(2)});

View File

@@ -271,8 +271,8 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
"' must be a multiple of " + std::to_string(required_align) +
" bytes, but '" + member_name_of(m) +
"' is currently at offset " + std::to_string(m->Offset()) +
". Consider setting [[align(" +
std::to_string(required_align) + ")]] on this member",
". Consider setting @align(" +
std::to_string(required_align) + ") on this member",
m->Declaration()->source);
AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
@@ -299,7 +299,7 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
"member be a multiple of 16 bytes, but there are currently " +
std::to_string(prev_to_curr_offset) + " bytes between '" +
member_name_of(prev_member) + "' and '" + member_name_of(m) +
"'. Consider setting [[align(16)]] on this member",
"'. Consider setting @align(16) on this member",
m->Declaration()->source);
AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
@@ -326,10 +326,10 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
"bytes, but array stride of '" +
member_name_of(m) + "' is currently " +
std::to_string(arr->Stride()) +
". Consider setting [[stride(" +
". Consider setting @stride(" +
std::to_string(
utils::RoundUp(required_align, arr->Stride())) +
")]] on the array type",
") on the array type",
m->Declaration()->type->source);
AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
str->Declaration()->source);
@@ -429,7 +429,7 @@ bool Resolver::ValidateGlobalVariable(const sem::Variable* var) {
// attributes.
if (!binding_point) {
AddError(
"resource variables require [[group]] and [[binding]] "
"resource variables require @group and @binding "
"decorations",
decl->source);
return false;
@@ -441,7 +441,7 @@ bool Resolver::ValidateGlobalVariable(const sem::Variable* var) {
// https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
// Must only be applied to a resource variable
AddError(
"non-resource variables must not have [[group]] or [[binding]] "
"non-resource variables must not have @group or @binding "
"decorations",
decl->source);
return false;
@@ -1037,7 +1037,7 @@ bool Resolver::ValidateEntryPoint(const sem::Function* func) {
if (interpolate_attribute) {
if (!pipeline_io_attribute ||
!pipeline_io_attribute->Is<ast::LocationDecoration>()) {
AddError("interpolate attribute must only be used with [[location]]",
AddError("interpolate attribute must only be used with @location",
interpolate_attribute->source);
return false;
}
@@ -1167,9 +1167,9 @@ bool Resolver::ValidateEntryPoint(const sem::Function* func) {
auto func_name = builder_->Symbols().NameFor(decl->symbol);
AddError("entry point '" + func_name +
"' references multiple variables that use the "
"same resource binding [[group(" +
std::to_string(bp.group) + "), binding(" +
std::to_string(bp.binding) + ")]]",
"same resource binding @group(" +
std::to_string(bp.group) + "), @binding(" +
std::to_string(bp.binding) + ")",
var_decl->source);
AddNote("first resource binding usage declared here",
res.first->second->source);
@@ -2035,7 +2035,7 @@ bool Resolver::ValidateStructure(const sem::Struct* str) {
}
if (interpolate_attribute && !has_location) {
AddError("interpolate attribute must only be used with [[location]]",
AddError("interpolate attribute must only be used with @location",
interpolate_attribute->source);
return false;
}

View File

@@ -28,10 +28,10 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
StorageBuffer_UnalignedMember) {
// [[block]]
// struct S {
// [[size(5)]] a : f32;
// [[align(1)]] b : f32;
// @size(5) a : f32;
// @align(1) b : f32;
// };
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<storage> a : S;
Structure(Source{{12, 34}}, "S",
@@ -45,7 +45,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting [[align(4)]] on this member
R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
12:34 note: see layout of struct:
/* align(4) size(12) */ struct S {
/* offset(0) align(4) size( 5) */ a : f32;
@@ -59,10 +59,10 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
StorageBuffer_UnalignedMember_SuggestedFix) {
// [[block]]
// struct S {
// [[size(5)]] a : f32;
// [[align(4)]] b : f32;
// @size(5) a : f32;
// @align(4) b : f32;
// };
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<storage> a : S;
Structure(Source{{12, 34}}, "S",
@@ -89,7 +89,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// inner : Inner;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
@@ -107,7 +107,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: the offset of a struct member of type 'Inner' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting [[align(16)]] on this member
R"(56:78 error: the offset of a struct member of type 'Inner' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
34:56 note: see layout of struct:
/* align(4) size(8) */ struct Outer {
/* offset(0) align(4) size(4) */ scalar : f32;
@@ -129,10 +129,10 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// [[block]]
// struct Outer {
// scalar : f32;
// [[align(16)]] inner : Inner;
// @align(16) inner : Inner;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
@@ -154,7 +154,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// Detect unaligned array member for uniform buffers
TEST_F(ResolverStorageClassLayoutValidationTest,
UniformBuffer_UnalignedMember_Array) {
// type Inner = [[stride(16)]] array<f32, 10>;
// type Inner = @stride(16) array<f32, 10>;
//
// [[block]]
// struct Outer {
@@ -162,7 +162,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// inner : Inner;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Alias("Inner", ty.array(ty.f32(), 10, 16));
@@ -179,26 +179,26 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: the offset of a struct member of type '[[stride(16)]] array<f32, 10>' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting [[align(16)]] on this member
R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
12:34 note: see layout of struct:
/* align(4) size(164) */ struct Outer {
/* offset( 0) align(4) size( 4) */ scalar : f32;
/* offset( 4) align(4) size(160) */ inner : [[stride(16)]] array<f32, 10>;
/* offset( 4) align(4) size(160) */ inner : @stride(16) array<f32, 10>;
/* */ };
78:90 note: see declaration of variable)");
}
TEST_F(ResolverStorageClassLayoutValidationTest,
UniformBuffer_UnalignedMember_Array_SuggestedFix) {
// type Inner = [[stride(16)]] array<f32, 10>;
// type Inner = @stride(16) array<f32, 10>;
//
// [[block]]
// struct Outer {
// scalar : f32;
// [[align(16)]] inner : Inner;
// @align(16) inner : Inner;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Alias("Inner", ty.array(ty.f32(), 10, 16));
@@ -221,7 +221,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
TEST_F(ResolverStorageClassLayoutValidationTest,
UniformBuffer_MembersOffsetNotMultipleOf16) {
// struct Inner {
// [[align(1), size(5)]] scalar : i32;
// @align(1) @size(5) scalar : i32;
// };
//
// [[block]]
@@ -230,7 +230,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// scalar : i32;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner",
@@ -249,7 +249,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 8 bytes between 'inner' and 'scalar'. Consider setting [[align(16)]] on this member
R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 8 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
34:56 note: see layout of struct:
/* align(4) size(12) */ struct Outer {
/* offset( 0) align(1) size( 5) */ inner : Inner;
@@ -270,7 +270,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// a : i32;
// b : i32;
// c : i32;
// [[align(1), size(5)]] scalar : i32;
// @align(1) @size(5) scalar : i32;
// };
//
// [[block]]
@@ -279,7 +279,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// scalar : i32;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner",
@@ -303,7 +303,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting [[align(16)]] on this member
R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
34:56 note: see layout of struct:
/* align(4) size(24) */ struct Outer {
/* offset( 0) align(4) size(20) */ inner : Inner;
@@ -323,16 +323,16 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
TEST_F(ResolverStorageClassLayoutValidationTest,
UniformBuffer_MembersOffsetNotMultipleOf16_SuggestedFix) {
// struct Inner {
// [[align(1), size(5)]] scalar : i32;
// @align(1) @size(5) scalar : i32;
// };
//
// [[block]]
// struct Outer {
// [[align(16)]] inner : Inner;
// @align(16) inner : Inner;
// scalar : i32;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Structure(Source{{12, 34}}, "Inner",
@@ -360,7 +360,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// v : vec3<f32>;
// s : f32;
// };
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : ScalarPackedAtEndOfVec3;
Structure("ScalarPackedAtEndOfVec3",
@@ -379,7 +379,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// Detect array stride must be a multiple of 16 bytes for uniform buffers
TEST_F(ResolverStorageClassLayoutValidationTest,
UniformBuffer_InvalidArrayStride) {
// type Inner = [[stride(8)]] array<f32, 10>;
// type Inner = @stride(8) array<f32, 10>;
//
// [[block]]
// struct Outer {
@@ -387,7 +387,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// scalar : i32;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Alias("Inner", ty.array(ty.f32(), 10, 8));
@@ -405,10 +405,10 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array stride of 'inner' is currently 8. Consider setting [[stride(16)]] on the array type
R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array stride of 'inner' is currently 8. Consider setting @stride(16) on the array type
12:34 note: see layout of struct:
/* align(4) size(84) */ struct Outer {
/* offset( 0) align(4) size(80) */ inner : [[stride(8)]] array<f32, 10>;
/* offset( 0) align(4) size(80) */ inner : @stride(8) array<f32, 10>;
/* offset(80) align(4) size( 4) */ scalar : i32;
/* */ };
78:90 note: see declaration of variable)");
@@ -416,7 +416,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
TEST_F(ResolverStorageClassLayoutValidationTest,
UniformBuffer_InvalidArrayStride_SuggestedFix) {
// type Inner = [[stride(16)]] array<f32, 10>;
// type Inner = @stride(16) array<f32, 10>;
//
// [[block]]
// struct Outer {
@@ -424,7 +424,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
// scalar : i32;
// };
//
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var<uniform> a : Outer;
Alias("Inner", ty.array(ty.f32(), 10, 16));

View File

@@ -226,7 +226,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
// [[block]] struct S { m: array<f32>; };
// [[group(0), binding(0)]] var<uniform, > svar : S;
// @group(0) @binding(0) var<uniform, > svar : S;
auto* s = Structure(Source{{12, 34}}, "S", {Member("m", ty.array<i32>())},
{create<ast::StructBlockDecoration>()});

View File

@@ -79,7 +79,7 @@ TEST_F(ResolverTypeValidationTest, VariableDeclNoConstructor_Pass) {
}
TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Pass) {
// [[override(0)]] let a :i32;
// @override(0) let a :i32;
GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr,
ast::DecorationList{create<ast::OverrideDecoration>(0)});
@@ -336,7 +336,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
}
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
// var<private> a : [[stride(8)]] array<f32, 0x20000000>;
// var<private> a : @stride(8) array<f32, 0x20000000>;
Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x20000000, 8),
ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
@@ -396,7 +396,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_InvalidExpr) {
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
/// [[stage(vertex)]]
/// @stage(vertex)
// fn func() { var a : array<i32>; }
auto* var =
@@ -594,7 +594,7 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
// fn func(a : array<u32>) {}
// [[stage(vertex)]] fn main() {}
// @stage(vertex) fn main() {}
auto* param = Param(Source{{12, 34}}, "a", ty.array<i32>());
@@ -855,7 +855,7 @@ static constexpr DimensionParams Dimension_cases[] = {
using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(StorageTextureDimensionTest, All) {
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var a : texture_storage_*<ru32int, write>;
auto& params = GetParam();
@@ -905,13 +905,13 @@ static constexpr FormatParams format_cases[] = {
using StorageTextureFormatTest = ResolverTestWithParam<FormatParams>;
TEST_P(StorageTextureFormatTest, All) {
auto& params = GetParam();
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var a : texture_storage_1d<*, write>;
// [[group(0), binding(1)]]
// @group(0) @binding(1)
// var b : texture_storage_2d<*, write>;
// [[group(0), binding(2)]]
// @group(0) @binding(2)
// var c : texture_storage_2d_array<*, write>;
// [[group(0), binding(3)]]
// @group(0) @binding(3)
// var d : texture_storage_3d<*, write>;
auto* st_a = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
@@ -951,7 +951,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
using StorageTextureAccessTest = ResolverTest;
TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var a : texture_storage_1d<ru32int>;
auto* st =
@@ -967,7 +967,7 @@ TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
}
TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var a : texture_storage_1d<ru32int, read_write>;
auto* st =
@@ -984,7 +984,7 @@ TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
}
TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var a : texture_storage_1d<ru32int, read>;
auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
@@ -1000,7 +1000,7 @@ TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
}
TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
// [[group(0), binding(0)]]
// @group(0) @binding(0)
// var a : texture_storage_1d<ru32int, write>;
auto* st =

View File

@@ -80,7 +80,7 @@ TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInFragmentStage) {
// var<workgroup> dst : vec4<f32>;
// fn f2(){ dst = wg; }
// fn f1() { f2(); }
// [[stage(fragment)]]
// @stage(fragment)
// fn f0() {
// f1();
//}

View File

@@ -288,7 +288,7 @@ TEST_F(ResolverVarLetTest, LetInheritsAccessFromOriginatingVariable) {
// [[block]] struct S {
// inner: Inner;
// }
// [[group(0), binding(0)]] var<storage, read_write> s : S;
// @group(0) @binding(0) var<storage, read_write> s : S;
// fn f() {
// let p = &s.inner.arr[2];
// }

View File

@@ -79,7 +79,7 @@ TEST_F(ResolverVarLetValidationTest, VarTypeNotStorable) {
}
TEST_F(ResolverVarLetValidationTest, LetTypeNotConstructible) {
// [[group(0), binding(0)]] var t1 : texture_2d<f32>;
// @group(0) @binding(0) var t1 : texture_2d<f32>;
// let t2 : t1;
auto* t1 =
Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
@@ -223,7 +223,7 @@ TEST_F(ResolverVarLetValidationTest, InferredPtrStorageAccessMismatch) {
// [[block]] struct S {
// inner: Inner;
// }
// [[group(0), binding(0)]] var<storage> s : S;
// @group(0) @binding(0) var<storage> s : S;
// fn f() {
// let p : pointer<storage, i32, read_write> = &s.inner.arr[2];
// }
@@ -286,7 +286,7 @@ TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Struct_WithAtomic) {
}
TEST_F(ResolverVarLetValidationTest, NonConstructibleType_InferredType) {
// [[group(0), binding(0)]] var s : sampler;
// @group(0) @binding(0) var s : sampler;
// fn foo() {
// var v = s;
// }