diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2024-04-04 16:25:30 +0200 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2025-03-19 15:32:12 +0100 |
commit | 2f743673232dc87b85e802ea5256a36bb1988172 (patch) | |
tree | 38f8a31052911eeea9b65742a5defd41acde8aae /gcc | |
parent | 8ed0cc70f73ab88218e587977cc0c181eb58453e (diff) | |
download | gcc-2f743673232dc87b85e802ea5256a36bb1988172.zip gcc-2f743673232dc87b85e802ea5256a36bb1988172.tar.gz gcc-2f743673232dc87b85e802ea5256a36bb1988172.tar.bz2 |
gccrs: early: Resolve imports and create import mappings
gcc/rust/ChangeLog:
* resolve/rust-early-name-resolver-2.0.cc (Early::resolve_glob_import): New function.
(Early::resolve_simple_import): Likewise.
(Early::resolve_rebind_import): Likewise.
(Early::build_import_mapping): Likewise.
* resolve/rust-early-name-resolver-2.0.h: Add declarations and list of imports to
resolve.
* resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::handle_use_glob): Remove function,
which is now being handled by the Early name resolver.
(TopLevel::handle_use_dec): Likewise.
(TopLevel::handle_rebind): Likewise.
* resolve/rust-toplevel-name-resolver-2.0.h: Likewise, and add functions for creating
import list and fetching it.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/resolve/rust-early-name-resolver-2.0.cc | 175 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-early-name-resolver-2.0.h | 16 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc | 188 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h | 74 |
4 files changed, 229 insertions, 224 deletions
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 1b21e11..884c05a 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -18,6 +18,7 @@ #include "rust-early-name-resolver-2.0.h" #include "rust-ast-full.h" +#include "rust-diagnostics.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-attributes.h" @@ -51,16 +52,182 @@ Early::go (AST::Crate &crate) auto toplevel = TopLevel (ctx); toplevel.go (crate); - textual_scope.push (); + // We start with resolving the list of imports that `TopLevel` has built for + // us + for (auto &&import : toplevel.get_imports_to_resolve ()) + build_import_mapping (std::move (import)); - // Then we proceed to the proper "early" name resolution: Import and macro - // name resolution + // We now proceed with resolving macros, which can be nested in almost any + // items + textual_scope.push (); for (auto &item : crate.items) item->accept_vis (*this); - textual_scope.pop (); } +bool +Early::resolve_glob_import (TopLevel::ImportKind &&glob) +{ + auto resolved = ctx.types.resolve_path (glob.to_resolve.get_segments ()); + if (!resolved.has_value ()) + return false; + + auto result + = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); + if (!result) + return false; + + // here, we insert the module's NodeId into the import_mappings and will look + // up the module proper in `FinalizeImports` + import_mappings.insert ({std::move (glob), resolved->get_node_id ()}); + + // FIXME: This needs to be done in `FinalizeImports` + // GlobbingVisitor gvisitor (ctx); + // gvisitor.go (result.value ()); + + return true; +} + +bool +Early::resolve_simple_import (TopLevel::ImportKind &&import) +{ + // TODO: Fix documentation - the function has changed slightly + + const auto &path = import.to_resolve; + // auto locus = path.get_final_segment ().get_locus (); + // auto declared_name = path.get_final_segment ().as_string (); + + // In that function, we only need to declare a new definition - the use path. + // the resolution needs to happpen in the EarlyNameResolver. So the + // definitions we'll add will be the path's NodeId - that makes sense, as we + // need one definition per path declared in a Use tree. so all good. + // alright, now in what namespace do we declare them? all of them? do we only + // declare them in the EarlyNameResolver? this is dodgy + + // 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 + // :( + + return ctx.values.resolve_path (path.get_segments ()) + .or_else ([&] () { return ctx.types.resolve_path (path.get_segments ()); }) + .or_else ([&] () { return ctx.macros.resolve_path (path.get_segments ()); }) + .map ([&] (Rib::Definition def) { + import_mappings.insert ({std::move (import), def.get_node_id ()}); + }) + .has_value (); + + // 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, path, import] (Rib::Definition + // def) { + // found = true; + + // import_mappings.insert ({std::move (import), def.get_node_id + // ()}); + + // // what do we do with the id? + // // insert_or_error_out (declared_name, locus, def.get_node_id (), + // // ns); auto result = node_forwarding.find (def.get_node_id ()); + // if + // // (result != node_forwarding.cend () + // // && result->second != path.get_node_id ()) + // // rust_error_at (path.get_locus (), "%qs defined multiple + // times", + // // declared_name.c_str ()); + // // else // No previous thing has inserted this into our scope + // // node_forwarding.insert ({def.get_node_id (), + // path.get_node_id + // // ()}); + + // return def.get_node_id (); + // }); + // }; + + // resolve_and_insert (path); + + // return found; +} + +bool +Early::resolve_rebind_import (TopLevel::ImportKind &&rebind_import) +{ + auto &path = rebind_import.to_resolve; + + // We can fetch the value here as `resolve_rebind` will only be called on + // imports of the right kind + auto &rebind = rebind_import.rebind.value (); + + location_t locus = UNKNOWN_LOCATION; + std::string declared_name; + + // FIXME: This needs to be done in `FinalizeImports` + switch (rebind.get_new_bind_type ()) + { + case AST::UseTreeRebind::NewBindType::IDENTIFIER: + declared_name = rebind.get_identifier ().as_string (); + locus = rebind.get_identifier ().get_locus (); + break; + case AST::UseTreeRebind::NewBindType::NONE: + declared_name = path.get_final_segment ().as_string (); + locus = path.get_final_segment ().get_locus (); + break; + case AST::UseTreeRebind::NewBindType::WILDCARD: + rust_unreachable (); + break; + } + + return ctx.values.resolve_path (path.get_segments ()) + .or_else ([&] () { return ctx.types.resolve_path (path.get_segments ()); }) + .or_else ([&] () { return ctx.macros.resolve_path (path.get_segments ()); }) + .map ([&] (Rib::Definition def) { + import_mappings.insert ({std::move (rebind_import), def.get_node_id ()}); + }) + .has_value (); +} + +void +Early::build_import_mapping (TopLevel::ImportKind &&import) +{ + auto found = false; + + // We create a copy of the path in case of errors, since the `import` will be + // moved into the newly created import mappings + auto path = import.to_resolve; + + switch (import.kind) + { + case TopLevel::ImportKind::Kind::Glob: + found = resolve_glob_import (std::move (import)); + break; + case TopLevel::ImportKind::Kind::Simple: + found = resolve_simple_import (std::move (import)); + break; + case TopLevel::ImportKind::Kind::Rebind: + found = resolve_rebind_import (std::move (import)); + break; + } + + if (!found) + rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433, + "unresolved import %qs", path.as_string ().c_str ()); +} + void Early::TextualScope::push () { diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index 590a256..6651bd2 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -24,6 +24,7 @@ #include "rust-ast-visitor.h" #include "rust-name-resolution-context.h" #include "rust-default-resolver.h" +#include "rust-toplevel-name-resolver-2.0.h" namespace Rust { namespace Resolver2_0 { @@ -91,6 +92,21 @@ private: std::vector<std::unordered_map<std::string, NodeId>> scopes; }; + // Mappings between an import and the definition it imports + std::map<TopLevel::ImportKind, NodeId> import_mappings; + + // 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 resolve_simple_import (TopLevel::ImportKind &&import); + bool resolve_glob_import (TopLevel::ImportKind &&glob_import); + bool resolve_rebind_import (TopLevel::ImportKind &&rebind_import); + + // Handle an import, resolving it to its definition and adding it to the list + // of import mappings + void build_import_mapping (TopLevel::ImportKind &&import); + TextualScope textual_scope; std::vector<Error> macro_resolve_errors; 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 3ce1630..8a1d8be 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -427,194 +427,6 @@ TopLevel::visit (AST::ConstantItem &const_item) DefaultResolver::visit (const_item); } -bool -TopLevel::handle_use_glob (AST::SimplePath &glob) -{ - auto resolved = ctx.types.resolve_path (glob.get_segments ()); - if (!resolved.has_value ()) - return false; - - auto result - = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); - - if (!result.has_value ()) - return false; - - GlobbingVisitor gvisitor (ctx); - gvisitor.go (result.value ()); - - return true; -} - -bool -TopLevel::handle_use_dec (AST::SimplePath &path) -{ - auto locus = path.get_final_segment ().get_locus (); - auto declared_name = path.get_final_segment ().as_string (); - - // In that function, we only need to declare a new definition - the use path. - // the resolution needs to happpen in the EarlyNameResolver. So the - // definitions we'll add will be the path's NodeId - that makes sense, as we - // need one definition per path declared in a Use tree. so all good. - // alright, now in what namespace do we declare them? all of them? do we only - // declare them in the EarlyNameResolver? this is dodgy - - // 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<Rib::Definition> resolved = tl::nullopt; - - insert_or_error_out (declared_name, locus, path.get_node_id (), ns); - // what do we do here with the full simplepath? do we add it to an extra - // map? - - // 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, - path] (Rib::Definition def) { - found = true; - - // what do we do with the id? - insert_or_error_out (declared_name, locus, def.get_node_id (), ns); - auto result = node_forwarding.find (def.get_node_id ()); - if (result != node_forwarding.cend () - && result->second != path.get_node_id ()) - rust_error_at (path.get_locus (), "%qs defined multiple times", - declared_name.c_str ()); - else // No previous thing has inserted this into our scope - node_forwarding.insert ({def.get_node_id (), path.get_node_id ()}); - - return def.get_node_id (); - }); - }; - - resolve_and_insert (Namespace::Values, path); - resolve_and_insert (Namespace::Types, path); - resolve_and_insert (Namespace::Macros, path); - - return found; -} - -bool -TopLevel::handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &rebind) -{ - auto &path = rebind.first; - - location_t locus = UNKNOWN_LOCATION; - std::string declared_name; - - switch (rebind.second.get_new_bind_type ()) - { - case AST::UseTreeRebind::NewBindType::IDENTIFIER: - declared_name = rebind.second.get_identifier ().as_string (); - locus = rebind.second.get_identifier ().get_locus (); - break; - case AST::UseTreeRebind::NewBindType::NONE: - declared_name = path.get_final_segment ().as_string (); - locus = path.get_final_segment ().get_locus (); - break; - case AST::UseTreeRebind::NewBindType::WILDCARD: - rust_unreachable (); - break; - } - - // 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<Rib::Definition> resolved = tl::nullopt; - tl::optional<Rib::Definition> resolved_bind = tl::nullopt; - - std::vector<AST::SimplePathSegment> declaration_v - = {AST::SimplePathSegment (declared_name, locus)}; - // 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 ()); - resolved_bind = ctx.values.resolve_path (declaration_v); - break; - case Namespace::Types: - resolved = ctx.types.resolve_path (path.get_segments ()); - resolved_bind = ctx.types.resolve_path (declaration_v); - break; - case Namespace::Macros: - resolved = ctx.macros.resolve_path (path.get_segments ()); - resolved_bind = ctx.macros.resolve_path (declaration_v); - break; - case Namespace::Labels: - // TODO: Is that okay? - rust_unreachable (); - } - - resolved.map ([this, &found, &declared_name, locus, ns, path, - &resolved_bind] (Rib::Definition def) { - found = true; - - insert_or_error_out (declared_name, locus, def.get_node_id (), ns); - if (resolved_bind.has_value ()) - { - auto bind_def = resolved_bind.value (); - // what do we do with the id? - auto result = node_forwarding.find (bind_def.get_node_id ()); - if (result != node_forwarding.cend () - && result->second != path.get_node_id ()) - rust_error_at (path.get_locus (), "%qs defined multiple times", - declared_name.c_str ()); - } - else - { - // No previous thing has inserted this into our scope - node_forwarding.insert ({def.get_node_id (), path.get_node_id ()}); - } - return def.get_node_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, 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 12c85c8..77dd522 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -66,30 +66,6 @@ public: void go (AST::Crate &crate); -private: - /** - * Insert a new definition or error out if a definition with the same name was - * already present in the same namespace in the same scope. - * - * @param identifier The identifier of the definition to add. - * @param node A reference to the node, so we can get its `NodeId` and - * location. - * @param ns The namespace in which to add the definition. - */ - 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; - - // Store node forwarding for use declaration, the link between a - // definition and its new local name. - std::unordered_map<NodeId, NodeId> node_forwarding; - // Each import will be transformed into an instance of `ImportKind`, a class // representing some of the data we need to resolve in the // `EarlyNameResolver`. Basically, for each `UseTree` that we see in @@ -142,6 +118,35 @@ private: {} }; + std::vector<ImportKind> &&get_imports_to_resolve () + { + return std::move (imports_to_resolve); + } + +private: + /** + * Insert a new definition or error out if a definition with the same name was + * already present in the same namespace in the same scope. + * + * @param identifier The identifier of the definition to add. + * @param node A reference to the node, so we can get its `NodeId` and + * location. + * @param ns The namespace in which to add the definition. + */ + 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; + + // Store node forwarding for use declaration, the link between a + // definition and its new local name. + std::unordered_map<NodeId, NodeId> node_forwarding; + // One of the outputs of the `TopLevel` visitor - the list of imports that // `Early` should take care of resolving std::vector<ImportKind> imports_to_resolve; @@ -163,18 +168,23 @@ private: 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); - bool handle_use_glob (AST::SimplePath &glob); - bool handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &pair); - void visit (AST::UseDeclaration &use) override; }; } // namespace Resolver2_0 } // namespace Rust +// For storing Imports as keys in maps +namespace std { +template <> struct less<Rust::Resolver2_0::TopLevel::ImportKind> +{ + bool operator() (const Rust::Resolver2_0::TopLevel::ImportKind &lhs, + const Rust::Resolver2_0::TopLevel::ImportKind &rhs) const + { + return lhs.to_resolve.as_string () < rhs.to_resolve.as_string () + && lhs.kind < rhs.kind; + } +}; +} // namespace std + #endif // !RUST_TOPLEVEL_NAME_RESOLVER_2_0_H |