diff mbox series

[074/125] gccrs: Add name resolution for on globbing use decl

Message ID 20240801145809.366388-76-arthur.cohen@embecosm.com
State New
Headers show
Series [001/125] Rust: Make 'tree'-level 'MAIN_NAME_P' work | expand

Commit Message

Arthur Cohen Aug. 1, 2024, 2:57 p.m. UTC
From: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>

This is the first part of the code required to enable globbing on use
declarations.

gcc/rust/ChangeLog:

	* resolve/rust-toplevel-name-resolver-2.0.cc (GlobbingVisitor::visit):
	Insert names into their namespace.
	(TopLevel::visit): Insert ast module.
	(TopLevel::handle_use_dec): Resolve use declaration.
	(TopLevel::handle_use_glob): Use globbing visitor.
	(flatten_list): Use globbing path vector.
	(flatten_glob): Likewise.
	(flatten): Likewise.
	(prefix_subpaths): Add a function to prefix subpath.
	* resolve/rust-toplevel-name-resolver-2.0.h (class GlobbingVisitor):
	Add globbing visitor.
	* util/rust-hir-map.cc (Mappings::insert_ast_module): Add function to
	insert module in module hashmap.
	(Mappings::lookup_ast_module): Add function to retrieve ast module.
	* util/rust-hir-map.h: Add module map and getter/setter prototypes.

Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
---
 .../rust-toplevel-name-resolver-2.0.cc        | 179 +++++++++++++++---
 .../resolve/rust-toplevel-name-resolver-2.0.h |  23 +++
 gcc/rust/util/rust-hir-map.cc                 |  19 ++
 gcc/rust/util/rust-hir-map.h                  |   3 +
 4 files changed, 199 insertions(+), 25 deletions(-)
diff mbox series

