From: Owen Avery <powerboat9.ga...@gmail.com>

This should improve our canonical path handling, without requiring
further tweaks to ForeverStack. This may also help if, in the future, we
have to move canonical path calculation to later compilation phases for
proper handling of generics.

gcc/rust/ChangeLog:

        * backend/rust-compile-base.cc
        (HIRCompileBase::compile_function): Since canonical paths
        returned from nr2.0 now include the crate name, avoid prepending
        the crate name again.

        * backend/rust-compile-implitem.cc (CompileTraitItem::visit):
        Use NameResolutionContext::to_canonical_path instead of
        ForeverStack::to_canonical_path.
        * backend/rust-compile-item.cc (CompileItem::visit): Likewise.
        * typecheck/rust-hir-type-check-enumitem.cc
        (TypeCheckEnumItem::visit): Likewise.
        * typecheck/rust-hir-type-check-implitem.cc
        (TypeCheckImplItem::visit): Likewise.
        * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit):
        Likewise.
        * typecheck/rust-hir-type-check.cc
        (TraitItemReference::get_type_from_fn): Likewise.

        * resolve/rust-default-resolver.cc (DefaultResolver::visit): Add
        Crate and EnumItem instance visitors, handle canonical path
        context scoping.
        * resolve/rust-default-resolver.h (DefaultResolver::visit): Add
        Crate and EnumItem instance visitors.
        * resolve/rust-early-name-resolver-2.0.cc (Early::go): Visit
        instances of Crate using the virtual member function visit.
        * resolve/rust-forever-stack.h
        (ForeverStack::to_canonical_path): Remove function declaration.
        * resolve/rust-forever-stack.hxx
        (ForeverStack::to_canonical_path): Remove function definition.
        * resolve/rust-late-name-resolver-2.0.cc (Late::go): Visit
        instances of Crate using the virtual member function visit.
        * resolve/rust-name-resolution-context.cc
        (CanonicalPathRecordCrateRoot::as_path): New function definition.
        (CanonicalPathRecordNormal::as_path): Likewise.
        (CanonicalPathRecordLookup::as_path): Likewise.
        (CanonicalPathRecordImpl::as_path): Likewise.
        (CanonicalPathRecordTraitImpl::as_path): Likewise.
        (NameResolutionContext::NameResolutionContext): Initialize
        member variable canonical_ctx.
        * resolve/rust-name-resolution-context.h: Include "rust-item.h".
        (class NameResolutionContext): Forward declare class.
        (class CanonicalPathRecord): New class.
        (class CanonicalPathRecordWithParent): Likewise.
        (class CanonicalPathRecordCrateRoot): Likewise.
        (class CanonicalPathRecordNormal): Likewise.
        (class CanonicalPathRecordLookup): Likewise.
        (class CanonicalPathRecordImpl): Likewise.
        (class CanonicalPathRecordTraitImpl): Likewise.
        (class CanonicalPathCtx): Likewise.
        (NameResolutionContext::canonical_ctx): New member variable.
        (NameResolutionContext::to_canonical_path): New member function.
        * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::go):
        Visit instances of Crate with the virtual member function visit.
        (TopLevel::visit): Handle canonical path context scoping for
        external crates, use DefaultResolver::visit when visiting
        instances of StructStruct.
        * util/rust-canonical-path.h (CanonicalPath::new_seg): Take path
        parameter by-value, as a duplicate instance will be constructed
        regardless.

gcc/testsuite/ChangeLog:

        * rust/compile/nr2/exclude: Remove canonical_paths1.rs.
---
 gcc/rust/backend/rust-compile-base.cc         |   5 -
 gcc/rust/backend/rust-compile-implitem.cc     |   6 +-
 gcc/rust/backend/rust-compile-item.cc         |  11 +-
 gcc/rust/resolve/rust-default-resolver.cc     | 169 ++++++++++--
 gcc/rust/resolve/rust-default-resolver.h      |   5 +
 .../resolve/rust-early-name-resolver-2.0.cc   |   5 +-
 gcc/rust/resolve/rust-forever-stack.h         |   3 -
 gcc/rust/resolve/rust-forever-stack.hxx       |  61 -----
 .../resolve/rust-late-name-resolver-2.0.cc    |   3 +-
 .../resolve/rust-name-resolution-context.cc   |  57 +++-
 .../resolve/rust-name-resolution-context.h    | 250 ++++++++++++++++++
 .../rust-toplevel-name-resolver-2.0.cc        |  24 +-
 .../typecheck/rust-hir-type-check-enumitem.cc |   8 +-
 .../typecheck/rust-hir-type-check-implitem.cc |   4 +-
 .../typecheck/rust-hir-type-check-item.cc     |  26 +-
 gcc/rust/typecheck/rust-hir-type-check.cc     |   2 +-
 gcc/rust/util/rust-canonical-path.h           |   5 +-
 gcc/testsuite/rust/compile/nr2/exclude        |   1 -
 18 files changed, 493 insertions(+), 152 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-base.cc 
