diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 293c63f5628b..536c828beb48 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 cf3028ef2717..b8ed3538f749 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 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 { } 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 & +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 54d59544b1dd..f38cbb941bf0 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -96,6 +96,8 @@ class Scope 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 cb); void iterate (std::function cb) const; @@ -109,6 +111,8 @@ class Scope CrateNum get_crate_num () const { return crate_num; } + const std::vector &get_context () const { return stack; }; + private: CrateNum crate_num; std::vector stack; @@ -191,6 +195,15 @@ class Resolver 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 &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 @@ class Resolver // keep track of the current module scope ids std::vector current_module_stack; + + // captured variables mappings + std::vector closure_context; + std::map> closures_capture_mappings; }; } // namespace Resolver