From: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>

Binding context may be stacked when a new binding group is introduced
within a const expression.

gcc/rust/ChangeLog:

        * resolve/rust-name-resolution-context.h: Use BindingLayer instead.
        * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer):
        Add new constructor for binding layer.
        (BindingLayer::bind_test): Add a function to test a binding constraint.
        (BindingLayer::push): Push a new binding group.
        (BindingLayer::and_binded): Add function to test and-binding
        constraint.
        (BindingLayer::or_binded): Add function to test or-binding constraints.
        (BindingLayer::insert_ident): Insert a new identifier in the current
        binding group.
        (BindingLayer::merge): Merge current binding group with it's parent.
        (BindingLayer::get_source): Get the source of the current binding
        group.
        * resolve/rust-late-name-resolver-2.0.cc: Use stacked context for
        binding group.
        * util/rust-stacked-contexts.h: Add mutable peek function.

Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>
---
 .../resolve/rust-late-name-resolver-2.0.cc    | 44 ++++++------
 .../resolve/rust-name-resolution-context.cc   | 59 +++++++++++++++
 .../resolve/rust-name-resolution-context.h    | 72 +++++++------------
 gcc/rust/util/rust-stacked-contexts.h         |  9 ++-
 4 files changed, 113 insertions(+), 71 deletions(-)

diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index 1ecf48152d8..e26e4187b28 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -133,11 +133,11 @@ Late::visit (AST::ForLoopExpr &expr)
 {
   visit_outer_attrs (expr);
 
-  ctx.bindings.new_binding (BindingSource::For);
+  ctx.bindings.enter (BindingSource::For);
 
   visit (expr.get_pattern ());
 
-  ctx.bindings.clear ();
+  ctx.bindings.exit ();
 
   visit (expr.get_iterator_expr ());
   visit (expr.get_loop_label ());
@@ -149,12 +149,12 @@ Late::visit (AST::IfLetExpr &expr)
 {
   visit_outer_attrs (expr);
 
-  ctx.bindings.new_binding (BindingSource::Let);
+  ctx.bindings.enter (BindingSource::Let);
 
   for (auto &pattern : expr.get_patterns ())
     visit (pattern);
 
-  ctx.bindings.clear ();
+  ctx.bindings.exit ();
 
   visit (expr.get_value_expr ());
   visit (expr.get_if_block ());
@@ -165,12 +165,12 @@ Late::visit (AST::MatchArm &arm)
 {
   visit_outer_attrs (arm);
 
-  ctx.bindings.new_binding (BindingSource::Match);
+  ctx.bindings.enter (BindingSource::Match);
 
   for (auto &pattern : arm.get_patterns ())
     visit (pattern);
 
-  ctx.bindings.clear ();
+  ctx.bindings.exit ();
 
   if (arm.has_match_arm_guard ())
     visit (arm.get_guard_expr ());
@@ -187,11 +187,11 @@ Late::visit (AST::LetStmt &let)
   if (let.has_init_expr ())
     visit (let.get_init_expr ());
 
-  ctx.bindings.new_binding (BindingSource::Let);
+  ctx.bindings.enter (BindingSource::Let);
 
   visit (let.get_pattern ());
 
-  ctx.bindings.clear ();
+  ctx.bindings.exit ();
 
   if (let.has_else_expr ())
     visit (let.get_init_expr ());
@@ -220,9 +220,9 @@ Late::visit (AST::IdentifierPattern &identifier)
   // but values does not allow shadowing... since functions cannot shadow
   // do we insert functions in labels as well?
 
-  if (ctx.bindings.and_binded (identifier.get_ident ()))
+  if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ()))
     {
-      if (ctx.bindings.get_source () == BindingSource::Param)
+      if (ctx.bindings.peek ().get_source () == BindingSource::Param)
        rust_error_at (
          identifier.get_locus (), ErrorCode::E0415,
          "identifier %qs is bound more than once in the same parameter list",
@@ -235,9 +235,9 @@ Late::visit (AST::IdentifierPattern &identifier)
       return;
     }
 
-  ctx.bindings.insert_ident (identifier.get_ident ());
+  ctx.bindings.peek ().insert_ident (identifier.get_ident ());
 
-  if (ctx.bindings.or_binded (identifier.get_ident ()))
+  if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ()))
     {
       // FIXME: map usage instead
       std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
@@ -255,14 +255,14 @@ Late::visit (AST::IdentifierPattern &identifier)
 void
 Late::visit (AST::AltPattern &pattern)
 {
-  ctx.bindings.push (Binding::Kind::Or);
+  ctx.bindings.peek ().push (Binding::Kind::Or);
   for (auto &alt : pattern.get_alts ())
     {
-      ctx.bindings.push (Binding::Kind::Product);
+      ctx.bindings.peek ().push (Binding::Kind::Product);
       visit (alt);
-      ctx.bindings.merge ();
+      ctx.bindings.peek ().merge ();
     }
-  ctx.bindings.merge ();
+  ctx.bindings.peek ().merge ();
 }
 
 void
@@ -276,12 +276,12 @@ Late::visit (AST::Function &function)
       visit (generic);
 
     // We only care about params
-    ctx.bindings.new_binding (BindingSource::Param);
+    ctx.bindings.enter (BindingSource::Param);
 
     for (auto &param : function.get_function_params ())
       visit (param);
 
-    ctx.bindings.clear ();
+    ctx.bindings.exit ();
 
     // Back to regular visit
 
@@ -652,12 +652,12 @@ Late::visit (AST::ClosureExprInner &closure)
 
   visit_outer_attrs (closure);
 
-  ctx.bindings.new_binding (BindingSource::Param);
+  ctx.bindings.enter (BindingSource::Param);
 
   for (auto &param : closure.get_params ())
     visit (param);
 
-  ctx.bindings.clear ();
+  ctx.bindings.exit ();
 
   visit (closure.get_definition_expr ());
 }
