public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] resolve: Handle multiple bindings to the same identifier
@ 2023-03-20  7:22 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2023-03-20  7:22 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:bed6308e5e5201f409b041ca5e712d1ed8839195

commit bed6308e5e5201f409b041ca5e712d1ed8839195
Author: Mahmoud Mohamed <mahadelr19@gmail.com>
Date:   Mon Mar 13 17:18:11 2023 +0300

    resolve: Handle multiple bindings to the same identifier
    
    https://github.com/rust-lang/rust/blob/master/compiler/rustc_resolve/src/late.rs#L3168
    This commit follows rustc's implementation of handling multiple bindings
    to the same identifier in parameters.
    
    gcc/rust/ChangeLog:
    
            * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit) :declare and
            pass bindings to PatternDeclaration::go.
            (ResolveExpr::resolve_closure_param): Likewise.
            * resolve/rust-ast-resolve-expr.h: Likewise.
            * resolve/rust-ast-resolve-item.cc (ResolveTraitItems::visit): Likewise.
            (ResolveItem::visit): Likewise.
            * resolve/rust-ast-resolve-pattern.cc (PatternDeclaration::go): Likewise.
            (PatternDeclaration::visit): check for previous identifier bindings
            before inserting the new one.
            * resolve/rust-ast-resolve-pattern.h (enum PatternBoundCtx): New enum.
            * resolve/rust-ast-resolve-stmt.h: pass bindings to PatterDeclaration::go.
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/multiple_bindings1.rs: New test.
    
    Signed-off-by: Mahmoud Mohamed <mahadelr19@gmail.com>

Diff:
---
 gcc/rust/resolve/rust-ast-resolve-expr.cc        | 30 ++++++++--
 gcc/rust/resolve/rust-ast-resolve-expr.h         |  4 +-
 gcc/rust/resolve/rust-ast-resolve-item.cc        | 28 ++++++---
 gcc/rust/resolve/rust-ast-resolve-pattern.cc     | 74 +++++++++++++++++++++++-
 gcc/rust/resolve/rust-ast-resolve-pattern.h      | 60 +++++++++----------
 gcc/rust/resolve/rust-ast-resolve-stmt.h         |  5 +-
 gcc/testsuite/rust/compile/multiple_bindings1.rs | 29 ++++++++++
 7 files changed, 183 insertions(+), 47 deletions(-)

diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 4dfc0833d91..ff9f7ef0cd1 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -207,9 +207,14 @@ ResolveExpr::visit (AST::IfLetExpr &expr)
   resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
   resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
 
+  // FIXME: this declaration should be removed after refactoring
+  // parse_match_arm_patterns output into an AltPattern
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Or, std::set<Identifier> ())};
+
   for (auto &pattern : expr.get_patterns ())
     {
-      PatternDeclaration::go (pattern.get (), Rib::ItemType::Var);
+      PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings);
     }
 
   ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
@@ -517,10 +522,15 @@ ResolveExpr::visit (AST::MatchExpr &expr)
 	ResolveExpr::go (arm.get_guard_expr ().get (), prefix,
 			 canonical_prefix);
 
+      // FIXME: this declaration should be removed after refactoring
+      // parse_match_arms_patterns output into a single AltPattern
+      std::vector<PatternBinding> bindings
+	= {PatternBinding (PatternBoundCtx::Or, std::set<Identifier> ())};
+
       // insert any possible new patterns
       for (auto &pattern : arm.get_patterns ())
 	{
-	  PatternDeclaration::go (pattern.get (), Rib::ItemType::Var);
+	  PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings);
 	}
 
       // resolve the body
@@ -576,9 +586,12 @@ ResolveExpr::visit (AST::ClosureExprInner &expr)
   resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
   resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
 
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
   for (auto &p : expr.get_params ())
     {
-      resolve_closure_param (p);
+      resolve_closure_param (p, bindings);
     }
 
   resolver->push_closure_context (expr.get_node_id ());
@@ -604,9 +617,12 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr)
   resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
   resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
 
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
   for (auto &p : expr.get_params ())
     {
-      resolve_closure_param (p);
+      resolve_closure_param (p, bindings);
     }
 
   ResolveType::go (expr.get_return_type ().get ());
@@ -624,9 +640,11 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr)
 }
 
 void
