https://gcc.gnu.org/g:708920065ea7199781a1cf3670a1a5b2ffdfc00a
commit 708920065ea7199781a1cf3670a1a5b2ffdfc00a Author: Arthur Cohen <arthur.co...@embecosm.com> Date: Wed Aug 23 13:51:06 2023 +0200 toplevel: Resolve `use` declarations gcc/rust/ChangeLog: * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::insert_or_error_out): New functions. (TopLevel::handle_use_dec): New function. (flatten_rebind): Likewise. (flatten_list): Likewise. (flatten_glob): Likewise. (flatten): Likewise. (TopLevel::visit): Visit various `use` declaration nodes. * resolve/rust-toplevel-name-resolver-2.0.h: Declare functions and visitors. Diff: --- .../resolve/rust-toplevel-name-resolver-2.0.cc | 187 ++++++++++++++++++++- gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h | 11 ++ 2 files changed, 194 insertions(+), 4 deletions(-) diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index b9d0bc7c0ac9..46113a8a46b3 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-toplevel-name-resolver-2.0.h" +#include "optional.h" #include "rust-ast-full.h" #include "rust-hir-map.h" #include "rust-attribute-values.h" @@ -33,11 +34,16 @@ void TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, Namespace ns) { - auto loc = node.get_locus (); - auto node_id = node.get_node_id (); + insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns); +} +void +TopLevel::insert_or_error_out (const Identifier &identifier, + const location_t &locus, const NodeId &node_id, + Namespace ns) +{ // keep track of each node's location to provide useful errors - node_locations.emplace (node_id, loc); + node_locations.emplace (node_id, locus); auto result = ctx.insert (identifier, node_id, ns); @@ -46,7 +52,7 @@ TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, // can we do something like check if the node id is the same? if it is the // same, it's not an error, just the resolver running multiple times? - rich_location rich_loc (line_table, loc); + rich_location rich_loc (line_table, locus); rich_loc.add_range (node_locations[result.error ().existing]); rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times", @@ -308,5 +314,178 @@ TopLevel::visit (AST::ConstantItem &const_item) ctx.scoped (Rib::Kind::ConstantItem, const_item.get_node_id (), expr_vis); } +bool +TopLevel::handle_use_dec (AST::SimplePath path) +{ + // TODO: Glob imports can get shadowed by regular imports and regular items. + // So we need to store them in a specific way in the ForeverStack - which can + // also probably be used by labels and macros etc. Like store it as a + // `Shadowable(NodeId)` instead of just a `NodeId` + + auto locus = path.get_final_segment ().get_locus (); + auto declared_name = path.get_final_segment ().as_string (); + + // in what namespace do we perform path resolution? All of them? see which one + // matches? Error out on ambiguities? + // so, apparently, for each one that matches, add it to the proper namespace + // :( + + auto found = false; + + auto resolve_and_insert = [this, &found, &declared_name, + locus] (Namespace ns, + const AST::SimplePath &path) { + tl::optional<NodeId> resolved = tl::nullopt; + + // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so + // that we can improve it with hints or location or w/ever. and maybe + // only emit it the first time. + switch (ns) + { + case Namespace::Values: + resolved = ctx.values.resolve_path (path.get_segments ()); + break; + case Namespace::Types: + resolved = ctx.types.resolve_path (path.get_segments ()); + break; + case Namespace::Macros: + resolved = ctx.macros.resolve_path (path.get_segments ()); + break; + case Namespace::Labels: + // TODO: Is that okay? + rust_unreachable (); + } + + // FIXME: Ugly + (void) resolved.map ([this, &found, &declared_name, locus, ns] (NodeId id) { + found = true; + + // what do we do with the id? + insert_or_error_out (declared_name, locus, id, ns); + + return id; + }); + }; + + // do this for all namespaces (even Labels?) + + resolve_and_insert (Namespace::Values, path); + resolve_and_insert (Namespace::Types, path); + resolve_and_insert (Namespace::Macros, path); + + // TODO: No labels? No, right? + + return found; +} + +static void +flatten_rebind (const AST::UseTreeRebind &glob, + std::vector<AST::SimplePath> &paths); +static void +flatten_list (const AST::UseTreeList &glob, + std::vector<AST::SimplePath> &paths); +static void +flatten_glob (const AST::UseTreeGlob &glob, + std::vector<AST::SimplePath> &paths); + +static void +flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths) +{ + switch (tree->get_kind ()) + { + case AST::UseTree::Rebind: { + auto rebind = static_cast<const AST::UseTreeRebind *> (tree); + flatten_rebind (*rebind, paths); + break; + } + case AST::UseTree::List: { + auto list = static_cast<const AST::UseTreeList *> (tree); + flatten_list (*list, paths); + break; + } + case AST::UseTree::Glob: { + rust_sorry_at (tree->get_locus (), "cannot resolve glob imports yet"); + auto glob = static_cast<const AST::UseTreeGlob *> (tree); + flatten_glob (*glob, paths); + break; + } + break; + } +} + +static void +flatten_rebind (const AST::UseTreeRebind &rebind, + std::vector<AST::SimplePath> &paths) +{ + auto path = rebind.get_path (); + + // FIXME: Do we want to emplace the rebind here as well? + if (rebind.has_identifier ()) + { + auto rebind_path = path; + auto new_seg = rebind.get_identifier (); + + // Add the identifier as a new path + rebind_path.get_segments ().back () + = AST::SimplePathSegment (new_seg.as_string (), UNDEF_LOCATION); + + paths.emplace_back (rebind_path); + } + else + { + paths.emplace_back (path); + } +} + +static void +flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths) +{ + auto prefix = AST::SimplePath::create_empty (); + if (list.has_path ()) + prefix = list.get_path (); + + for (const auto &tree : list.get_trees ()) + { + auto sub_paths = std::vector<AST::SimplePath> (); + flatten (tree.get (), sub_paths); + + for (auto &sub_path : sub_paths) + { + auto new_path = prefix; + std::copy (sub_path.get_segments ().begin (), + sub_path.get_segments ().end (), + std::back_inserter (new_path.get_segments ())); + + paths.emplace_back (new_path); + } + } +} + +static void +flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths) +{ + if (glob.has_path ()) + paths.emplace_back (glob.get_path ()); +} + +void +TopLevel::visit (AST::UseDeclaration &use) +{ + auto paths = std::vector<AST::SimplePath> (); + + // FIXME: How do we handle `use foo::{self}` imports? Some beforehand cleanup? + // How do we handle module imports in general? Should they get added to all + // namespaces? + + const auto &tree = use.get_tree (); + flatten (tree.get (), paths); + + for (auto &path : paths) + if (!handle_use_dec (path)) + rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433, + "could not resolve import %qs", + path.as_string ().c_str ()); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h index 95187d7b3fdb..996899b0848f 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -53,6 +53,9 @@ private: template <typename T> void insert_or_error_out (const Identifier &identifier, const T &node, Namespace ns); + void insert_or_error_out (const Identifier &identifier, + const location_t &locus, const NodeId &id, + Namespace ns); // FIXME: Do we move these to our mappings? std::unordered_map<NodeId, location_t> node_locations; @@ -73,6 +76,14 @@ private: void visit (AST::Union &union_item) override; void visit (AST::ConstantItem &const_item) override; void visit (AST::ExternCrate &crate) override; + + // FIXME: Documentation + // Call this on all the paths of a UseDec - so each flattened path in a + // UseTreeList for example + // FIXME: Should that return `found`? + bool handle_use_dec (AST::SimplePath path); + + void visit (AST::UseDeclaration &use) override; }; } // namespace Resolver2_0