aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2024-04-04 16:25:30 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2025-03-19 15:32:12 +0100
commit2f743673232dc87b85e802ea5256a36bb1988172 (patch)
tree38f8a31052911eeea9b65742a5defd41acde8aae /gcc/rust/resolve
parent8ed0cc70f73ab88218e587977cc0c181eb58453e (diff)
downloadgcc-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/rust/resolve')
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.cc175
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.h16
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc188
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h74
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