-ResolveExpr::resolve_closure_param (AST::ClosureParam &param)
+ResolveExpr::resolve_closure_param (AST::ClosureParam &param,
+				    std::vector<PatternBinding> &bindings)
 {
-  PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param);
+  PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param,
+			  bindings);
 
   if (param.has_type_given ())
     ResolveType::go (param.get_type ().get ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 9e3e7750119..07b029fabb3 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -20,6 +20,7 @@
 #define RUST_AST_RESOLVE_EXPR_H
 
 #include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-pattern.h"
 #include "rust-ast-full.h"
 
 namespace Rust {
@@ -79,7 +80,8 @@ public:
   void visit (AST::ClosureExprInnerTyped &expr) override;
 
 protected:
-  void resolve_closure_param (AST::ClosureParam &param);
+  void resolve_closure_param (AST::ClosureParam &param,
+			      std::vector<PatternBinding> &bindings);
 
 private:
   ResolveExpr (const CanonicalPath &prefix,
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index 0be9a02a6f6..958ae49c810 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -77,13 +77,16 @@ ResolveTraitItems::visit (AST::TraitItemFunc &func)
   if (function.has_return_type ())
     ResolveType::go (function.get_return_type ().get ());
 
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
   // we make a new scope so the names of parameters are resolved and shadowed
   // correctly
   for (auto &param : function.get_function_params ())
     {
       ResolveType::go (param.get_type ().get ());
-      PatternDeclaration::go (param.get_pattern ().get (),
-			      Rib::ItemType::Param);
+      PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param,
+			      bindings);
     }
 
   if (function.has_where_clause ())
@@ -141,13 +144,16 @@ ResolveTraitItems::visit (AST::TraitItemMethod &func)
   ResolveType::go (&self_type_path);
   PatternDeclaration::go (&self_pattern, Rib::ItemType::Param);
 
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
   // we make a new scope so the names of parameters are resolved and shadowed
   // correctly
   for (auto &param : function.get_function_params ())
     {
       ResolveType::go (param.get_type ().get ());
-      PatternDeclaration::go (param.get_pattern ().get (),
-			      Rib::ItemType::Param);
+      PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param,
+			      bindings);
     }
 
   if (function.has_where_clause ())
@@ -496,13 +502,16 @@ ResolveItem::visit (AST::Function &function)
   if (function.has_return_type ())
     ResolveType::go (function.get_return_type ().get ());
 
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
   // we make a new scope so the names of parameters are resolved and shadowed
   // correctly
   for (auto &param : function.get_function_params ())
     {
       ResolveType::go (param.get_type ().get ());
-      PatternDeclaration::go (param.get_pattern ().get (),
-			      Rib::ItemType::Param);
+      PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param,
+			      bindings);
     }
 
   // resolve the function body