Patch

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 5e6f5e9bd78..3122d41412f 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -25,6 +25,87 @@ 
 namespace Rust {
 namespace Resolver2_0 {
 
+void
+GlobbingVisitor::visit (AST::Module &module)
+{
+  if (module.get_visibility ().is_public ())
+    ctx.insert (module.get_name (), module.get_node_id (), Namespace::Types);
+}
+
+void
+GlobbingVisitor::visit (AST::MacroRulesDefinition &macro)
+{
+  if (macro.get_visibility ().is_public ())
+    ctx.insert (macro.get_rule_name (), macro.get_node_id (),
+		Namespace::Macros);
+}
+
+void
+GlobbingVisitor::visit (AST::Function &function)
+{
+  if (function.get_visibility ().is_public ())
+    ctx.insert (function.get_function_name (), function.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::StaticItem &static_item)
+{
+  if (static_item.get_visibility ().is_public ())
+    ctx.insert (static_item.get_identifier (), static_item.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::StructStruct &struct_item)
+{
+  if (struct_item.get_visibility ().is_public ())
+    ctx.insert (struct_item.get_identifier (), struct_item.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::TupleStruct &tuple_struct)
+{
+  if (tuple_struct.get_visibility ().is_public ())
+    ctx.insert (tuple_struct.get_identifier (), tuple_struct.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::Enum &enum_item)
+{
+  if (enum_item.get_visibility ().is_public ())
+    ctx.insert (enum_item.get_identifier (), enum_item.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::Union &union_item)
+{
+  if (union_item.get_visibility ().is_public ())
+    ctx.insert (union_item.get_identifier (), union_item.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::ConstantItem &const_item)
+{
+  if (const_item.get_visibility ().is_public ())
+    ctx.insert (const_item.get_identifier (), const_item.get_node_id (),
+		Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::ExternCrate &crate)
+{}
+
+void
+GlobbingVisitor::visit (AST::UseDeclaration &use)
+{
+  // Handle cycles ?
+}
+
 TopLevel::TopLevel (NameResolutionContext &resolver)
   : DefaultResolver (resolver)
 {}
@@ -81,6 +162,10 @@  TopLevel::visit (AST::Module &module)
 
   ctx.scoped (Rib::Kind::Module, module.get_node_id (), sub_visitor,
 	      module.get_name ());
+
+  if (Analysis::Mappings::get ()->lookup_ast_module (module.get_node_id ())
+      == tl::nullopt)
+    Analysis::Mappings::get ()->insert_ast_module (&module);
 }
 
 template <typename PROC_MACRO>
@@ -302,13 +387,26 @@  TopLevel::visit (AST::ConstantItem &const_item)
 }
 
 bool
-TopLevel::handle_use_dec (AST::SimplePath path)
+TopLevel::handle_use_glob (AST::SimplePath glob)
 {
-  // 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 resolved = ctx.types.resolve_path (glob.get_segments ());
+  if (!resolved.has_value ())
+    return false;
+
+  auto result = Analysis::Mappings::get ()->lookup_ast_module (*resolved);
+
+  if (!result.has_value ())
+    return false;
+
+  GlobbingVisitor gvisitor (ctx);
+  gvisitor.visit (*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 ();
 
@@ -377,14 +475,17 @@  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);
+flatten_list (const AST::UseTreeList &glob, std::vector<AST::SimplePath> &paths,
+	      std::vector<AST::SimplePath> &glob_paths,
+	      NameResolutionContext &ctx);
 static void
 flatten_glob (const AST::UseTreeGlob &glob,
-	      std::vector<AST::SimplePath> &paths);
+	      std::vector<AST::SimplePath> &glob_paths,
+	      NameResolutionContext &ctx);
 
 static void
-flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
+flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths,
+	 std::vector<AST::SimplePath> &glob_paths, NameResolutionContext &ctx)
 {
   switch (tree->get_kind ())
     {
@@ -395,13 +496,12 @@  flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
       }
       case AST::UseTree::List: {
 	auto list = static_cast<const AST::UseTreeList *> (tree);
-	flatten_list (*list, paths);
+	flatten_list (*list, paths, glob_paths, ctx);
 	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);
+	flatten_glob (*glob, glob_paths, ctx);
 	break;
       }
       break;
@@ -432,8 +532,28 @@  flatten_rebind (const AST::UseTreeRebind &rebind,
     }
 }
 
+/** Prefix a list of subpath
+ * @param prefix A prefix for all subpath
+ * @param subs List of subpath to prefix
+ * @param size List where results should be stored
+ */
+static void
+prefix_subpaths (AST::SimplePath prefix, std::vector<AST::SimplePath> subs,
+		 std::vector<AST::SimplePath> &results)
+{
+  for (auto &sub : subs)
+    {
+      auto new_path = prefix;
+      std::copy (sub.get_segments ().begin (), sub.get_segments ().end (),
+		 std::back_inserter (new_path.get_segments ()));
+      results.emplace_back (new_path);
+    }
+}
+
 static void
-flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
+flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths,
+	      std::vector<AST::SimplePath> &glob_paths,
+	      NameResolutionContext &ctx)
 {
   auto prefix = AST::SimplePath::create_empty ();
   if (list.has_path ())
@@ -442,43 +562,52 @@  flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
   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 ()));
+      auto sub_globs = std::vector<AST::SimplePath> ();
+      flatten (tree.get (), sub_paths, sub_globs, ctx);
 
-	  paths.emplace_back (new_path);
-	}
+      prefix_subpaths (prefix, sub_paths, paths);
+      prefix_subpaths (prefix, sub_globs, glob_paths);
     }
 }
 
 static void
-flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
+flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths,
+	      NameResolutionContext &ctx)
 {
   if (glob.has_path ())
     paths.emplace_back (glob.get_path ());
+
+  // (PE): Get path rib
+  auto rib = ctx.values.resolve_path (glob.get_path ().get_segments ())
+	       .and_then ([&] (NodeId id) { return ctx.values.to_rib (id); });
+  if (rib.has_value ())
+    {
+      auto value = rib.value ().get_values ();
+    }
 }
 
 void
 TopLevel::visit (AST::UseDeclaration &use)
 {
   auto paths = std::vector<AST::SimplePath> ();
+  auto glob_path = 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);
+  flatten (tree.get (), paths, glob_path, this->ctx);
 
   for (auto &path : paths)
     if (!handle_use_dec (path))
       rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433,
 		     "unresolved import %qs", path.as_string ().c_str ());
