From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by sourceware.org (Postfix) with ESMTPS id 4CF113888C4A for ; Tue, 21 Feb 2023 12:04:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4CF113888C4A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x42c.google.com with SMTP id j2so3984800wrh.9 for ; Tue, 21 Feb 2023 04:04:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=DYtrhUnhoey2Jh6lTnVuch7YxTpbWRR7E1O7oWil0JM=; b=DGwrdBQKSIwMYMVTnGUNftjnav4vEmzHWUph9FI8bX4b740dXn0MIK0i6YtD7VcoMd qfVTdtyEGx5t6RT7K+nfRIG1P5XiELDoq7RdM8t3bSMxh1NWbTVr/qEi4nEt9/yRBX9M bj7cMml3eggBIOFo++e6Ncgz6PGDvf59Wm9fjrYsRXPErCGVyo01N58JkZYoAj0ORDvk Gw8zUz6IlAUN+LXwlualOg0oevE0VTxEUxNoiNbaMboioHihQWNlhsk34rPZHY1J/oD/ sWsc9FTyVN3YbTymJGx8W45nitXllsMZl0GssQbjEybHibuGKCZHupdoShsGcLPd6ZJS 7uSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=DYtrhUnhoey2Jh6lTnVuch7YxTpbWRR7E1O7oWil0JM=; b=B/iKuRWVbaugAwqduQ6/XLRlccZw1hVVC4FTRIeIQgcOJBwdYGoUQWjG7tOMg7ID85 ffk59qBoHeL+vC9mvODrtCEskFi399dHssaDJ607Bi6ifxrU7ooTcTidZy2/y6E/+oLh APTrOH8NklhXJ59aW4334Ejc0fIR7sEb5Qc6r4akJoDuQSUNYNrc8BN16At8jS7vKc8n o1leQjElo1OGoBwWA9rpU35fEdSme1fD89fsepXyGVoj8Gdk39uqkqcKMOD20KPs8rPO bmk+iKDlVGcb0aLH/owZXdFuInBZvwkiBha8PT4QjyL9WirgehwgFdXFm1MNXyn/cD55 wH4Q== X-Gm-Message-State: AO0yUKUj8dTkyZQtDCiz/LMwmW+48q6cxdeXYZgHMFStReEj8TAeAcEM cxed7BRNz4i+8tAHtxO8LUUb X-Google-Smtp-Source: AK7set82AHFQsDfBOWEtGEU6kKcY8l9nLinO9+wYjqnNiVItO3mBd08ka3T616GhUGNcfIfPy5csNQ== X-Received: by 2002:a5d:4f08:0:b0:2c5:5870:b589 with SMTP id c8-20020a5d4f08000000b002c55870b589mr4131831wru.14.1676981078866; Tue, 21 Feb 2023 04:04:38 -0800 (PST) Received: from platypus.localdomain ([62.23.166.218]) by smtp.gmail.com with ESMTPSA id c15-20020adffb4f000000b002c55b0e6ef1sm5013811wrs.4.2023.02.21.04.04.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Feb 2023 04:04:38 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron Subject: [committed 095/103] gccrs: Add closure binding's tracking to name resolution Date: Tue, 21 Feb 2023 13:02:25 +0100 Message-Id: <20230221120230.596966-96-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230221120230.596966-1-arthur.cohen@embecosm.com> References: <20230221120230.596966-1-arthur.cohen@embecosm.com> Reply-To: arthur.cohen@embecosm.com MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-14.7 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: Philip Herron 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 gcc/rust/ChangeLog: * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Use proper closure contexts. * resolve/rust-name-resolver.cc (Scope::lookup_decl_type): New function. (Scope::lookup_rib_for_decl): Likewise. (Resolver::insert_resolved_name): Insert captured items. (Resolver::push_closure_context): New function. (Resolver::pop_closure_context): Likewise. (Resolver::insert_captured_item): Likewise. (Resolver::decl_needs_capture): Likewise. (Resolver::get_captures): Likewise. * resolve/rust-name-resolver.h: Declare new functions. --- 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 293c63f5628..536c828beb4 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 cf3028ef271..b8ed3538f74 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 54d59544b1d..f38cbb941bf 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 -- 2.39.1