diff mbox series

[067/125] gccrs: late: Setup builtin types properly, change Rib API

Message ID 20240801145809.366388-69-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
gcc/rust/ChangeLog:

	* resolve/rust-forever-stack.hxx: Start using Rib::Definition for
	shadowable information.
	* resolve/rust-late-name-resolver-2.0.cc (next_node_id): New.
	(next_hir_id): New.
	(Late::setup_builtin_types): Improve builtin type setup.
	* resolve/rust-rib.cc (Rib::Definition::Definition): New constructor.
	(Rib::Definition::Shadowable): Likewise.
	(Rib::Definition::NonShadowable): Likewise.
	(Rib::Rib): Fix general constructor.
	(Rib::insert): Use Definition class.
	(Rib::get): Likewise.
	* resolve/rust-rib.h: New Definition class, new prototypes.
---
 gcc/rust/resolve/rust-forever-stack.hxx       | 22 +++--
 .../resolve/rust-late-name-resolver-2.0.cc    | 84 +++++++++++++------
 gcc/rust/resolve/rust-rib.cc                  | 38 +++++++--
 gcc/rust/resolve/rust-rib.h                   | 30 +++++--
 4 files changed, 126 insertions(+), 48 deletions(-)
diff mbox series

Patch

diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx
index 0aa9943191e..a2fdce98362 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -100,9 +100,9 @@  ForeverStack<N>::pop ()
 }
 
 static tl::expected<NodeId, DuplicateNameError>
-insert_inner (Rib &rib, std::string name, NodeId node, bool can_shadow)
+insert_inner (Rib &rib, std::string name, Rib::Definition definition)
 {
-  return rib.insert (name, node, can_shadow);
+  return rib.insert (name, definition);
 }
 
 template <Namespace N>
@@ -115,7 +115,8 @@  ForeverStack<N>::insert (Identifier name, NodeId node)
   // pass, we might end up in a situation where it is okay to re-add new names.
   // Do we just ignore that here? Do we keep track of if the Rib is new or not?
   // should our cursor have info on the current node like "is it newly pushed"?
-  return insert_inner (innermost_rib, name.as_string (), node, false);
+  return insert_inner (innermost_rib, name.as_string (),
+		       Rib::Definition::NonShadowable (node));
 }
 
 template <Namespace N>
@@ -126,7 +127,8 @@  ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
 
   // inserting in the root of the crate is never a shadowing operation, even for
   // macros
-  return insert_inner (root_rib, name.as_string (), node, false);
+  return insert_inner (root_rib, name.as_string (),
+		       Rib::Definition::NonShadowable (node));
 }
 
 // Specialization for Macros and Labels - where we are allowed to shadow
@@ -135,14 +137,16 @@  template <>
 inline tl::expected<NodeId, DuplicateNameError>
 ForeverStack<Namespace::Macros>::insert (Identifier name, NodeId node)
 {
-  return insert_inner (peek (), name.as_string (), node, true);
+  return insert_inner (peek (), name.as_string (),
+		       Rib::Definition::Shadowable (node));
 }
 
 template <>
 inline tl::expected<NodeId, DuplicateNameError>
 ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node)
 {
-  return insert_inner (peek (), name.as_string (), node, true);
+  return insert_inner (peek (), name.as_string (),
+		       Rib::Definition::Shadowable (node));
 }
 
 template <Namespace N>
@@ -455,10 +459,10 @@  template <Namespace N>
 tl::optional<std::pair<typename ForeverStack<N>::Node &, std::string>>
 ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
 {
-  auto &values = starting_point.rib.get_values ();
+  auto values = starting_point.rib.get_values ();
 
   for (auto &kv : values)
-    if (kv.second == to_find)
+    if (kv.second.id == to_find)
       return {{starting_point, kv.first}};
 
   for (auto &child : starting_point.children)
@@ -568,7 +572,7 @@  ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
   stream << next << "rib: {\n";
 
   for (const auto &kv : rib.get_values ())
-    stream << next_next << kv.first << ": " << kv.second << "\n";
+    stream << next_next << kv.first << ": " << kv.second.id << "\n";
 
   stream << next << "},\n";
 }
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index 50034073edf..3090bbeff2a 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -18,8 +18,10 @@ 
 
 #include "optional.h"
 #include "rust-ast-full.h"
+#include "rust-hir-map.h"
 #include "rust-late-name-resolver-2.0.h"
 #include "rust-default-resolver.h"
+#include "rust-name-resolution-context.h"
 #include "rust-path.h"
 #include "rust-tyty.h"
 #include "rust-hir-type-check.h"
