public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Add closure binding's tracking to name resolution
@ 2022-12-05  9:53 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-12-05  9:53 UTC (permalink / raw)
  To: gcc-cvs

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

commit b5c354de73ddccb7738778c1e013d42b96aeb048
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Fri Oct 21 13:40:40 2022 +0100

    Add closure binding's tracking to name resolution
    
    When we have a closure block referencing variables in a parent function,
    we must track what these are. We do this by having a context of closures
    so if we have a variable reference and its declared in a rib whose node id
    is less than the node id of the closure's node id we know it must be a
    captured variable. We also need to iterate all possible closure contexts
    as we might be in the case of a nested closure.
    
    Addresses #195

Diff:
---
 gcc/rust/resolve/rust-ast-resolve-expr.cc |   9 ++
 gcc/rust/resolve/rust-name-resolver.cc    | 133 ++++++++++++++++++++++++++++++
 gcc/rust/resolve/rust-name-resolver.h     |  17 ++++
 3 files changed, 159 insertions(+)

diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 262f904829b..2063dceb2e1 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -581,9 +581,13 @@ ResolveExpr::visit (AST::ClosureExprInner &expr)
       resolve_closure_param (p);
     }
 
+  resolver->push_closure_context (expr.get_node_id ());
+
   ResolveExpr::go (expr.get_definition_expr ().get (), prefix,
 		   canonical_prefix);
 
+  resolver->pop_closure_context ();
+
   resolver->get_name_scope ().pop ();
   resolver->get_type_scope ().pop ();
   resolver->get_label_scope ().pop ();
@@ -606,9 +610,14 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr)
     }
 
   ResolveType::go (expr.get_return_type ().get ());
+
+  resolver->push_closure_context (expr.get_node_id ());
+
   ResolveExpr::go (expr.get_definition_block ().get (), prefix,
 		   canonical_prefix);
 
+  resolver->pop_closure_context ();
+
   resolver->get_name_scope ().pop ();
   resolver->get_type_scope ().pop ();
   resolver->get_label_scope ().pop ();
diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc
index 376a59ddcb3..59aed21bd87 100644
--- a/gcc/rust/resolve/rust-name-resolver.cc
+++ b/gcc/rust/resolve/rust-name-resolver.cc
@@ -169,6 +169,39 @@ Scope::lookup (const CanonicalPath &ident, NodeId *id)
   return lookup != UNKNOWN_NODEID;
 }
 
+bool
+Scope::lookup_decl_type (NodeId id, Rib::ItemType *type)
+{
+  bool found = false;
+  iterate ([&] (const Rib *r) -> bool {
+    if (r->decl_was_declared_here (id))
+      {
+	bool ok = r->lookup_decl_type (id, type);
+	rust_assert (ok);
+	found = true;
+	return false;
+      }
+    return true;
+  });
+  return found;
+}
+
+bool
+Scope::lookup_rib_for_decl (NodeId id, const Rib **rib)
+{
+  bool found = false;
+  iterate ([&] (const Rib *r) -> bool {
+    if (r->decl_was_declared_here (id))
+      {
+	*rib = r;
+	found = true;
+	return false;
+      }
+    return true;
+  });
+  return found;
+}
+
 void
 Scope::iterate (std::function<bool (Rib *)> cb)
 {
@@ -435,6 +468,7 @@ Resolver::insert_resolved_name (NodeId refId, NodeId defId)
 {
   resolved_names[refId] = defId;
   get_name_scope ().append_reference_for_def (refId, defId);
+  insert_captured_item (defId);
 }
 
 bool
@@ -531,5 +565,104 @@ Resolver::lookup_resolved_misc (NodeId refId, NodeId *defId)
   return true;
 }
 