@@ -633,13 +642,16 @@ ResolveItem::visit (AST::Method &method)
   ResolveType::go (&self_type_path);
   PatternDeclaration::go (&self_pattern, Rib::ItemType::Param);
 
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
   // we make a new scope so the names of parameters are resolved and shadowed
   // correctly
   for (auto &param : method.get_function_params ())
     {
       ResolveType::go (param.get_type ().get ());
-      PatternDeclaration::go (param.get_pattern ().get (),
-			      Rib::ItemType::Param);
+      PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param,
+			      bindings);
     }
 
   // resolve any where clause items
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
index 10f4fd8a61b..866745e098e 100644
--- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
@@ -23,6 +23,78 @@
 namespace Rust {
 namespace Resolver {
 
+void
+PatternDeclaration::go (AST::Pattern *pattern, Rib::ItemType type)
+{
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+  PatternDeclaration resolver (bindings, type);
+  pattern->accept_vis (resolver);
+};
+
+void
+PatternDeclaration::go (AST::Pattern *pattern, Rib::ItemType type,
+			std::vector<PatternBinding> &bindings)
+{
+  PatternDeclaration resolver (bindings, type);
+  pattern->accept_vis (resolver);
+}
+
+void
+PatternDeclaration::visit (AST::IdentifierPattern &pattern)
+{
+  bool has_binding_ctx = bindings.size () > 0;
+  rust_assert (has_binding_ctx);
+
+  auto &binding_idents = bindings.back ().idents;
+
+  bool current_ctx_is_product
+    = bindings.back ().ctx == PatternBoundCtx::Product;
+  bool identifier_is_product_bound
+    = current_ctx_is_product
+      && binding_idents.find (pattern.get_ident ()) != binding_idents.end ();
+
+  if (identifier_is_product_bound)
+    {
+      if (type == Rib::ItemType::Param)
+	{
+	  rust_error_at (pattern.get_locus (), ErrorCode ("E0415"),
+			 "identifier '%s' is bound more than once in the "
+			 "same parameter list",
+			 pattern.get_ident ().c_str ());
+	}
+      else
+	{
+	  rust_error_at (
+	    pattern.get_locus (), ErrorCode ("E0416"),
+	    "identifier '%s' is bound more than once in the same pattern",
+	    pattern.get_ident ().c_str ());
+	}
+
+      return;
+    }
+
+  // if we have a duplicate id this then allows for shadowing correctly
+  // as new refs to this decl will match back here so it is ok to overwrite
+  resolver->get_name_scope ().insert (
+    CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()),
+    pattern.get_node_id (), pattern.get_locus (), type);
+
+  binding_idents.insert (pattern.get_ident ());
+}
+
+void
+PatternDeclaration::visit (AST::GroupedPattern &pattern)
+{
+  pattern.get_pattern_in_parens ()->accept_vis (*this);
+}
+
+void
+PatternDeclaration::visit (AST::ReferencePattern &pattern)
+{
+  pattern.get_referenced_pattern ()->accept_vis (*this);
+}
+
 void
 PatternDeclaration::visit (AST::PathInExpression &pattern)
 {
@@ -49,7 +121,7 @@ PatternDeclaration::visit (AST::TupleStructPattern &pattern)
 
 	for (auto &inner_pattern : items_no_range.get_patterns ())
 	  {
-	    PatternDeclaration::go (inner_pattern.get (), type);
+	    inner_pattern.get ()->accept_vis (*this);
 	  }
       }
       break;
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h
index 12d2b5986e8..0ff500a4d99 100644
--- a/gcc/rust/resolve/rust-ast-resolve-pattern.h
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h
@@ -25,6 +25,26 @@
 namespace Rust {
 namespace Resolver {
 
+// Specifies whether the set of already bound patterns are related by 'Or' or
+// 'Product'. Used to check for multiple bindings to the same identifier.
+enum PatternBoundCtx
+{
+  // A product pattern context (e.g. struct and tuple patterns)
+  Product,
+  // An or-pattern context (e.g. p_0 | p_1 | ...)
+  Or,
+};
+
+struct PatternBinding
+{
+  PatternBoundCtx ctx;
+  std::set<Identifier> idents;
+
+  PatternBinding (PatternBoundCtx ctx, std::set<Identifier> idents)
+    : ctx (ctx), idents (idents)
+  {}
+};
+
 class ResolvePattern : public ResolverBase
 {
   using Rust::Resolver::ResolverBase::visit;
@@ -55,45 +75,25 @@ class PatternDeclaration : public ResolverBase
   using Rust::Resolver::ResolverBase::visit;
 
 public:
-  static void go (AST::Pattern *pattern, Rib::ItemType type)
-  {
-    PatternDeclaration resolver (type);
-    pattern->accept_vis (resolver);
-  };
+  static void go (AST::Pattern *pattern, Rib::ItemType type);
+  static void go (AST::Pattern *pattern, Rib::ItemType type,
+		  std::vector<PatternBinding> &bindings);
 
-  void visit (AST::IdentifierPattern &pattern) override
-  {
-    // if we have a duplicate id this then allows for shadowing correctly
-    // as new refs to this decl will match back here so it is ok to overwrite
-    resolver->get_name_scope ().insert (
-      CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()),
-      pattern.get_node_id (), pattern.get_locus (), type);
-  }
-
-  void visit (AST::GroupedPattern &pattern) override
-  {
-    pattern.get_pattern_in_parens ()->accept_vis (*this);
-  }
-
-  void visit (AST::ReferencePattern &pattern) override
-  {
-    pattern.get_referenced_pattern ()->accept_vis (*this);
-  }
-
-  // cases in a match expression
+  void visit (AST::IdentifierPattern &pattern) override;
+  void visit (AST::GroupedPattern &pattern) override;
+  void visit (AST::ReferencePattern &pattern) override;
   void visit (AST::PathInExpression &pattern) override;
-
   void visit (AST::StructPattern &pattern) override;
-
   void visit (AST::TupleStructPattern &pattern) override;
-
   void visit (AST::TuplePattern &pattern) override;
-
   void visit (AST::RangePattern &pattern) override;
 
 private:
-  PatternDeclaration (Rib::ItemType type) : ResolverBase (), type (type) {}
+  PatternDeclaration (std::vector<PatternBinding> &bindings, Rib::ItemType type)
+    : ResolverBase (), bindings (bindings), type (type)
+  {}
 
+  std::vector<PatternBinding> &bindings;
   Rib::ItemType type;
 };
 
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 28c547f410b..1336402d43e 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -344,13 +344,16 @@ public:
     if (function.has_return_type ())
       ResolveType::go (function.get_return_type ().get ());
 
+    std::vector<PatternBinding> bindings
+      = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
     // we make a new scope so the names of parameters are resolved and shadowed
     // correctly
     for (auto &param : function.get_function_params ())
       {
 	ResolveType::go (param.get_type ().get ());
 	PatternDeclaration::go (param.get_pattern ().get (),
-				Rib::ItemType::Param);
+				Rib::ItemType::Param, bindings);
       }
 
     // resolve the function body
diff --git a/gcc/testsuite/rust/compile/multiple_bindings1.rs b/gcc/testsuite/rust/compile/multiple_bindings1.rs
new file mode 100644
index 00000000000..e73dc2ae7d9
--- /dev/null
+++ b/gcc/testsuite/rust/compile/multiple_bindings1.rs
@@ -0,0 +1,29 @@
+fn f1(i: i32, i: i32) {}
+// { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+
+trait Foo {
+  fn f2(i: i32, i: i32) {}
+  // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+
+trait Bar {
+  fn f3(i: i32, j: i32) {}
+}
+
+struct S;
+
+impl S {
+  fn f4(i: i32, i: i32) {}
+  // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+
+impl Bar for S {
+  fn f3(i: i32, i: i32) {}
+  // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+
+fn main() {
+  let _ = |i, i| {};
+  // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-03-20  7:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-20  7:22 [gcc/devel/rust/master] resolve: Handle multiple bindings to the same identifier Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).