b/gcc/rust/backend/rust-compile-base.cc
index 12b956168bd..84c4bcd3fe4 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -687,11 +687,6 @@ HIRCompileBase::compile_function (
     }
   std::string asm_name = fn_name;
 
-  auto &mappings = Analysis::Mappings::get ();
-
-  if (flag_name_resolution_2_0)
-    ir_symbol_name = mappings.get_current_crate_name () + "::" + 
ir_symbol_name;
-
   unsigned int flags = 0;
   tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name,
                                   "" /* asm_name */, flags, locus);
diff --git a/gcc/rust/backend/rust-compile-implitem.cc 
b/gcc/rust/backend/rust-compile-implitem.cc
index 1230c85c57c..f9172c5282c 100644
--- a/gcc/rust/backend/rust-compile-implitem.cc
+++ b/gcc/rust/backend/rust-compile-implitem.cc
@@ -33,8 +33,8 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      canonical_path = nr_ctx.values.to_canonical_path (
-       constant.get_mappings ().get_nodeid ());
+      canonical_path
+       = nr_ctx.to_canonical_path (constant.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -103,7 +103,7 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func)
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.values.to_canonical_path (func.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (func.get_mappings ().get_nodeid ());
     }
   else
     {
diff --git a/gcc/rust/backend/rust-compile-item.cc 
b/gcc/rust/backend/rust-compile-item.cc
index 96669903fd5..3e7ea9a25e9 100644
--- a/gcc/rust/backend/rust-compile-item.cc
+++ b/gcc/rust/backend/rust-compile-item.cc
@@ -58,7 +58,7 @@ CompileItem::visit (HIR::StaticItem &var)
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.values.to_canonical_path (var.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (var.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -124,8 +124,7 @@ CompileItem::visit (HIR::ConstantItem &constant)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      canonical_path
-       = nr_ctx.values.to_canonical_path (mappings.get_nodeid ()).value ();
+      canonical_path = nr_ctx.to_canonical_path (mappings.get_nodeid ());
     }
   else
     {
@@ -218,10 +217,8 @@ CompileItem::visit (HIR::Function &function)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      auto path = nr_ctx.values.to_canonical_path (
-       function.get_mappings ().get_nodeid ());
-
-      canonical_path = path.value ();
+      canonical_path
+       = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ());
     }
   else
     {
diff --git a/gcc/rust/resolve/rust-default-resolver.cc 
b/gcc/rust/resolve/rust-default-resolver.cc
index a4793c04870..969711c2995 100644
--- a/gcc/rust/resolve/rust-default-resolver.cc
+++ b/gcc/rust/resolve/rust-default-resolver.cc
@@ -24,6 +24,21 @@
 namespace Rust {
 namespace Resolver2_0 {
 
+void
+DefaultResolver::visit (AST::Crate &crate)
+{
+  auto inner_fn = [this, &crate] () { AST::DefaultASTVisitor::visit (crate); };
+
+  auto &mappings = Analysis::Mappings::get ();
+
+  auto crate_num = mappings.lookup_crate_num (crate.get_node_id ());
+  rust_assert (crate_num.has_value ());
+  auto crate_name = mappings.get_crate_name (*crate_num);
+  rust_assert (crate_name.has_value ());
+
+  ctx.canonical_ctx.scope_crate (crate.get_node_id (), *crate_name, inner_fn);
+}
+
 void
 DefaultResolver::visit (AST::BlockExpr &expr)
 {
@@ -38,19 +53,32 @@ DefaultResolver::visit (AST::BlockExpr &expr)
 void
 DefaultResolver::visit (AST::Module &module)
 {
-  auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); 
};
+  auto item_fn_1
+    = [this, &module] () { AST::DefaultASTVisitor::visit (module); };
 
-  ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn,
+  auto item_fn_2 = [this, &module, &item_fn_1] () {
+    ctx.canonical_ctx.scope (module.get_node_id (), module.get_name (),
+                            std::move (item_fn_1));
+  };
+
+  ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn_2,
              module.get_name ());
 }
 
 void
 DefaultResolver::visit (AST::Function &function)
 {
-  auto def_fn
+  auto def_fn_1
     = [this, &function] () { AST::DefaultASTVisitor::visit (function); };
 
-  ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn);
+  auto def_fn_2 = [this, &function, &def_fn_1] () {
+    ctx.canonical_ctx.scope (function.get_node_id (),
+                            function.get_function_name (),
+                            std::move (def_fn_1));
+  };
+
+  ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn_2,
+             function.get_function_name ());
 }
 
 void
