[tint][wgsl] Add `Requires` AST node

This corresponds to the `requires` directive.

Bug: tint:2088
Change-Id: Ied437b6131b9e85eee7daed83d3d958cc063a36e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/158625
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/wgsl/ast/BUILD.bazel b/src/tint/lang/wgsl/ast/BUILD.bazel
index eabb9ca..bc6462d 100644
--- a/src/tint/lang/wgsl/ast/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/BUILD.bazel
@@ -97,6 +97,7 @@
     "parameter.cc",
     "phony_expression.cc",
     "pipeline_stage.cc",
+    "requires.cc",
     "return_statement.cc",
     "stage_attribute.cc",
     "statement.cc",
@@ -177,6 +178,7 @@
     "parameter.h",
     "phony_expression.h",
     "pipeline_stage.h",
+    "requires.h",
     "return_statement.h",
     "stage_attribute.h",
     "statement.h",
@@ -271,6 +273,7 @@
     "member_accessor_expression_test.cc",
     "module_test.cc",
     "phony_expression_test.cc",
+    "requires_test.cc",
     "return_statement_test.cc",
     "stage_attribute_test.cc",
     "stride_attribute_test.cc",
diff --git a/src/tint/lang/wgsl/ast/BUILD.cmake b/src/tint/lang/wgsl/ast/BUILD.cmake
index e72ea46..e35a8b1 100644
--- a/src/tint/lang/wgsl/ast/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/BUILD.cmake
@@ -158,6 +158,8 @@
   lang/wgsl/ast/phony_expression.h
   lang/wgsl/ast/pipeline_stage.cc
   lang/wgsl/ast/pipeline_stage.h
+  lang/wgsl/ast/requires.cc
+  lang/wgsl/ast/requires.h
   lang/wgsl/ast/return_statement.cc
   lang/wgsl/ast/return_statement.h
   lang/wgsl/ast/stage_attribute.cc
@@ -271,6 +273,7 @@
   lang/wgsl/ast/member_accessor_expression_test.cc
   lang/wgsl/ast/module_test.cc
   lang/wgsl/ast/phony_expression_test.cc
+  lang/wgsl/ast/requires_test.cc
   lang/wgsl/ast/return_statement_test.cc
   lang/wgsl/ast/stage_attribute_test.cc
   lang/wgsl/ast/stride_attribute_test.cc
diff --git a/src/tint/lang/wgsl/ast/BUILD.gn b/src/tint/lang/wgsl/ast/BUILD.gn
index e440921..9c36fd0 100644
--- a/src/tint/lang/wgsl/ast/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/BUILD.gn
@@ -161,6 +161,8 @@
     "phony_expression.h",
     "pipeline_stage.cc",
     "pipeline_stage.h",
+    "requires.cc",
+    "requires.h",
     "return_statement.cc",
     "return_statement.h",
     "stage_attribute.cc",
@@ -271,6 +273,7 @@
       "member_accessor_expression_test.cc",
       "module_test.cc",
       "phony_expression_test.cc",
+      "requires_test.cc",
       "return_statement_test.cc",
       "stage_attribute_test.cc",
       "stride_attribute_test.cc",
diff --git a/src/tint/lang/wgsl/ast/builder.h b/src/tint/lang/wgsl/ast/builder.h
index bab8fb9..1cbdfba 100644
--- a/src/tint/lang/wgsl/ast/builder.h
+++ b/src/tint/lang/wgsl/ast/builder.h
@@ -97,6 +97,7 @@
 #include "src/tint/lang/wgsl/ast/override.h"
 #include "src/tint/lang/wgsl/ast/parameter.h"
 #include "src/tint/lang/wgsl/ast/phony_expression.h"
+#include "src/tint/lang/wgsl/ast/requires.h"
 #include "src/tint/lang/wgsl/ast/return_statement.h"
 #include "src/tint/lang/wgsl/ast/stage_attribute.h"
 #include "src/tint/lang/wgsl/ast/stride_attribute.h"
@@ -1617,6 +1618,25 @@
         return enable;
     }
 
+    /// Adds the language feature to the list of requires directives at the top of the module.
+    /// @param feature the feature to require
+    /// @return a `ast::Requires` requiring the given language feature.
+    const ast::Requires* Require(wgsl::LanguageFeature feature) {
+        auto* req = create<ast::Requires>(wgsl::LanguageFeatures({feature}));
+        AST().AddRequires(req);
+        return req;
+    }
+
+    /// Adds the language feature to the list of requires directives at the top of the module.
+    /// @param source the requires source
+    /// @param feature the feature to require
+    /// @return a `ast::Requires` requiring the given language feature.
+    const ast::Requires* Require(const Source& source, wgsl::LanguageFeature feature) {
+        auto* req = create<ast::Requires>(source, wgsl::LanguageFeatures({feature}));
+        AST().AddRequires(req);
+        return req;
+    }
+
     /// @param name the variable name
     /// @param options the extra options passed to the ast::Var initializer
     /// Can be any of the following, in any order:
diff --git a/src/tint/lang/wgsl/ast/module.cc b/src/tint/lang/wgsl/ast/module.cc
index 3ee8cfd..974abad 100644
--- a/src/tint/lang/wgsl/ast/module.cc
+++ b/src/tint/lang/wgsl/ast/module.cc
@@ -89,6 +89,10 @@
             TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(enable, generation_id);
             enables_.Push(enable);
         },
