From patchwork Tue Feb 21 12:02:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 60051 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp1843985wrn; Tue, 21 Feb 2023 04:53:38 -0800 (PST) X-Google-Smtp-Source: AK7set/SgLRFyQx9X3PNbkHoPJbWKtc6O72AhihoT2dv+BovLrYE4DRvhjEQejduE8no1ww8Y+eQ X-Received: by 2002:a05:6402:215:b0:4aa:9fc2:216 with SMTP id t21-20020a056402021500b004aa9fc20216mr5074317edv.9.1676984018092; Tue, 21 Feb 2023 04:53:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1676984018; cv=none; d=google.com; s=arc-20160816; b=pvNfCht7Vv7jjFdwVp64TmFlakPZ+L13HmnbpGj7TcD4yNNIUrSgwmCauM3KUJ/qg6 eBUAabSoR0Yuzdtu+fmaWgMHptpr7Bmi2KOFSoIVVu+T9FalC6sHmOFFu0CsFpdSajf8 5plzsWC7eIbZ6n8JIsQSw1RWIAzQ7lqBLWJZRsUSFXsZ7ACtLZHG+dFqX+Kfc7FyoGJa G4kiL/tbnxeLK5AP9Pdah8kf6CM07iykpZCqACzieKloT70Cnc0Tel9hFFgy5xvQLQTg GXH9VHQXUIYSo2f9/GBVee3C8zi+/dNXUGi44ZDAn1aS/2yv7AWCA84E6pp+4QOorsnN 9pDA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:dmarc-filter :delivered-to; bh=DYtrhUnhoey2Jh6lTnVuch7YxTpbWRR7E1O7oWil0JM=; b=xxXDKJEen7y5yc+XO/o3y+h5Zy87MO2cDSpXHJ+9OGJuZfmfmNkcZg3uouSjoRAPWE zF4swh0qcrUFtY4HNCG/7w+MO7F2gXdlsZ55r0+PCW2d3YNWeFGBkKk4xtHryfN52PaJ ZfnwGqHABVvPC9B9UFTv5MRhfO0MC1NORvaX+EP/BzXTujneWULqG7wD8QSPdwM8QjT/ Ecf6ACHWSGV41n45rixnjsmjaQzSj8MWfKhgeAIWq0FqxT2urTfoEED7Sx9uTmM/Gc+o VilbmYcNi04udwecAZ0Mtga9OcwGaJZU359Onh46Id0V3uP/wYfg+LHkbcLCqAuHVN9a a/Cw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@embecosm.com header.s=google header.b=DGwrdBQK; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id q9-20020aa7d449000000b004ad7c1ef7c7si15661437edr.506.2023.02.21.04.53.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Feb 2023 04:53:38 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@embecosm.com header.s=google header.b=DGwrdBQK; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8B4E2395A01C for ; Tue, 21 Feb 2023 12:18:22 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by sourceware.org (Postfix) with ESMTPS id 8B3E43888C52 for ; Tue, 21 Feb 2023 12:04:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8B3E43888C52 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-x42b.google.com with SMTP id t15so4270088wrz.7 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=w9csHLzfI0M+1rDRsQLebUZ9Mf1idAGXwiHUYHlmreBiChHh/jiAdUjrwRuNhipYZ2 9qhancfwMA7dtnvyg1jEuke1TVbduWaXhtphtkzhYECPGJRTpXI32iUfzzsouGNfv7pw i7bHnqTvwuBtDf5pd05OcKnJUqk6A/DVWSuICzOZrb/ecGep3tMT2o7Io+xb5tEoLpUP jwiMqcEGNcuMn8uF6gegkQwKT5CSk8e6El6oPcxl+uSucPOlU57nufc4D1Qzc4YbX0Ur 8myeu195dbSCm4SwMexu+FmvuN5wkCVJPoSnsMNroQhWVRyc5damqK1Vsx7uiH0KUVE7 JROw== X-Gm-Message-State: AO0yUKWHte1p4HYJi7DGSnuHkGOOP2v9qlITe1emp9TjmPSDc+/snO6w vZy0ZREk/mpbsMchcgyBlz0OqSs7LWWPhQC7FA== 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> MIME-Version: 1.0 X-Spam-Status: No, score=-14.3 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=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1758445193805956577?= X-GMAIL-MSGID: =?utf-8?q?1758445193805956577?= 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