@@ -85,9 +113,15 @@ DefaultResolver::visit (AST::IfLetExpr &expr)
 void
 DefaultResolver::visit (AST::Trait &trait)
 {
-  auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); };
+  auto inner_fn_1
+    = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); };
+
+  auto inner_fn_2 = [this, &trait, &inner_fn_1] () {
+    ctx.canonical_ctx.scope (trait.get_node_id (), trait.get_identifier (),
+                            std::move (inner_fn_1));
+  };
 
-  ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn,
+  ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn_2,
              trait.get_identifier () /* FIXME: Is that valid?*/);
 }
 
@@ -98,12 +132,12 @@ DefaultResolver::visit (AST::InherentImpl &impl)
   visit (impl.get_visibility ());
   visit_inner_attrs (impl);
 
-  auto inner_fn_inner = [this, &impl] () {
+  auto inner_fn_1 = [this, &impl] () {
     for (auto &item : impl.get_impl_items ())
       visit (item);
   };
 
-  auto inner_fn_outer = [this, &impl, &inner_fn_inner] () {
+  auto inner_fn_2 = [this, &impl, &inner_fn_1] () {
     maybe_insert_big_self (impl);
     for (auto &generic : impl.get_generic_params ())
       visit (generic);
@@ -111,10 +145,14 @@ DefaultResolver::visit (AST::InherentImpl &impl)
       visit (impl.get_where_clause ());
     visit_impl_type (impl.get_type ());
 
-    ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_inner);
+    ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1);
   };
 
-  ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_outer);
+  auto inner_fn_3 = [this, &impl, &inner_fn_2] () {
+    ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2));
+  };
+
+  ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3);
 }
 
 void
@@ -124,12 +162,12 @@ DefaultResolver::visit (AST::TraitImpl &impl)
   visit (impl.get_visibility ());
   visit_inner_attrs (impl);
 
-  auto inner_fn_inner = [this, &impl] () {
+  auto inner_fn_1 = [this, &impl] () {
     for (auto &item : impl.get_impl_items ())
       visit (item);
   };
 
-  auto inner_fn_outer = [this, &impl, &inner_fn_inner] () {
+  auto inner_fn_2 = [this, &impl, &inner_fn_1] () {
     maybe_insert_big_self (impl);
     for (auto &generic : impl.get_generic_params ())
       visit (generic);
@@ -138,55 +176,120 @@ DefaultResolver::visit (AST::TraitImpl &impl)
     visit_impl_type (impl.get_type ());
     visit (impl.get_trait_path ());
 
-    ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_inner);
+    ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1);
+  };
+
+  auto inner_fn_3 = [this, &impl, &inner_fn_2] () {
+    ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2));
   };
 
-  ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_outer);
+  ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3);
 }
 
 void
 DefaultResolver::visit (AST::StructStruct &type)
 {
-  auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+  auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+
+  auto inner_fn_2 = [this, &type, &inner_fn_1] () {
+    ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (),
+                            std::move (inner_fn_1));
+  };
 
   ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
-             inner_fn, type.get_struct_name ());
+             inner_fn_2, type.get_struct_name ());
 }
 
 void
 DefaultResolver::visit (AST::TupleStruct &type)
 {
-  auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+  auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+
+  auto inner_fn_2 = [this, &type, &inner_fn_1] () {
+    ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (),
+                            std::move (inner_fn_1));
+  };
 
   ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