+void
+Resolver::push_closure_context (NodeId closure_expr_id)
+{
+  auto it = closures_capture_mappings.find (closure_expr_id);
+  rust_assert (it == closures_capture_mappings.end ());
+
+  closures_capture_mappings.insert ({closure_expr_id, {}});
+  closure_context.push_back (closure_expr_id);
+}
+
+void
+Resolver::pop_closure_context ()
+{
+  rust_assert (!closure_context.empty ());
+  closure_context.pop_back ();
+}
+
+void
+Resolver::insert_captured_item (NodeId id)
+{
+  // nothing to do unless we are in a closure context
+  if (closure_context.empty ())
+    return;
+
+  // check that this is a VAR_DECL?
+  Scope &name_scope = get_name_scope ();
+  Rib::ItemType type = Rib::ItemType::Unknown;
+  bool found = name_scope.lookup_decl_type (id, &type);
+  if (!found)
+    return;
+
+  // RIB Function { let a, let b } id = 1;
+  //   RIB Closure { let c } id = 2;
+  //     RIB IfStmt { <bind a>} id = 3;
+  //   RIB ... { ... } id = 4
+  //
+  // if we have a resolved_node_id of 'a' and the current rib is '3' we know
+  // this is binding exists in a rib with id < the closure rib id, other wise
+  // its just a normal binding and we don't care
+  //
+  // Problem the node id's dont work like this because the inner most items are
+  // created first so this means the root will have a larger id and a simple
+  // less than or greater than check wont work for more complex scoping cases
+  // but we can use our current rib context to figure this out by checking if
+  // the rib id the decl we care about exists prior to the rib for the closure
+  // id
+
+  const Rib *r = nullptr;
+  bool ok = name_scope.lookup_rib_for_decl (id, &r);
+  rust_assert (ok);
+  NodeId decl_rib_node_id = r->get_node_id ();
+
+  // iterate the closure context and add in the mapping for all to handle the
+  // case of nested closures
+  for (auto &closure_expr_id : closure_context)
+    {
+      if (!decl_needs_capture (decl_rib_node_id, closure_expr_id, name_scope))
+	continue;
+
+      // is this a valid binding to take
+      bool is_var_decl_p = type == Rib::ItemType::Var;
+      if (!is_var_decl_p)
+	{
+	  // FIXME is this an error case?
+	  return;
+	}
+
+      // append it to the context info
+      auto it = closures_capture_mappings.find (closure_expr_id);
+      rust_assert (it != closures_capture_mappings.end ());
+
+      it->second.insert (id);
+    }
+}
+
+bool
+Resolver::decl_needs_capture (NodeId decl_rib_node_id,
+			      NodeId closure_rib_node_id, const Scope &scope)
+{
+  for (const auto &rib : scope.get_context ())
+    {
+      bool rib_is_closure = rib->get_node_id () == closure_rib_node_id;
+      bool rib_is_decl = rib->get_node_id () == decl_rib_node_id;
+      if (rib_is_closure)
+	return false;
+      else if (rib_is_decl)
+	return true;
+    }
+  return false;
+}
+
+const std::set<NodeId> &
+Resolver::get_captures (NodeId id) const
+{
+  auto it = closures_capture_mappings.find (id);
+  rust_assert (it != closures_capture_mappings.end ());
+  return it->second;
+}
+
 } // namespace Resolver
 } // namespace Rust
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
index 92e9b380880..5bfdeb748ae 100644
--- a/gcc/rust/resolve/rust-name-resolver.h
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -96,6 +96,8 @@ public:
   void insert (const CanonicalPath &ident, NodeId id, Location locus,
 	       Rib::ItemType type = Rib::ItemType::Unknown);
   bool lookup (const CanonicalPath &ident, NodeId *id);
+  bool lookup_decl_type (NodeId id, Rib::ItemType *type);
+  bool lookup_rib_for_decl (NodeId id, const Rib **rib);
 
   void iterate (std::function<bool (Rib *)> cb);
   void iterate (std::function<bool (const Rib *)> cb) const;
@@ -109,6 +111,8 @@ public:
 
   CrateNum get_crate_num () const { return crate_num; }
 
+  const std::vector<Rib *> &get_context () const { return stack; };
+
 private:
   CrateNum crate_num;
   std::vector<Rib *> stack;
@@ -191,6 +195,15 @@ public:
     return current_module_stack.at (current_module_stack.size () - 2);
   }
 
+  void push_closure_context (NodeId closure_expr_id);
+  void pop_closure_context ();
+  void insert_captured_item (NodeId id);
+  const std::set<NodeId> &get_captures (NodeId id) const;
+
+protected:
+  bool decl_needs_capture (NodeId decl_rib_node_id, NodeId closure_rib_node_id,
+			   const Scope &scope);
+
 private:
   Resolver ();
 
@@ -234,6 +247,10 @@ private:
 
   // keep track of the current module scope ids
   std::vector<NodeId> current_module_stack;
+
+  // captured variables mappings
+  std::vector<NodeId> closure_context;
+  std::map<NodeId, std::set<NodeId>> closures_capture_mappings;
 };
 
 } // namespace Resolver

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

only message in thread, other threads:[~2022-12-05  9:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-05  9:53 [gcc/devel/rust/master] Add closure binding's tracking to name resolution 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).