+
+  for (auto &glob : glob_path)
+    if (!handle_use_glob (glob))
+      rust_error_at (glob.get_final_segment ().get_locus (), ErrorCode::E0433,
+		     "unresolved import %qs", glob.as_string ().c_str ());
 }
 
 } // namespace Resolver2_0
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 0a766bab259..31535a9b22e 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -26,6 +26,28 @@ 
 namespace Rust {
 namespace Resolver2_0 {
 
+class GlobbingVisitor : public AST::DefaultASTVisitor
+{
+  using AST::DefaultASTVisitor::visit;
+
+public:
+  GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {}
+
+  void visit (AST::Module &module) override;
+  void visit (AST::MacroRulesDefinition &macro) override;
+  void visit (AST::Function &function) override;
+  void visit (AST::StaticItem &static_item) override;
+  void visit (AST::StructStruct &struct_item) override;
+  void visit (AST::TupleStruct &tuple_struct) override;
+  void visit (AST::Enum &enum_item) override;
+  void visit (AST::Union &union_item) override;
+  void visit (AST::ConstantItem &const_item) override;
+  void visit (AST::ExternCrate &crate) override;
+  void visit (AST::UseDeclaration &use) override;
+
+private:
+  NameResolutionContext &ctx;
+};
 /**
  * The `TopLevel` visitor takes care of collecting all the definitions in a
  * crate, and inserting them into the proper namespaces. These definitions can
@@ -85,6 +107,7 @@  private:
   // UseTreeList for example
   // FIXME: Should that return `found`?
   bool handle_use_dec (AST::SimplePath path);
+  bool handle_use_glob (AST::SimplePath glob);
 
   void visit (AST::UseDeclaration &use) override;
 };
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index c62c11189ae..05b26d64069 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -17,9 +17,11 @@ 
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-hir-map.h"
+#include "optional.h"
 #include "rust-ast-full.h"
 #include "rust-diagnostics.h"
 #include "rust-hir-full.h"
+#include "rust-item.h"
 #include "rust-macro-builtins.h"
 #include "rust-mapping-common.h"
 #include "rust-attribute-values.h"
@@ -1158,6 +1160,23 @@  Mappings::lookup_module_children (NodeId module)
   return it->second;
 }
 
+void
+Mappings::insert_ast_module (AST::Module *module)
+{
+  rust_assert (modules.find (module->get_node_id ()) == modules.end ());
+  modules[module->get_node_id ()] = module;
+}
+
+tl::optional<AST::Module *>
+Mappings::lookup_ast_module (NodeId id)
+{
+  auto it = modules.find (id);
+  if (it == modules.end ())
+    return tl::nullopt;
+
+  return {it->second};
+}
+
 void
 Mappings::insert_module_child_item (NodeId module,
 				    Resolver::CanonicalPath child)
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 927c01251db..92af0673f95 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -328,6 +328,8 @@  public:
   void insert_visibility (NodeId id, Privacy::ModuleVisibility visibility);
   bool lookup_visibility (NodeId id, Privacy::ModuleVisibility &def);
 
+  void insert_ast_module (AST::Module *);
+  tl::optional<AST::Module *> lookup_ast_module (NodeId id);
   void insert_module_child (NodeId module, NodeId child);
   tl::optional<std::vector<NodeId> &> lookup_module_children (NodeId module);
 
@@ -427,6 +429,7 @@  private:
   std::map<NodeId, std::vector<NodeId>> module_child_map;
   std::map<NodeId, std::vector<Resolver::CanonicalPath>> module_child_items;
   std::map<NodeId, NodeId> child_to_parent_module_map;
+  std::map<NodeId, AST::Module *> modules;
 
   // AST mappings
   std::map<NodeId, AST::Item *> ast_item_mappings;