validation: cleaning up name uniqueness rules

Bug: tint:353
Change-Id: I01e5b63937e218d7c42e41f7c0e9a7910aacaa90
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56320
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: Sarah Mashayekhi <sarahmashay@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/resolver/function_validation_test.cc b/src/resolver/function_validation_test.cc
index 5d55377..9e03a47 100644
--- a/src/resolver/function_validation_test.cc
+++ b/src/resolver/function_validation_test.cc
@@ -42,8 +42,8 @@
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
-            R"(12:34 error: duplicate function named 'func'
-note: first function declared here)");
+            "12:34 error: redefinition of 'func'\nnote: previous definition "
+            "is here");
 }
 
 TEST_F(ResolverFunctionValidationTest,
@@ -74,8 +74,8 @@
 
   EXPECT_FALSE(r()->Resolve()) << r()->error();
   EXPECT_EQ(r()->error(),
-            "12:34 error: duplicate declaration 'foo'\n56:78 note: 'foo' first "
-            "declared here:");
+            "12:34 error: redefinition of 'foo'\n56:78 note: previous "
+            "definition is here");
 }
 
 TEST_F(ResolverFunctionValidationTest,
@@ -85,14 +85,14 @@
 
   Func(Source{Source::Location{12, 34}}, "foo", ast::VariableList{}, ty.void_(),
        ast::StatementList{}, ast::DecorationList{});
-  auto* global_var =
-      Var("foo", ty.f32(), ast::StorageClass::kPrivate, Expr(3.14f));
+  auto* global_var = Var(Source{Source::Location{56, 78}}, "foo", ty.f32(),
+                         ast::StorageClass::kPrivate, Expr(3.14f));
   AST().AddGlobalVariable(global_var);
 
   EXPECT_FALSE(r()->Resolve()) << r()->error();
   EXPECT_EQ(r()->error(),
-            "error: duplicate declaration 'foo'\n12:34 note: 'foo' first "
-            "declared here:");
+            "56:78 error: redefinition of 'foo'\n12:34 note: previous "
+            "definition is here");
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionUsingSameVariableName_Pass) {
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index c9876d3..75560d0 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -615,10 +615,8 @@
 }
 
 bool Resolver::GlobalVariable(ast::Variable* var) {
-  if (variable_stack_.has(var->symbol())) {
-    AddError("redeclared global identifier '" +
-                 builder_->Symbols().NameFor(var->symbol()) + "'",
-             var->source());
+  if (!ValidateNoDuplicateDefinition(var->symbol(), var->source(),
+                                     /* check_global_scope_only */ true)) {
     return false;
   }
 
@@ -673,17 +671,6 @@
 }
 
 bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
-  auto duplicate_func = symbol_to_function_.find(info->declaration->symbol());
-  if (duplicate_func != symbol_to_function_.end()) {
-    AddError("duplicate declaration '" +
-                 builder_->Symbols().NameFor(info->declaration->symbol()) + "'",
-             info->declaration->source());
-    AddNote("'" + builder_->Symbols().NameFor(info->declaration->symbol()) +
-                "' first declared here:",
-            duplicate_func->second->declaration->source());
-    return false;
-  }
-
   if (!ValidateNoDuplicateDecorations(info->declaration->decorations())) {
     return false;
   }
@@ -1063,30 +1050,11 @@
 
 bool Resolver::ValidateFunction(const ast::Function* func,
                                 const FunctionInfo* info) {
-  auto func_it = symbol_to_function_.find(func->symbol());
-  if (func_it != symbol_to_function_.end()) {
-    AddError("duplicate function named '" +
-                 builder_->Symbols().NameFor(func->symbol()) + "'",
-             func->source());
-    AddNote("first function declared here",
-            func_it->second->declaration->source());
+  if (!ValidateNoDuplicateDefinition(func->symbol(), func->source(),
+                                     /* check_global_scope_only */ true)) {
     return false;
   }
 
-  bool is_global = false;
-  VariableInfo* var;
-  if (variable_stack_.get(func->symbol(), &var, &is_global)) {
-    if (is_global) {
-      AddError("duplicate declaration '" +
-                   builder_->Symbols().NameFor(func->symbol()) + "'",
-               func->source());
-      AddNote("'" + builder_->Symbols().NameFor(func->symbol()) +
-                  "' first declared here:",
-              var->declaration->source());
-      return false;
-    }
-  }
-
   auto stage_deco_count = 0;
   auto workgroup_deco_count = 0;
   for (auto* deco : func->decorations()) {
@@ -2857,11 +2825,7 @@
   ast::Variable* var = stmt->variable();
   Mark(var);
 
-  bool is_global = false;
-  if (variable_stack_.get(var->symbol(), nullptr, &is_global)) {
-    AddError("redeclared identifier '" +
-                 builder_->Symbols().NameFor(var->symbol()) + "'",
-             var->source());
+  if (!ValidateNoDuplicateDefinition(var->symbol(), var->source())) {
     return false;
   }
 
@@ -3772,6 +3736,39 @@
   return true;
 }
 
+bool Resolver::ValidateNoDuplicateDefinition(Symbol sym,
+                                             const Source& source,
+                                             bool check_global_scope_only) {
+  if (check_global_scope_only) {
+    bool is_global = false;
+    VariableInfo* var;
+    if (variable_stack_.get(sym, &var, &is_global)) {
+      if (is_global) {
+        AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
+                 source);
+        AddNote("previous definition is here", var->declaration->source());
+        return false;
+      }
+    }
+    auto it = symbol_to_function_.find(sym);
+    if (it != symbol_to_function_.end()) {
+      AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
+               source);
+      AddNote("previous definition is here", it->second->declaration->source());
+      return false;
+    }
+  } else {
+    VariableInfo* var;
+    if (variable_stack_.get(sym, &var)) {
+      AddError("redefinition of '" + builder_->Symbols().NameFor(sym) + "'",
+               source);
+      AddNote("previous definition is here", var->declaration->source());
+      return false;
+    }
+  }
+  return true;
+}
+
 bool Resolver::ValidateNoDuplicateDecorations(
     const ast::DecorationList& decorations) {
   std::unordered_map<const TypeInfo*, Source> seen;
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index 8eb2ed2..f1d663d 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -283,6 +283,10 @@
                                  const sem::Matrix* matrix_type);
   bool ValidateFunctionParameter(const ast::Function* func,
                                  const VariableInfo* info);
+  bool ValidateNoDuplicateDefinition(Symbol sym,
+                                     const Source& source,
+                                     bool check_global_scope_only = false);
+  bool ValidateParameter(const ast::Function* func, const VariableInfo* info);
   bool ValidateReturn(const ast::ReturnStatement* ret);
   bool ValidateStatements(const ast::StatementList& stmts);
   bool ValidateStorageTexture(const ast::StorageTexture* t);
diff --git a/src/resolver/var_let_validation_test.cc b/src/resolver/var_let_validation_test.cc
index e03e6e7..959b2ca 100644
--- a/src/resolver/var_let_validation_test.cc
+++ b/src/resolver/var_let_validation_test.cc
@@ -124,7 +124,9 @@
   WrapInFunction(v1, v2);
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: redeclared identifier 'v'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'v'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, LocalLetRedeclared) {
@@ -135,7 +137,9 @@
   WrapInFunction(l1, l2);
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: redeclared identifier 'l'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'l'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, GlobalVarRedeclared) {
@@ -145,8 +149,9 @@
   Global(Source{{12, 34}}, "v", ty.i32(), ast::StorageClass::kPrivate);
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: redeclared global identifier 'v'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'v'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, GlobalLetRedeclared) {
@@ -156,8 +161,9 @@
   GlobalConst(Source{{12, 34}}, "l", ty.i32(), Expr(0));
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: redeclared global identifier 'l'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'l'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, GlobalVarRedeclaredAsLocal) {
@@ -173,7 +179,9 @@
                      Expr(2.0f)));
 
   EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 error: redeclared identifier 'v'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'v'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, VarRedeclaredInInnerBlock) {
@@ -190,7 +198,9 @@
   WrapInFunction(outer_body);
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: redeclared identifier 'v'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'v'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, VarRedeclaredInIfBlock) {
@@ -213,7 +223,9 @@
   WrapInFunction(outer_body);
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: redeclared identifier 'v'");
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: redefinition of 'v'\nnote: previous definition is here");
 }
 
 TEST_F(ResolverVarLetValidationTest, InferredPtrStorageAccessMismatch) {