-             inner_fn, type.get_struct_name ());
+             inner_fn_2, type.get_struct_name ());
+}
+
+void
+DefaultResolver::visit (AST::EnumItem &item)
+{
+  auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
+
+  ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (),
+                          inner_fn);
+}
+
+void
+DefaultResolver::visit (AST::EnumItemTuple &item)
+{
+  auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
+
+  ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (),
+                          inner_fn);
+}
+
+void
+DefaultResolver::visit (AST::EnumItemStruct &item)
+{
+  auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
+
+  ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (),
+                          inner_fn);
+}
+
+void
+DefaultResolver::visit (AST::EnumItemDiscriminant &item)
+{
+  auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
+
+  ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (),
+                          inner_fn);
 }
 
 void
 DefaultResolver::visit (AST::Enum &type)
 {
-  auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+  auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+
+  auto inner_fn_2 = [this, &type, &inner_fn_1] () {
+    ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (),
+                            std::move (inner_fn_1));
+  };
 
   ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
-             variant_fn, type.get_identifier ());
+             inner_fn_2, type.get_identifier ());
 }
 
 void
 DefaultResolver::visit (AST::Union &type)
 {
-  auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+  auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+
+  auto inner_fn_2 = [this, &type, &inner_fn_1] () {
+    ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (),
+                            std::move (inner_fn_1));
+  };
 
   ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
-             inner_fn, type.get_identifier ());
+             inner_fn_2, type.get_identifier ());
 }
 
 void
 DefaultResolver::visit (AST::TypeAlias &type)
 {
-  auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+  auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
+
+  auto inner_fn_2 = [this, &type, &inner_fn_1] () {
+    ctx.canonical_ctx.scope (type.get_node_id (), type.get_new_type_name (),
+                            std::move (inner_fn_1));
+  };
 
   ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
-             inner_fn, type.get_new_type_name ());
+             inner_fn_2, type.get_new_type_name ());
 }
 
 void
@@ -221,21 +324,31 @@ DefaultResolver::visit (AST::ConstantItem &item)
 {
   if (item.has_expr ())
     {
-      auto expr_vis
+      auto expr_vis_1
        = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
 
+      auto expr_vis_2 = [this, &item, &expr_vis_1] () {
+       ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (),
+                                std::move (expr_vis_1));
+      };
+
       // FIXME: Why do we need a Rib here?
-      ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
+      ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2);
     }
 }
 
 void
 DefaultResolver::visit (AST::StaticItem &item)
 {
-  auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
+  auto expr_vis_1 = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
+
+  auto expr_vis_2 = [this, &item, &expr_vis_1] () {
+    ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (),
+                            std::move (expr_vis_1));
+  };
 
   // FIXME: Why do we need a Rib here?
-  ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
+  ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2);
 }
 
 void
diff --git a/gcc/rust/resolve/rust-default-resolver.h 
b/gcc/rust/resolve/rust-default-resolver.h
index f500d9018f2..e80d77440b1 100644
--- a/gcc/rust/resolve/rust-default-resolver.h
+++ b/gcc/rust/resolve/rust-default-resolver.h
@@ -39,6 +39,7 @@ public:
 
   virtual ~DefaultResolver () {}
 
+  void visit (AST::Crate &) override;
   // First, our lexical scope expressions - these visit their sub nodes, always
   // these nodes create new scopes and ribs - they are often used to declare 
new
   // variables, such as a for loop's iterator, or a function's arguments
@@ -60,6 +61,10 @@ public:
   // type dec nodes, which visit their fields or variants by default
   void visit (AST::StructStruct &) override;
   void visit (AST::TupleStruct &) override;
+  void visit (AST::EnumItem &) override;
+  void visit (AST::EnumItemTuple &) override;
+  void visit (AST::EnumItemStruct &) override;
+  void visit (AST::EnumItemDiscriminant &) override;
   void visit (AST::Enum &) override;
   void visit (AST::Union &) override;
   void visit (AST::TypeAlias &) override;
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 b00bd1ee7f8..c10379a65eb 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -62,8 +62,9 @@ Early::go (AST::Crate &crate)
   // 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);
+
+  visit (crate);
+
   textual_scope.pop ();
 }
 
diff --git a/gcc/rust/resolve/rust-forever-stack.h 
b/gcc/rust/resolve/rust-forever-stack.h
index 3f6f002da68..75dd87395be 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -683,9 +683,6 @@ public:
     std::function<void (const S &, NodeId)> insert_segment_resolution,
     std::vector<Error> &collect_errors);
 
