From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 27FAB3898382; Mon, 5 Dec 2022 09:53:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 27FAB3898382 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1670233987; bh=1/mbF0X2Za2TQ4FoYTHU/4Nk79mNxBqTWeiCFv47f5k=; h=From:To:Subject:Date:From; b=ra0rUUHLZj9uslxk7vLNKWbY0x/rBRCIN9RsNuTuzVCdw/NW5hEubNQHDz5XkWtya MQc8XDGEnXT4epNsAW89zIcq9HwP+u7koz734yMIHP0Jkz0RgV44Bf/smsic+F9L0k 5WPIOYUNsagQgWIV2wGh1CsANpdvtSj8NJzTcKnQ= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] Add closure binding's tracking to name resolution X-Act-Checkin: gcc X-Git-Author: Philip Herron X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 6c5dc8aa1a99bc3a0220aeabecd84ffa6f233433 X-Git-Newrev: b5c354de73ddccb7738778c1e013d42b96aeb048 Message-Id: <20221205095307.27FAB3898382@sourceware.org> Date: Mon, 5 Dec 2022 09:53:07 +0000 (GMT) List-Id: https://gcc.gnu.org/g:b5c354de73ddccb7738778c1e013d42b96aeb048 commit b5c354de73ddccb7738778c1e013d42b96aeb048 Author: Philip Herron 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 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 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 cb); void iterate (std::function cb) const; @@ -109,6 +111,8 @@ public: 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 @@ 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 &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 current_module_stack; + + // captured variables mappings + std::vector closure_context; + std::map> closures_capture_mappings; }; } // namespace Resolver