@@ -669,12 +669,12 @@ Late::visit (AST::ClosureExprInnerTyped &closure)
 
   visit_outer_attrs (closure);
 
-  ctx.bindings.new_binding (BindingSource::Param);
+  ctx.bindings.enter (BindingSource::Param);
 
   for (auto &param : closure.get_params ())
     visit (param);
 
-  ctx.bindings.clear ();
+  ctx.bindings.exit ();
 
   visit (closure.get_return_type ());
   visit (closure.get_definition_block ());
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc 
b/gcc/rust/resolve/rust-name-resolution-context.cc
index 92c48633e56..f098e4880e5 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -23,6 +23,65 @@
 namespace Rust {
 namespace Resolver2_0 {
 
+BindingLayer::BindingLayer (BindingSource source) : source (source)
+{
+  push (Binding::Kind::Product);
+}
+
+bool
+BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
+{
+  for (auto &bind : bindings)
+    {
+      if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
+       {
+         return true;
+       }
+    }
+  return false;
+}
+
+void
+BindingLayer::push (Binding::Kind kind)
+{
+  bindings.push_back (Binding (kind));
+}
+
+bool
+BindingLayer::is_and_bound (Identifier ident)
+{
+  return bind_test (ident, Binding::Kind::Product);
+}
+
+bool
+BindingLayer::is_or_bound (Identifier ident)
+{
+  return bind_test (ident, Binding::Kind::Or);
+}
+
+void
+BindingLayer::insert_ident (Identifier ident)
+{
+  bindings.back ().set.insert (ident);
+}
+
+void
+BindingLayer::merge ()
+{
+  auto last_binding = bindings.back ();
+  bindings.pop_back ();
+  for (auto &value : last_binding.set)
+    {
+      bindings.back ().set.insert (value);
+    }
+}
+
+BindingSource
+BindingLayer::get_source () const
+{
+  return source;
+}
+
 NameResolutionContext::NameResolutionContext ()
   : mappings (Analysis::Mappings::get ())
 {}
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h 
b/gcc/rust/resolve/rust-name-resolution-context.h
index 657d1512fe8..19ba7507686 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -23,6 +23,7 @@
 #include "rust-forever-stack.h"
 #include "rust-hir-map.h"
 #include "rust-rib.h"
+#include "rust-stacked-contexts.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -169,72 +170,47 @@ struct Binding
   Binding (Binding::Kind kind) : kind (kind) {}
 };
 
+/**
+ * Used to identify the source of a binding, and emit the correct error 
message.
+ */
 enum class BindingSource
 {
   Match,
   Let,
   For,
+  /* Closure param or function param */
   Param
 };
 
-class BindingContext
+class BindingLayer
 {
-  // FIXME: Use std::vector<std::vector<Binding>> to handle nested patterns
-  std::vector<Binding> bindings;
-
   BindingSource source;
+  std::vector<Binding> bindings;
 
-  bool bind_test (Identifier ident, Binding::Kind kind)
-  {
-    for (auto &bind : bindings)
-      {
-       if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
-         {
-           return true;
-         }
-      }
-    return false;
-  }
+  bool bind_test (Identifier ident, Binding::Kind kind);
 
 public:
-  bool and_binded (Identifier ident)
-  {
-    return bind_test (ident, Binding::Kind::Product);
-  }
+  void push (Binding::Kind kind);
 
-  bool or_binded (Identifier ident)
-  {
-    return bind_test (ident, Binding::Kind::Or);
-  }
+  BindingLayer (BindingSource source);
 
-  void insert_ident (Identifier ident) { bindings.back ().set.insert (ident); }
+  /**
+   * Identifies if the identifier has been used in a product binding context.
+   * eg. `let (a, a) = test();`
+   */
+  bool is_and_bound (Identifier ident);
 
-  void push (Binding::Kind kind) { bindings.push_back (Binding (kind)); }
+  /**
+   * Identifies if the identifier has been used in a or context.
+   * eg. `let (a, 1) | (a, 2) = test()`
+   */
+  bool is_or_bound (Identifier ident);
 
-  void new_binding (BindingSource source)
-  {
-    rust_assert (bindings.size () == 0);
-    this->source = source;
-    push (Binding::Kind::Product);
-  }
+  void insert_ident (Identifier ident);
 
-  void clear ()
-  {
-    rust_assert (bindings.size () == 1);
-    bindings.clear ();
-  }
-
-  void merge ()
-  {
-    auto last_binding = bindings.back ();
-    bindings.pop_back ();
-    for (auto &value : last_binding.set)
-      {
-       bindings.back ().set.insert (value);
-      }
-  }
+  void merge ();
 
-  BindingSource get_source () const { return source; }
+  BindingSource get_source () const;
 };
 
 // Now our resolver, which keeps track of all the `ForeverStack`s we could want
@@ -293,7 +269,7 @@ public:
   ForeverStack<Namespace::Labels> labels;
 
   Analysis::Mappings &mappings;
-  BindingContext bindings;
+  StackedContexts<BindingLayer> bindings;
 
   // TODO: Rename
   // TODO: Use newtype pattern for Usage and Definition
diff --git a/gcc/rust/util/rust-stacked-contexts.h 
b/gcc/rust/util/rust-stacked-contexts.h
index fe0bc8a291b..b263d75d2d5 100644
--- a/gcc/rust/util/rust-stacked-contexts.h
+++ b/gcc/rust/util/rust-stacked-contexts.h
@@ -71,7 +71,14 @@ public:
     return last;
   }
 
-  const T &peek ()
+  const T &peek () const
+  {
+    rust_assert (!stack.empty ());
+
+    return stack.back ();
+  }
+
+  T &peek ()
   {
     rust_assert (!stack.empty ());
 
-- 
2.49.0

Reply via email to