From: Arthur Cohen <arthur.co...@embecosm.com>

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.
---
 .../resolve/rust-early-name-resolver-2.0.cc   | 175 +++++++++++++++-
 .../resolve/rust-early-name-resolver-2.0.h    |  16 ++
 .../rust-toplevel-name-resolver-2.0.cc        | 188 ------------------
 .../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 1b21e115aee..884c05a93c3 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 590a2566053..6651bd2acfd 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 3ce16307508..8a1d8be0694 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 12c85c86a81..77dd522c17c 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
-- 
2.45.2

Reply via email to