-  // FIXME: Documentation
-  tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const;
-
   // FIXME: Documentation
   tl::optional<Rib &> to_rib (NodeId rib_id);
   tl::optional<const Rib &> to_rib (NodeId rib_id) const;
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx 
b/gcc/rust/resolve/rust-forever-stack.hxx
index d568682786c..df3df1059fc 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -773,67 +773,6 @@ ForeverStack<N>::dfs (const ForeverStack<N>::Node 
&starting_point,
   return tl::nullopt;
 }
 
-template <Namespace N>
-tl::optional<Resolver::CanonicalPath>
-ForeverStack<N>::to_canonical_path (NodeId id) const
-{
-  // find the id in the current forever stack, starting from the root,
-  // performing either a BFS or DFS once the Node containing the ID is found, 
go
-  // back up to the root (parent().parent().parent()...) accumulate link
-  // segments reverse them that's your canonical path
-
-  return dfs (root, id).map ([this, id] (ConstDfsResult tuple) {
-    auto containing_node = tuple.first;
-    auto name = tuple.second;
-
-    auto segments = std::vector<Resolver::CanonicalPath> ();
-
-    reverse_iter (containing_node, [&segments] (const Node &current) {
-      if (current.is_root ())
-       return KeepGoing::No;
-
-      auto children = current.parent.value ().children;
-      const Link *outer_link = nullptr;
-
-      for (auto &kv : children)
-       {
-         auto &link = kv.first;
-         auto &child = kv.second;
-
-         if (current.id == child.id)
-           {
-             outer_link = &link;
-             break;
-           }
-       }
-
-      rust_assert (outer_link);
-
-      outer_link->path.map ([&segments, outer_link] (Identifier path) {
-       segments.emplace (segments.begin (),
-                         Resolver::CanonicalPath::new_seg (outer_link->id,
-                                                           path.as_string ()));
-      });
-
-      return KeepGoing::Yes;
-    });
-
-    auto &mappings = Analysis::Mappings::get ();
-    CrateNum crate_num = mappings.lookup_crate_num (root.id).value ();
-    auto path = Resolver::CanonicalPath::new_seg (
-      root.id, mappings.get_crate_name (crate_num).value ());
-    path.set_crate_num (crate_num);
-
-    for (const auto &segment : segments)
-      path = path.append (segment);
-
-    // Finally, append the name
-    path = path.append (Resolver::CanonicalPath::new_seg (id, name));
-
-    return path;
-  });
-}
-
 template <Namespace N>
 tl::optional<Rib &>
 ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId 
to_find)
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 99e79868246..1c0850c66f4 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -116,8 +116,7 @@ Late::go (AST::Crate &crate)
 {
   setup_builtin_types ();
 
-  for (auto &item : crate.items)
-    item->accept_vis (*this);
+  visit (crate);
 }
 
 void
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc 
b/gcc/rust/resolve/rust-name-resolution-context.cc
index f098e4880e5..34615ed97c3 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -82,8 +82,63 @@ BindingLayer::get_source () const
   return source;
 }
 
+Resolver::CanonicalPath
+CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &)
+{
+  auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
+  ret.set_crate_num (crate_num);
+  return ret;
+}
+
+Resolver::CanonicalPath
+CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx)
+{
+  auto parent_path = get_parent ().as_path (ctx);
+  return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
+}
+
+Resolver::CanonicalPath
+CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx)
+{
+  if (!cache)
+    {
+      auto res = ctx.lookup (lookup_id).and_then (
+       [&ctx] (NodeId id) { return ctx.canonical_ctx.get_record_opt (id); });
+
+      if (!res)
+       {
+         // HACK: use a dummy value
+         // this should bring us roughly to parity with nr1.0
+         // since nr1.0 doesn't seem to handle canonical paths for generics
+         //   quite right anyways
+         return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
+       }
+
+      cache = res.value ();
+    }
+  return cache->as_path (ctx);
+}
+
+Resolver::CanonicalPath
+CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx)
+{
+  auto parent_path = get_parent ().as_path (ctx);
+  return parent_path.append (
+    Resolver::CanonicalPath::inherent_impl_seg (impl_id,
+                                               type_record.as_path (ctx)));
+}
+
+Resolver::CanonicalPath
+CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx)
+{
+  auto parent_path = get_parent ().as_path (ctx);
+  return parent_path.append (
+    Resolver::CanonicalPath::trait_impl_projection_seg (
+      impl_id, trait_path_record.as_path (ctx), type_record.as_path (ctx)));
+}
+
 NameResolutionContext::NameResolutionContext ()
