[validation] implement the pair of entry point stage and name must be unique

This CL implements the following rule:
v-0020: The pair of <entry point name, pipeline stage> must be unique in the module

Bug: tint: 6
Change-Id: Id0c50438861b251d48a9f8dcb8a23556327c965c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27380
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/validator_function_test.cc b/src/validator_function_test.cc
index 6326f8e..601bc2c 100644
--- a/src/validator_function_test.cc
+++ b/src/validator_function_test.cc
@@ -313,8 +313,7 @@
             "'vtx_func'");
 }
 
-TEST_F(ValidateFunctionTest,
-       DISABLED_EntryPointFunctionPairMustBeUniqueDuplicate_Fail) {
+TEST_F(ValidateFunctionTest, EntryPointFunctionPairMustBeUniqueDuplicate_Fail) {
   // entry_point vertex  = vtx_main
   // entry_point vertex  = vtx_main
   // fn vtx_main() -> void { return; }
@@ -337,11 +336,11 @@
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_FALSE(v()->Validate(mod()));
   EXPECT_EQ(v()->error(),
-            "12:34: v-0020: Entry point and function pair must be unique");
+            "12:34: v-0020: The pair of <entry point name, pipeline stage> "
+            "must be unique");
 }
 
-TEST_F(ValidateFunctionTest,
-       DISABLED_EntryPointFunctionPairMustBeUniqueTowVertex_Fail) {
+TEST_F(ValidateFunctionTest, EntryPointFunctionPairMustBeUniqueTowVertex_Fail) {
   // entry_point vertex as "main" = vtx_func1
   // entry_point vertex as "main" = vtx_func0
   // fn vtx_func1() -> void { return; }
@@ -373,11 +372,12 @@
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_FALSE(v()->Validate(mod()));
   EXPECT_EQ(v()->error(),
-            "12:34: v-0020: Entry point and function pair must be unique");
+            "12:34: v-0020: The pair of <entry point name, pipeline stage> "
+            "must be unique");
 }
 
 TEST_F(ValidateFunctionTest,
-       DISABLED_EntryPointFunctionPairMustBeUniqueSameFuncDiffStage_Pass) {
+       EntryPointFunctionPairMustBeUniqueSameFuncDiffStage_Pass) {
   // entry_point vertex as "main" = vtx_func
   // entry_point fragment as "main" = vtx_func
   // fn vtx_func() -> void { return; }
diff --git a/src/validator_impl.cc b/src/validator_impl.cc
index 968b2c6..9540a00 100644
--- a/src/validator_impl.cc
+++ b/src/validator_impl.cc
@@ -73,6 +73,8 @@
 }
 
 bool ValidatorImpl::ValidateEntryPoints(const ast::EntryPointList& eps) {
+  ScopeStack<ast::PipelineStage> entry_point_map;
+  entry_point_map.push_scope();
   for (const auto& ep : eps) {
     auto* ep_ptr = ep.get();
     if (!function_stack_.has(ep_ptr->function_name())) {
@@ -81,6 +83,7 @@
                     ep_ptr->function_name() + "'");
       return false;
     }
+
     ast::Function* func;
     function_stack_.get(ep_ptr->function_name(), &func);
     if (!func->return_type()->IsVoid()) {
@@ -89,13 +92,27 @@
                     ep_ptr->function_name() + "'");
       return false;
     }
+
     if (func->params().size() != 0) {
       set_error(ep_ptr->source(),
                 "v-0023: Entry point function must accept no parameters: '" +
                     ep_ptr->function_name() + "'");
       return false;
     }
+
+    ast::PipelineStage pipeline_stage;
+    if (entry_point_map.get(ep_ptr->name(), &pipeline_stage)) {
+      if (pipeline_stage == ep_ptr->stage()) {
+        set_error(ep_ptr->source(),
+                  "v-0020: The pair of <entry point name, pipeline stage> must "
+                  "be unique");
+        return false;
+      }
+    }
+    entry_point_map.set(ep_ptr->name(), ep_ptr->stage());
   }
+
+  entry_point_map.pop_scope();
   return true;
 }