+        [&](const ast::Requires* req) {
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(req, generation_id);
+            requires_.Push(req);
+        },
         [&](const ConstAssert* assertion) {
             TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(assertion, generation_id);
             const_asserts_.Push(assertion);
@@ -110,6 +114,13 @@
     enables_.Push(enable);
 }
 
+void Module::AddRequires(const ast::Requires* req) {
+    TINT_ASSERT(req);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(req, generation_id);
+    global_declarations_.Push(req);
+    requires_.Push(req);
+}
+
 void Module::AddGlobalVariable(const Variable* var) {
     TINT_ASSERT(var);
     TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(var, generation_id);
diff --git a/src/tint/lang/wgsl/ast/module.h b/src/tint/lang/wgsl/ast/module.h
index 7214aec..8513348 100644
--- a/src/tint/lang/wgsl/ast/module.h
+++ b/src/tint/lang/wgsl/ast/module.h
@@ -34,6 +34,7 @@
 #include "src/tint/lang/wgsl/ast/diagnostic_directive.h"
 #include "src/tint/lang/wgsl/ast/enable.h"
 #include "src/tint/lang/wgsl/ast/function.h"
+#include "src/tint/lang/wgsl/ast/requires.h"
 #include "src/tint/utils/containers/vector.h"
 
 namespace tint::ast {
@@ -110,12 +111,19 @@
     /// @param ext the enable directive to add
     void AddEnable(const Enable* ext);
 
+    /// Add a requires directive to the module
+    /// @param req the requires directive to add
+    void AddRequires(const Requires* req);
+
     /// @returns the diagnostic directives for the module
     const auto& DiagnosticDirectives() const { return diagnostic_directives_; }
 
     /// @returns the extension set for the module
     const auto& Enables() const { return enables_; }
 
+    /// @returns the requires directives for the module
+    const auto& Requires() const { return requires_; }
+
     /// Add a global const assertion to the module
     /// @param assertion the const assert to add
     void AddConstAssert(const ConstAssert* assertion);
@@ -168,6 +176,7 @@
     tint::Vector<const Variable*, 32> global_variables_;
     tint::Vector<const DiagnosticDirective*, 8> diagnostic_directives_;
     tint::Vector<const Enable*, 8> enables_;
+    tint::Vector<const ast::Requires*, 8> requires_;
     tint::Vector<const ConstAssert*, 8> const_asserts_;
 };
 
diff --git a/src/tint/lang/wgsl/ast/requires.cc b/src/tint/lang/wgsl/ast/requires.cc
new file mode 100644
index 0000000..059c35f
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/requires.cc
@@ -0,0 +1,47 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/ast/requires.h"
+
+#include "src/tint/lang/wgsl/ast/builder.h"
+#include "src/tint/lang/wgsl/ast/clone_context.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Requires);
+
+namespace tint::ast {
+
+Requires::Requires(GenerationID pid, NodeID nid, const Source& src, wgsl::LanguageFeatures feats)
+    : Base(pid, nid, src), features(std::move(feats)) {}
+
+Requires::~Requires() = default;
+
+const Requires* Requires::Clone(CloneContext& ctx) const {
+    auto src = ctx.Clone(source);
+    return ctx.dst->create<Requires>(src, features);
+}
+
+}  // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/requires.h b/src/tint/lang/wgsl/ast/requires.h
new file mode 100644
index 0000000..c94d6b0
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/requires.h
@@ -0,0 +1,68 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_AST_REQUIRES_H_
+#define SRC_TINT_LANG_WGSL_AST_REQUIRES_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/tint/lang/wgsl/ast/node.h"
+#include "src/tint/lang/wgsl/language_feature.h"
+
+namespace tint::ast {
+
+/// A "requires" directive. Example:
+/// ```
+///   // Require a language feature named "foo"
+///   requires foo;
+/// ```
+class Requires final : public Castable<Requires, Node> {
+  public:
+    /// Create a requires directive
+    /// @param pid the identifier of the program that owns this node
+    /// @param nid the unique node identifier
+    /// @param src the source of this node
+    /// @param feats the language features being required by this directive
+    Requires(GenerationID pid, NodeID nid, const Source& src, wgsl::LanguageFeatures feats);
+
+    /// Destructor
+    ~Requires() override;
+
+    /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const Requires* Clone(CloneContext& ctx) const override;
+
+    /// The features being required by this directive.
+    const wgsl::LanguageFeatures features;
+};
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_LANG_WGSL_AST_REQUIRES_H_
diff --git a/src/tint/lang/wgsl/ast/requires_test.cc b/src/tint/lang/wgsl/ast/requires_test.cc
new file mode 100644
index 0000000..8650f3f
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/requires_test.cc
@@ -0,0 +1,51 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/ast/requires.h"
+
+#include "src/tint/lang/wgsl/ast/helper_test.h"
+
+namespace tint::ast {
+namespace {
+
+using RequiresTest = TestHelper;
+
+TEST_F(RequiresTest, Creation) {
+    auto* req = Require(Source{{{20, 2}, {20, 5}}},
+                        wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures);
+    EXPECT_EQ(req->source.range.begin.line, 20u);
+    EXPECT_EQ(req->source.range.begin.column, 2u);
+    EXPECT_EQ(req->source.range.end.line, 20u);
+    EXPECT_EQ(req->source.range.end.column, 5u);
+    ASSERT_EQ(req->features.Length(), 1u);
+    EXPECT_EQ(req->features[0], wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures);
+    ASSERT_EQ(AST().Requires().Length(), 1u);
+    EXPECT_EQ(AST().Requires()[0], req);
+}
+
+}  // namespace
+}  // namespace tint::ast