-  : mappings (Analysis::Mappings::get ())
+  : mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
 {}
 
 tl::expected<NodeId, DuplicateNameError>
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h 
b/gcc/rust/resolve/rust-name-resolution-context.h
index 1509857739e..bb8519a0493 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -24,6 +24,7 @@
 #include "rust-hir-map.h"
 #include "rust-rib.h"
 #include "rust-stacked-contexts.h"
+#include "rust-item.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -214,6 +215,248 @@ public:
   BindingSource get_source () const;
 };
 
+class NameResolutionContext;
+/*
+ * Used to handle canonical paths
+ * Similar to ForeverStack, but namespace independent and more specialized
+ */
+class CanonicalPathRecord
+{
+public:
+  virtual Resolver::CanonicalPath as_path (const NameResolutionContext &) = 0;
+
+  virtual bool is_root () const = 0;
+
+  virtual ~CanonicalPathRecord () = default;
+};
+
+class CanonicalPathRecordWithParent : public CanonicalPathRecord
+{
+public:
+  CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent 
(&parent)
+  {}
+
+  CanonicalPathRecord &get_parent () { return *parent; }
+
+  bool is_root () const override final { return false; }
+
+private:
+  CanonicalPathRecord *parent;
+};
+
+class CanonicalPathRecordCrateRoot : public CanonicalPathRecord
+{
+public:
+  CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg)
+    : node_id (node_id), seg (std::move (seg))
+  {
+    rust_assert (Analysis::Mappings::get ().node_is_crate (node_id));
+    crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value ();
+  }
+
+  Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
+
+  bool is_root () const override final { return true; }
+
+private:
+  NodeId node_id;
+  CrateNum crate_num;
+  std::string seg;
+};
+
+class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent
+{
+public:
+  CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id,
+                            std::string seg)
+    : CanonicalPathRecordWithParent (parent), node_id (node_id),
+      seg (std::move (seg))
+  {
+    rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id));
+  }
+
+  Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
+
+private:
+  NodeId node_id;
+  std::string seg;
+};
+
+class CanonicalPathRecordLookup : public CanonicalPathRecord
+{
+public:
+  CanonicalPathRecordLookup (NodeId lookup_id)
+    : lookup_id (lookup_id), cache (nullptr)
+  {}
+
+  Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
+
+  bool is_root () const override final { return true; }
+
+private:
+  NodeId lookup_id;
+  CanonicalPathRecord *cache;
+};
+
+class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent
+{
+public:
+  CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id,
+                          NodeId type_id)
+    : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
+      type_record (type_id)
+  {}
+
+  Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
+
+private:
+  NodeId impl_id;
+  CanonicalPathRecordLookup type_record;
+};
+
+class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent
+{
+public:
+  CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id,
+                               NodeId type_id, NodeId trait_path_id)
+    : CanonicalPathRecordWithParent (parent), impl_id (impl_id),
+      type_record (type_id), trait_path_record (trait_path_id)
+  {}
+
+  Resolver::CanonicalPath as_path (const NameResolutionContext &) override;
+
+private:
+  NodeId impl_id;
+  CanonicalPathRecordLookup type_record;
+  CanonicalPathRecordLookup trait_path_record;
+};
+
+class CanonicalPathCtx
+{
+public:
+  CanonicalPathCtx (const NameResolutionContext &ctx)
+    : current_record (nullptr), nr_ctx (&ctx)
+  {}
+
+  Resolver::CanonicalPath get_path (NodeId id) const
+  {
+    return get_record (id).as_path (*nr_ctx);
+  }
+
+  CanonicalPathRecord &get_record (NodeId id) const
+  {
+    auto it = records.find (id);
+    rust_assert (it != records.end ());
+    return *it->second;
+  }
+
+  tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const
+  {
+    auto it = records.find (id);
+    if (it == records.end ())
+      return tl::nullopt;
+    else
+      return it->second.get ();
+  }
+
+  void insert_record (NodeId id, const Identifier &ident)
+  {
+    insert_record (id, ident.as_string ());
+  }
+
+  void insert_record (NodeId id, std::string seg)
+  {
+    rust_assert (current_record != nullptr);
+
+    auto it = records.find (id);
+    if (it == records.end ())
+      {
+       auto record = new CanonicalPathRecordNormal (*current_record, id,
+                                                    std::move (seg));
+       bool ok
+         = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
+             .second;
+       rust_assert (ok);
+      }
+  }
+
+  template <typename F> void scope (NodeId id, const Identifier &ident, F &&f)
+  {
+    scope (id, ident.as_string (), std::forward<F> (f));
+  }
+
+  template <typename F> void scope (NodeId id, std::string seg, F &&f)
+  {
+    rust_assert (current_record != nullptr);
+
+    scope_inner (id, std::forward<F> (f), [this, id, &seg] () {
+      return new CanonicalPathRecordNormal (*current_record, id,
+                                           std::move (seg));
+    });
+  }
+
+  template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f)
+  {
+    rust_assert (current_record != nullptr);
+
+    NodeId id = impl.get_node_id ();
+    scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
+      return new CanonicalPathRecordImpl (*current_record, id,
+                                         impl.get_type ().get_node_id ());
+    });
+  }
+
+  template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f)
+  {
+    rust_assert (current_record != nullptr);
+
+    NodeId id = impl.get_node_id ();
+    scope_inner (id, std::forward<F> (f), [this, id, &impl] () {
+      return new CanonicalPathRecordTraitImpl (
+       *current_record, id, impl.get_type ().get_node_id (),
+       impl.get_trait_path ().get_node_id ());
+    });
+  }
+
+  template <typename F>
+  void scope_crate (NodeId node_id, std::string crate_name, F &&f)
+  {
+    scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () {
+      return new CanonicalPathRecordCrateRoot (node_id, std::move 
(crate_name));
+    });
+  }
+
+private:
+  template <typename FCreate, typename FCallback>
+  void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create)
+  {
+    auto it = records.find (id);
+    if (it == records.end ())
+      {
+       CanonicalPathRecord *record = std::forward<FCreate> (f_create) ();
+       it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record))
+              .first;
+      }
+
+    rust_assert (it->second->is_root ()
+                || &static_cast<CanonicalPathRecordWithParent &> (*it->second)
+                       .get_parent ()
+                     == current_record);
+
+    CanonicalPathRecord *stash = it->second.get ();
+    std::swap (stash, current_record);
+
+    std::forward<FCallback> (f_callback) ();
+
+    std::swap (stash, current_record);
+  }
+
+  std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records;
+  CanonicalPathRecord *current_record;
+
+  const NameResolutionContext *nr_ctx;
+};
+
 // Now our resolver, which keeps track of all the `ForeverStack`s we could want
 class NameResolutionContext
 {
@@ -272,12 +515,19 @@ public:
   Analysis::Mappings &mappings;
   StackedContexts<BindingLayer> bindings;
 
+  CanonicalPathCtx canonical_ctx;
+
   // TODO: Rename
   // TODO: Use newtype pattern for Usage and Definition
   void map_usage (Usage usage, Definition definition);
 
   tl::optional<NodeId> lookup (NodeId usage) const;
 
+  Resolver::CanonicalPath to_canonical_path (NodeId id) const
+  {
+    return canonical_ctx.get_path (id);
+  }
+
   template <typename S>
   tl::optional<Rib::Definition>
   resolve_path (const std::vector<S> &segments, ResolutionMode mode,
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 4d88ad1eb37..3e5ed534e4e 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -95,8 +95,7 @@ TopLevel::go (AST::Crate &crate)
   // times in a row in a fixed-point fashion, so it would make the code
   // responsible for this ugly and perfom a lot of error checking.
 
-  for (auto &item : crate.items)
-    item->accept_vis (*this);
+  visit (crate);
 }
 
 void
@@ -194,7 +193,7 @@ TopLevel::visit (AST::ExternCrate &crate)
 
   auto derive_macros = mappings.lookup_derive_proc_macros (num);
 
-  auto sub_visitor = [&] () {
+  auto sub_visitor_1 = [&] () {
     // TODO: Find a way to keep this part clean without the double dispatch.
     if (derive_macros.has_value ())
       {
@@ -216,11 +215,17 @@ TopLevel::visit (AST::ExternCrate &crate)
       }
   };
 
+  auto sub_visitor_2 = [&] () {
+    ctx.canonical_ctx.scope_crate (crate.get_node_id (),
+                                  crate.get_referenced_crate (),
+                                  std::move (sub_visitor_1));
+  };
+
   if (crate.has_as_clause ())
-    ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor,
+    ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor_2,
                crate.get_as_clause ());
   else
-    ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor,
+    ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor_2,
                crate.get_referenced_crate ());
 }
 