@@ -29,41 +31,75 @@  namespace Resolver2_0 {
 
 Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {}
 
+static NodeId
+next_node_id ()
+{
+  return Analysis::Mappings::get ()->get_next_node_id ();
+};
+
+static HirId
+next_hir_id ()
+{
+  return Analysis::Mappings::get ()->get_next_hir_id ();
+};
+
 void
 Late::setup_builtin_types ()
 {
-  auto next_id = [this] () { return ctx.mappings.get_next_hir_id (); };
-
-  static const std::pair<std::string, TyTy::BaseType *> builtins[] = {
-    {"u8", new TyTy::UintType (next_id (), TyTy::UintType::U8)},
-    {"u16", new TyTy::UintType (next_id (), TyTy::UintType::U16)},
-    {"u32", new TyTy::UintType (next_id (), TyTy::UintType::U32)},
-    {"u64", new TyTy::UintType (next_id (), TyTy::UintType::U64)},
-    {"u128", new TyTy::UintType (next_id (), TyTy::UintType::U128)},
-    {"i8", new TyTy::IntType (next_id (), TyTy::IntType::I8)},
-    {"i16", new TyTy::IntType (next_id (), TyTy::IntType::I16)},
-    {"i32", new TyTy::IntType (next_id (), TyTy::IntType::I32)},
-    {"i64", new TyTy::IntType (next_id (), TyTy::IntType::I64)},
-    {"i128", new TyTy::IntType (next_id (), TyTy::IntType::I128)},
-    {"f32", new TyTy::FloatType (next_id (), TyTy::FloatType::F32)},
-    {"f64", new TyTy::FloatType (next_id (), TyTy::FloatType::F64)},
-    {"usize", new TyTy::USizeType (next_id ())},
-    {"isize", new TyTy::ISizeType (next_id ())},
-    // missing char, str, never, ()
-    // does name resolution play a part for this? or is it all at typechecking?
-    // yeah it seems to be name resolution as well, which makes sense
+  // access the global type context to setup the TyTys
+  auto &ty_ctx = *Resolver::TypeCheckContext::get ();
+
+  // Late builtin type struct helper
+  struct LType
+  {
+    std::string name;
+    NodeId node_id;
+    NodeId hir_id;
+    TyTy::BaseType *type;
+
+    explicit LType (std::string name, TyTy::BaseType *type)
+      : name (name), node_id (next_node_id ()), hir_id (type->get_ref ()),
+	type (type)
+    {}
+  };
+
+  static const LType builtins[] = {
+    {LType ("u8", new TyTy::UintType (next_hir_id (), TyTy::UintType::U8))},
+    {LType ("u16", new TyTy::UintType (next_hir_id (), TyTy::UintType::U16))},
+    {LType ("u32", new TyTy::UintType (next_hir_id (), TyTy::UintType::U32))},
+    {LType ("u64", new TyTy::UintType (next_hir_id (), TyTy::UintType::U64))},
+    {LType ("u128", new TyTy::UintType (next_hir_id (), TyTy::UintType::U128))},
+    {LType ("i8", new TyTy::IntType (next_hir_id (), TyTy::IntType::I8))},
+    {LType ("i16", new TyTy::IntType (next_hir_id (), TyTy::IntType::I16))},
+    {LType ("i32", new TyTy::IntType (next_hir_id (), TyTy::IntType::I32))},
+    {LType ("i64", new TyTy::IntType (next_hir_id (), TyTy::IntType::I64))},
+    {LType ("i128", new TyTy::IntType (next_hir_id (), TyTy::IntType::I128))},
+    {LType ("f32", new TyTy::FloatType (next_hir_id (), TyTy::FloatType::F32))},
+    {LType ("f64", new TyTy::FloatType (next_hir_id (), TyTy::FloatType::F64))},
+    {LType ("usize", new TyTy::USizeType (next_hir_id ()))},
+    {LType ("isize", new TyTy::ISizeType (next_hir_id ()))},
+    {LType ("char", new TyTy::CharType (next_hir_id ()))},
+    {LType ("str", new TyTy::StrType (next_hir_id ()))},
+    {LType ("!", new TyTy::NeverType (next_hir_id ()))},
+
+    // the unit type `()` does not play a part in name-resolution - so we only
+    // insert it in the type context...
   };
 
   for (const auto &builtin : builtins)
     {
       // we should be able to use `insert_at_root` or `insert` here, since we're
       // at the root :) hopefully!
-      auto ok
-	= ctx.types.insert (builtin.first, builtin.second->get_ref ()
-			    /* FIXME: Invalid! This returns an *HirId* */);
-
+      auto ok = ctx.types.insert (builtin.name, builtin.node_id);
       rust_assert (ok);
+
+      ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
+      ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
     }
+
+  // ...here!
+  auto *unit_type = TyTy::TupleType::get_unit_type (next_hir_id ());
+  ty_ctx.insert_builtin (unit_type->get_ref (), next_node_id (), unit_type);
 }
 
 void
diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc
index a1981498673..dee3a09ad49 100644
--- a/gcc/rust/resolve/rust-rib.cc
+++ b/gcc/rust/resolve/rust-rib.cc
@@ -17,10 +17,27 @@ 
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-rib.h"
+#include "rust-name-resolution-context.h"
 
 namespace Rust {
 namespace Resolver2_0 {
 
+Rib::Definition::Definition (NodeId id, bool shadowable)
+  : id (id), shadowable (shadowable)
+{}
+
+Rib::Definition
+Rib::Definition::Shadowable (NodeId id)
+{
+  return Definition (id, true);
+}
+
+Rib::Definition
+Rib::Definition::NonShadowable (NodeId id)
+{
+  return Definition (id, false);
+}
+
 DuplicateNameError::DuplicateNameError (std::string name, NodeId existing)
   : name (name), existing (existing)
 {}
@@ -31,20 +48,23 @@  Rib::Rib (Kind kind, std::string identifier, NodeId id)
   : Rib (kind, {{identifier, id}})
 {}
 
-Rib::Rib (Kind kind, std::unordered_map<std::string, NodeId> values)
-  : kind (kind), values (std::move (values))
-{}
+Rib::Rib (Kind kind, std::unordered_map<std::string, NodeId> to_insert)
+  : kind (kind)
+{
+  for (auto &value : to_insert)
+    values.insert ({value.first, Definition::NonShadowable (value.second)});
+}
 
 tl::expected<NodeId, DuplicateNameError>
-Rib::insert (std::string name, NodeId id, bool can_shadow)
+Rib::insert (std::string name, Definition def)
 {
-  auto res = values.insert ({name, id});
-  auto inserted_id = res.first->second;
+  auto res = values.insert ({name, def});
+  auto inserted_id = res.first->second.id;
   auto existed = !res.second;
 
   // if we couldn't insert, the element already exists - exit with an error,
   // unless shadowing is allowed
-  if (existed && !can_shadow)
+  if (existed && !def.shadowable)
     return tl::make_unexpected (DuplicateNameError (name, inserted_id));
 
   // return the NodeId
@@ -59,10 +79,10 @@  Rib::get (const std::string &name)
   if (it == values.end ())
     return {};
 
-  return it->second;
+  return it->second.id;
 }
 
-const std::unordered_map<std::string, NodeId> &
+const std::unordered_map<std::string, Rib::Definition> &
 Rib::get_values () const
 {
   return values;
diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h
index da777bb9ba7..732ad76b805 100644
--- a/gcc/rust/resolve/rust-rib.h
+++ b/gcc/rust/resolve/rust-rib.h
@@ -103,6 +103,24 @@  struct DuplicateNameError
 class Rib
 {
 public:
+  // TODO: Rename the class? to what? Binding? Declaration?
+  // This is useful for items which are in namespaces where shadowing is not
+  // allowed, but which are still shadowable! for example, when you do a glob
+  // import, if a later import has the same name as an item imported in the glob
+  // import, that glob imported item will need to get shadowed
+  class Definition
+  {
+  public:
+    static Definition NonShadowable (NodeId id);
+    static Definition Shadowable (NodeId id);
+
+    NodeId id;
+    bool shadowable;
+
+  private:
+    Definition (NodeId id, bool shadowable);
+  };
+
   enum class Kind
   {
     Normal,
@@ -131,15 +149,14 @@  public:
    * Insert a new node in the rib
    *
    * @param name The name associated with the AST node
-   * @param id Its NodeId
-   * @param can_shadow If the newly inserted value can shadow an existing one
+   * @param def The `Definition` to insert
    *
    * @return `DuplicateNameError` if the node is already present in the rib. The
    *         `DuplicateNameError` class contains the NodeId of the existing
    * node. Returns the new NodeId on success.
    */
-  tl::expected<NodeId, DuplicateNameError> insert (std::string name, NodeId id,
-						   bool can_shadow = false);
+  tl::expected<NodeId, DuplicateNameError> insert (std::string name,
+						   Definition def);
 
   /**
    * Access an inserted NodeId.
@@ -149,10 +166,11 @@  public:
   tl::optional<NodeId> get (const std::string &name);
 
   /* View all the values stored in the rib */
-  const std::unordered_map<std::string, NodeId> &get_values () const;
+  const std::unordered_map<std::string, Definition> &get_values () const;
 
 private:
-  std::unordered_map<std::string, NodeId> values;
+  // TODO: Switch this to (NodeId, shadowable = false);
+  std::unordered_map<std::string, Definition> values;
 };
 
 } // namespace Resolver2_0