Resolver: Validate resource binding decorations

Validate that:
* That resource variables have resource bindings
* Only resource variables have resource bindings
* That a [[binding]] decoration is paired with a [[group]]
* That binding points are not reused in the same entry point

Fixed: tint:235
Fixed: tint:645
Bug: tint:645
Change-Id: I2542934b4c6a2b4bbde48242932c04c796033a90
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50500
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/resolver/storage_class_validation_test.cc b/src/resolver/storage_class_validation_test.cc
index 9c36597..0db6410 100644
--- a/src/resolver/storage_class_validation_test.cc
+++ b/src/resolver/storage_class_validation_test.cc
@@ -36,8 +36,12 @@
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
-  // var<storage> g : bool;
-  Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kStorage);
+  // var<storage> g : i32;
+  Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -49,7 +53,11 @@
 TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
   // var<storage> g : ptr<i32, input>;
   Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput),
-         ast::StorageClass::kStorage);
+         ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -63,7 +71,11 @@
   auto* s = Structure("S", {Member("a", ty.f32())});
   auto* a = ty.array(s, 3);
   auto ac = ty.access(ast::AccessControl::kReadOnly, a);
-  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage);
+  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -77,7 +89,11 @@
   // var<storage> g : [[access(read)]] a;
   auto* a = ty.alias("a", ty.bool_());
   AST().AddConstructedType(a);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -89,7 +105,11 @@
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
   // var<storage> g : S;
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage);
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -103,7 +123,11 @@
   // var<storage> g : [[access(read)]] S;
   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
   auto a = ty.access(ast::AccessControl::kReadOnly, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -119,7 +143,11 @@
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
   auto a = ty.access(ast::AccessControl::kReadOnly, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_TRUE(r()->Resolve());
 }
@@ -136,7 +164,11 @@
   auto ac = ty.access(ast::AccessControl::kReadOnly, a1);
   auto* a2 = ty.alias("a2", ac);
   AST().AddConstructedType(a2);
-  Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage);
+  Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_TRUE(r()->Resolve());
 }
@@ -145,7 +177,12 @@
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
   // var<uniform> g : bool;
-  Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform);
+  Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
+         nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -157,7 +194,11 @@
 TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
   // var<uniform> g : ptr<i32, input>;
   Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput),
-         ast::StorageClass::kUniform);
+         ast::StorageClass::kUniform, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -171,7 +212,11 @@
   auto* s = Structure("S", {Member("a", ty.f32())});
   auto* a = ty.array(s, 3);
   auto ac = ty.access(ast::AccessControl::kReadOnly, a);
-  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform);
+  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -185,7 +230,11 @@
   // var<uniform> g : [[access(read)]] a;
   auto* a = ty.alias("a", ty.bool_());
   AST().AddConstructedType(a);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform);
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -198,7 +247,11 @@
   // struct S { x : i32 };
   // var<uniform> g : S;
   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_FALSE(r()->Resolve());
 
@@ -213,7 +266,11 @@
   // var<uniform> g :  S;
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_TRUE(r()->Resolve());
 }
@@ -226,7 +283,11 @@
                       {create<ast::StructBlockDecoration>()});
   auto* a1 = ty.alias("a1", s);
   AST().AddConstructedType(a1);
-  Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform);
+  Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform, nullptr,
+         {
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   ASSERT_TRUE(r()->Resolve());
 }