@@ -298,14 +303,7 @@ TopLevel::visit (AST::ExternalStaticItem &static_item)
 void
 TopLevel::visit (AST::StructStruct &struct_item)
 {
-  auto generic_vis = [this, &struct_item] () {
-    for (auto &g : struct_item.get_generic_params ())
-      {
-       g->accept_vis (*this);
-      }
-  };
-
-  ctx.scoped (Rib::Kind::Item, struct_item.get_node_id (), generic_vis);
+  DefaultResolver::visit (struct_item);
 
   insert_or_error_out (struct_item.get_struct_name (), struct_item,
                       Namespace::Types);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc 
b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
index c80a12f8f84..2dbd84d254a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
@@ -87,7 +87,7 @@ TypeCheckEnumItem::visit (HIR::EnumItem &item)
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -131,7 +131,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item)
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -193,7 +193,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemTuple &item)
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -253,7 +253,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemStruct &item)
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ());
     }
   else
     {
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc 
b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 168a934fa54..00f0cc66974 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -345,8 +345,8 @@ TypeCheckImplItem::visit (HIR::Function &function)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      canonical_path = nr_ctx.values.to_canonical_path (
-       function.get_mappings ().get_nodeid ());
+      canonical_path
+       = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ());
     }
   else
     {
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index aaa04af628f..5595dad22cc 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -203,9 +203,8 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      path = nr_ctx.values
-              .to_canonical_path (struct_decl.get_mappings ().get_nodeid ())
-              .value ();
+      path
+       = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -283,12 +282,8 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
     {
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
-      auto canonical_path = nr_ctx.types.to_canonical_path (
-       struct_decl.get_mappings ().get_nodeid ());
-
-      if (!canonical_path.has_value ())
-       rust_unreachable ();
-      path = canonical_path.value ();
+      path
+       = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -375,8 +370,8 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      canonical_path = nr_ctx.types.to_canonical_path (
-       enum_decl.get_mappings ().get_nodeid ());
+      canonical_path
+       = nr_ctx.to_canonical_path (enum_decl.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -439,8 +434,8 @@ TypeCheckItem::visit (HIR::Union &union_decl)
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
-      canonical_path = nr_ctx.types.to_canonical_path (
-       union_decl.get_mappings ().get_nodeid ());
+      canonical_path
+       = nr_ctx.to_canonical_path (union_decl.get_mappings ().get_nodeid ());
     }
   else
     {
@@ -614,10 +609,7 @@ TypeCheckItem::visit (HIR::Function &function)
     {
       auto &nr_ctx
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
-      auto canonical_path = nr_ctx.values.to_canonical_path (
-       function.get_mappings ().get_nodeid ());
-
-      path = canonical_path.value ();
+      path = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ());
     }
   else
     {
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc 
b/gcc/rust/typecheck/rust-hir-type-check.cc
index d386fda036b..27879e3d4e9 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -284,7 +284,7 @@ TraitItemReference::get_type_from_fn (/*const*/ 
HIR::TraitItemFunc &fn) const
        = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
 
       canonical_path
-       = nr_ctx.values.to_canonical_path (fn.get_mappings ().get_nodeid ());
+       = nr_ctx.to_canonical_path (fn.get_mappings ().get_nodeid ());
     }
   else
     {
diff --git a/gcc/rust/util/rust-canonical-path.h 
b/gcc/rust/util/rust-canonical-path.h
index ee37befb2e0..079ae76eadb 100644
--- a/gcc/rust/util/rust-canonical-path.h
+++ b/gcc/rust/util/rust-canonical-path.h
@@ -57,10 +57,11 @@ public:
     return *this;
   }
 
-  static CanonicalPath new_seg (NodeId id, const std::string &path)
+  static CanonicalPath new_seg (NodeId id, std::string path)
   {
     rust_assert (!path.empty ());
-    return CanonicalPath ({std::pair<NodeId, std::string> (id, path)},
+    return CanonicalPath ({std::pair<NodeId, std::string> (id,
+                                                          std::move (path))},
                          UNKNOWN_CRATENUM);
   }
 
diff --git a/gcc/testsuite/rust/compile/nr2/exclude 
b/gcc/testsuite/rust/compile/nr2/exclude
index dc8d5fbcc08..9d5b7dfbbd3 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -1,4 +1,3 @@
-canonical_paths1.rs
 issue-3315-2.rs
 privacy8.rs
 pub_restricted_1.rs
-- 
2.49.0

Reply via email to