diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc
new file mode 100644
index 00000000000..2a78918fbdb
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-base.cc
@@ -0,0 +1,658 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-resolve-path.h"
+#include "rust-item.h"
+
+namespace Rust {
+namespace Resolver {
+
+bool
+ResolverBase::resolve_visibility (const AST::Visibility &vis)
+{
+  if (vis.has_path ())
+    {
+      auto path = vis.get_path ();
+      ResolvePath::go (&path);
+
+      // Do we need to lookup something here?
+      // Is it just about resolving the names correctly so we can look them up
+      // later?
+    }
+
+  return true;
+}
+
+// Default visitors implementations
+
+void
+ResolverBase::visit (AST::Token &)
+{}
+
+void
+ResolverBase::visit (AST::DelimTokenTree &)
+{}
+
+void
+ResolverBase::visit (AST::AttrInputMetaItemContainer &)
+{}
+
+void
+ResolverBase::visit (AST::IdentifierExpr &)
+{}
+
+void
+ResolverBase::visit (AST::Lifetime &)
+{}
+
+void
+ResolverBase::visit (AST::LifetimeParam &)
+{}
+
+void
+ResolverBase::visit (AST::ConstGenericParam &)
+{}
+
+void
+ResolverBase::visit (AST::PathInExpression &)
+{}
+
+void
+ResolverBase::visit (AST::TypePathSegment &)
+{}
+
+void
+ResolverBase::visit (AST::TypePathSegmentGeneric &)
+{}
+
+void
+ResolverBase::visit (AST::TypePathSegmentFunction &)
+{}
+
+void
+ResolverBase::visit (AST::TypePath &)
+{}
+
+void
+ResolverBase::visit (AST::QualifiedPathInExpression &)
+{}
+
+void
+ResolverBase::visit (AST::QualifiedPathInType &)
+{}
+
+void
+ResolverBase::visit (AST::LiteralExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AttrInputLiteral &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemLitExpr &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemPathLit &)
+{}
+
+void
+ResolverBase::visit (AST::BorrowExpr &)
+{}
+
+void
+ResolverBase::visit (AST::DereferenceExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ErrorPropagationExpr &)
+{}
+
+void
+ResolverBase::visit (AST::NegationExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ArithmeticOrLogicalExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ComparisonExpr &)
+{}
+
+void
+ResolverBase::visit (AST::LazyBooleanExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TypeCastExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AssignmentExpr &)
+{}
+
+void
+ResolverBase::visit (AST::CompoundAssignmentExpr &)
+{}
+
+void
+ResolverBase::visit (AST::GroupedExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayElemsValues &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayElemsCopied &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayIndexExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TupleExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TupleIndexExpr &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprStruct &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprFieldIdentifier &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprFieldIdentifierValue &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprFieldIndexValue &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprStructFields &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprStructBase &)
+{}
+
+void
+ResolverBase::visit (AST::CallExpr &)
+{}
+
+void
+ResolverBase::visit (AST::MethodCallExpr &)
+{}
+
+void
+ResolverBase::visit (AST::FieldAccessExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ClosureExprInner &)
+{}
+
+void
+ResolverBase::visit (AST::BlockExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ClosureExprInnerTyped &)
+{}
+
+void
+ResolverBase::visit (AST::ContinueExpr &)
+{}
+
+void
+ResolverBase::visit (AST::BreakExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFromToExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFromExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeToExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFullExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFromToInclExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeToInclExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ReturnExpr &)
+{}
+
+void
+ResolverBase::visit (AST::UnsafeBlockExpr &)
+{}
+
+void
+ResolverBase::visit (AST::LoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::WhileLoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::WhileLetLoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ForLoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::IfExpr &)
+{}
+
+void
+ResolverBase::visit (AST::IfExprConseqElse &)
+{}
+
+void
+ResolverBase::visit (AST::IfExprConseqIf &)
+{}
+
+void
+ResolverBase::visit (AST::IfExprConseqIfLet &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExpr &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExprConseqElse &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExprConseqIf &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExprConseqIfLet &)
+{}
+
+void
+ResolverBase::visit (AST::MatchExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AwaitExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AsyncBlockExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TypeParam &)
+{}
+
+void
+ResolverBase::visit (AST::LifetimeWhereClauseItem &)
+{}
+
+void
+ResolverBase::visit (AST::TypeBoundWhereClauseItem &)
+{}
+
+void
+ResolverBase::visit (AST::Method &)
+{}
+
+void
+ResolverBase::visit (AST::Module &)
+{}
+
+void
+ResolverBase::visit (AST::ExternCrate &)
+{}
+
+void
+ResolverBase::visit (AST::UseTreeGlob &)
+{}
+
+void
+ResolverBase::visit (AST::UseTreeList &)
+{}
+
+void
+ResolverBase::visit (AST::UseTreeRebind &)
+{}
+
+void
+ResolverBase::visit (AST::UseDeclaration &)
+{}
+
+void
+ResolverBase::visit (AST::Function &)
+{}
+
+void
+ResolverBase::visit (AST::TypeAlias &)
+{}
+
+void
+ResolverBase::visit (AST::StructStruct &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStruct &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItem &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItemTuple &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItemStruct &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItemDiscriminant &)
+{}
+
+void
+ResolverBase::visit (AST::Enum &)
+{}
+
+void
+ResolverBase::visit (AST::Union &)
+{}
+
+void
+ResolverBase::visit (AST::ConstantItem &)
+{}
+
+void
+ResolverBase::visit (AST::StaticItem &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemFunc &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemMethod &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemConst &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemType &)
+{}
+
+void
+ResolverBase::visit (AST::Trait &)
+{}
+
+void
+ResolverBase::visit (AST::InherentImpl &)
+{}
+
+void
+ResolverBase::visit (AST::TraitImpl &)
+{}
+
+void
+ResolverBase::visit (AST::ExternalStaticItem &)
+{}
+
+void
+ResolverBase::visit (AST::ExternalFunctionItem &)
+{}
+
+void
+ResolverBase::visit (AST::ExternBlock &)
+{}
+
+void
+ResolverBase::visit (AST::MacroMatchFragment &)
+{}
+
+void
+ResolverBase::visit (AST::MacroMatchRepetition &)
+{}
+
+void
+ResolverBase::visit (AST::MacroMatcher &)
+{}
+
+void
+ResolverBase::visit (AST::MacroRulesDefinition &)
+{}
+
+void
+ResolverBase::visit (AST::MacroInvocation &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemPath &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemSeq &)
+{}
+
+void
+ResolverBase::visit (AST::MetaWord &)
+{}
+
+void
+ResolverBase::visit (AST::MetaNameValueStr &)
+{}
+
+void
+ResolverBase::visit (AST::MetaListPaths &)
+{}
+
+void
+ResolverBase::visit (AST::MetaListNameValueStr &)
+{}
+
+void
+ResolverBase::visit (AST::LiteralPattern &)
+{}
+
+void
+ResolverBase::visit (AST::IdentifierPattern &)
+{}
+
+void
+ResolverBase::visit (AST::WildcardPattern &)
+{}
+
+void
+ResolverBase::visit (AST::RangePatternBoundLiteral &)
+{}
+
+void
+ResolverBase::visit (AST::RangePatternBoundPath &)
+{}
+
+void
+ResolverBase::visit (AST::RangePatternBoundQualPath &)
+{}
+
+void
+ResolverBase::visit (AST::RangePattern &)
+{}
+
+void
+ResolverBase::visit (AST::ReferencePattern &)
+{}
+
+void
+ResolverBase::visit (AST::StructPatternFieldTuplePat &)
+{}
+
+void
+ResolverBase::visit (AST::StructPatternFieldIdentPat &)
+{}
+
+void
+ResolverBase::visit (AST::StructPatternFieldIdent &)
+{}
+
+void
+ResolverBase::visit (AST::StructPattern &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStructItemsNoRange &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStructItemsRange &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStructPattern &)
+{}
+
+void
+ResolverBase::visit (AST::TuplePatternItemsMultiple &)
+{}
+
+void
+ResolverBase::visit (AST::TuplePatternItemsRanged &)
+{}
+
+void
+ResolverBase::visit (AST::TuplePattern &)
+{}
+
+void
+ResolverBase::visit (AST::GroupedPattern &)
+{}
+
+void
+ResolverBase::visit (AST::SlicePattern &)
+{}
+
+void
+ResolverBase::visit (AST::EmptyStmt &)
+{}
+
+void
+ResolverBase::visit (AST::LetStmt &)
+{}
+
+void
+ResolverBase::visit (AST::ExprStmtWithoutBlock &)
+{}
+
+void
+ResolverBase::visit (AST::ExprStmtWithBlock &)
+{}
+
+void
+ResolverBase::visit (AST::TraitBound &)
+{}
+
+void
+ResolverBase::visit (AST::ImplTraitType &)
+{}
+
+void
+ResolverBase::visit (AST::TraitObjectType &)
+{}
+
+void
+ResolverBase::visit (AST::ParenthesisedType &)
+{}
+
+void
+ResolverBase::visit (AST::ImplTraitTypeOneBound &)
+{}
+
+void
+ResolverBase::visit (AST::TraitObjectTypeOneBound &)
+{}
+
+void
+ResolverBase::visit (AST::TupleType &)
+{}
+
+void
+ResolverBase::visit (AST::NeverType &)
+{}
+
+void
+ResolverBase::visit (AST::RawPointerType &)
+{}
+
+void
+ResolverBase::visit (AST::ReferenceType &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayType &)
+{}
+
+void
+ResolverBase::visit (AST::SliceType &)
+{}
+
+void
+ResolverBase::visit (AST::InferredType &)
+{}
+
+void
+ResolverBase::visit (AST::BareFunctionType &)
+{}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h
new file mode 100644
index 00000000000..32f30bcea62
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-base.h
@@ -0,0 +1,221 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_BASE_H
+#define RUST_AST_RESOLVE_BASE_H
+
+#include "rust-ast-visitor.h"
+#include "rust-name-resolver.h"
+#include "rust-diagnostics.h"
+#include "rust-location.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolverBase : public AST::ASTVisitor
+{
+public:
+  virtual ~ResolverBase () {}
+
+  void visit (AST::Token &);
+  void visit (AST::DelimTokenTree &);
+  void visit (AST::AttrInputMetaItemContainer &);
+  void visit (AST::IdentifierExpr &);
+  void visit (AST::Lifetime &);
+  void visit (AST::LifetimeParam &);
+  void visit (AST::ConstGenericParam &);
+  void visit (AST::PathInExpression &);
+  void visit (AST::TypePathSegment &);
+  void visit (AST::TypePathSegmentGeneric &);
+  void visit (AST::TypePathSegmentFunction &);
+  void visit (AST::TypePath &);
+  void visit (AST::QualifiedPathInExpression &);
+  void visit (AST::QualifiedPathInType &);
+  void visit (AST::LiteralExpr &);
+  void visit (AST::AttrInputLiteral &);
+  void visit (AST::MetaItemLitExpr &);
+  void visit (AST::MetaItemPathLit &);
+  void visit (AST::BorrowExpr &);
+  void visit (AST::DereferenceExpr &);
+  void visit (AST::ErrorPropagationExpr &);
+  void visit (AST::NegationExpr &);
+  void visit (AST::ArithmeticOrLogicalExpr &);
+  void visit (AST::ComparisonExpr &);
+  void visit (AST::LazyBooleanExpr &);
+  void visit (AST::TypeCastExpr &);
+  void visit (AST::AssignmentExpr &);
+  void visit (AST::CompoundAssignmentExpr &);
+  void visit (AST::GroupedExpr &);
+  void visit (AST::ArrayElemsValues &);
+  void visit (AST::ArrayElemsCopied &);
+  void visit (AST::ArrayExpr &);
+  void visit (AST::ArrayIndexExpr &);
+  void visit (AST::TupleExpr &);
+  void visit (AST::TupleIndexExpr &);
+  void visit (AST::StructExprStruct &);
+  void visit (AST::StructExprFieldIdentifier &);
+  void visit (AST::StructExprFieldIdentifierValue &);
+  void visit (AST::StructExprFieldIndexValue &);
+  void visit (AST::StructExprStructFields &);
+  void visit (AST::StructExprStructBase &);
+  void visit (AST::CallExpr &);
+  void visit (AST::MethodCallExpr &);
+  void visit (AST::FieldAccessExpr &);
+  void visit (AST::ClosureExprInner &);
+  void visit (AST::BlockExpr &);
+  void visit (AST::ClosureExprInnerTyped &);
+  void visit (AST::ContinueExpr &);
+  void visit (AST::BreakExpr &);
+  void visit (AST::RangeFromToExpr &);
+  void visit (AST::RangeFromExpr &);
+  void visit (AST::RangeToExpr &);
+  void visit (AST::RangeFullExpr &);
+  void visit (AST::RangeFromToInclExpr &);
+  void visit (AST::RangeToInclExpr &);
+  void visit (AST::ReturnExpr &);
+  void visit (AST::UnsafeBlockExpr &);
+  void visit (AST::LoopExpr &);
+  void visit (AST::WhileLoopExpr &);
+  void visit (AST::WhileLetLoopExpr &);
+  void visit (AST::ForLoopExpr &);
+  void visit (AST::IfExpr &);
+  void visit (AST::IfExprConseqElse &);
+  void visit (AST::IfExprConseqIf &);
+  void visit (AST::IfExprConseqIfLet &);
+  void visit (AST::IfLetExpr &);
+  void visit (AST::IfLetExprConseqElse &);
+  void visit (AST::IfLetExprConseqIf &);
+  void visit (AST::IfLetExprConseqIfLet &);
+
+  void visit (AST::MatchExpr &);
+  void visit (AST::AwaitExpr &);
+  void visit (AST::AsyncBlockExpr &);
+
+  void visit (AST::TypeParam &);
+
+  void visit (AST::LifetimeWhereClauseItem &);
+  void visit (AST::TypeBoundWhereClauseItem &);
+  void visit (AST::Method &);
+  void visit (AST::Module &);
+  void visit (AST::ExternCrate &);
+
+  void visit (AST::UseTreeGlob &);
+  void visit (AST::UseTreeList &);
+  void visit (AST::UseTreeRebind &);
+  void visit (AST::UseDeclaration &);
+  void visit (AST::Function &);
+  void visit (AST::TypeAlias &);
+  void visit (AST::StructStruct &);
+  void visit (AST::TupleStruct &);
+  void visit (AST::EnumItem &);
+  void visit (AST::EnumItemTuple &);
+  void visit (AST::EnumItemStruct &);
+  void visit (AST::EnumItemDiscriminant &);
+  void visit (AST::Enum &);
+  void visit (AST::Union &);
+  void visit (AST::ConstantItem &);
+  void visit (AST::StaticItem &);
+  void visit (AST::TraitItemFunc &);
+  void visit (AST::TraitItemMethod &);
+  void visit (AST::TraitItemConst &);
+  void visit (AST::TraitItemType &);
+  void visit (AST::Trait &);
+  void visit (AST::InherentImpl &);
+  void visit (AST::TraitImpl &);
+
+  void visit (AST::ExternalStaticItem &);
+  void visit (AST::ExternalFunctionItem &);
+  void visit (AST::ExternBlock &);
+
+  void visit (AST::MacroMatchFragment &);
+  void visit (AST::MacroMatchRepetition &);
+  void visit (AST::MacroMatcher &);
+  void visit (AST::MacroRulesDefinition &);
+  void visit (AST::MacroInvocation &);
+  void visit (AST::MetaItemPath &);
+  void visit (AST::MetaItemSeq &);
+  void visit (AST::MetaWord &);
+  void visit (AST::MetaNameValueStr &);
+  void visit (AST::MetaListPaths &);
+  void visit (AST::MetaListNameValueStr &);
+
+  void visit (AST::LiteralPattern &);
+  void visit (AST::IdentifierPattern &);
+  void visit (AST::WildcardPattern &);
+
+  void visit (AST::RangePatternBoundLiteral &);
+  void visit (AST::RangePatternBoundPath &);
+  void visit (AST::RangePatternBoundQualPath &);
+  void visit (AST::RangePattern &);
+  void visit (AST::ReferencePattern &);
+
+  void visit (AST::StructPatternFieldTuplePat &);
+  void visit (AST::StructPatternFieldIdentPat &);
+  void visit (AST::StructPatternFieldIdent &);
+  void visit (AST::StructPattern &);
+
+  void visit (AST::TupleStructItemsNoRange &);
+  void visit (AST::TupleStructItemsRange &);
+  void visit (AST::TupleStructPattern &);
+
+  void visit (AST::TuplePatternItemsMultiple &);
+  void visit (AST::TuplePatternItemsRanged &);
+  void visit (AST::TuplePattern &);
+  void visit (AST::GroupedPattern &);
+  void visit (AST::SlicePattern &);
+
+  void visit (AST::EmptyStmt &);
+  void visit (AST::LetStmt &);
+  void visit (AST::ExprStmtWithoutBlock &);
+  void visit (AST::ExprStmtWithBlock &);
+
+  void visit (AST::TraitBound &);
+  void visit (AST::ImplTraitType &);
+  void visit (AST::TraitObjectType &);
+  void visit (AST::ParenthesisedType &);
+  void visit (AST::ImplTraitTypeOneBound &);
+  void visit (AST::TraitObjectTypeOneBound &);
+  void visit (AST::TupleType &);
+  void visit (AST::NeverType &);
+  void visit (AST::RawPointerType &);
+  void visit (AST::ReferenceType &);
+  void visit (AST::ArrayType &);
+  void visit (AST::SliceType &);
+  void visit (AST::InferredType &);
+  void visit (AST::BareFunctionType &);
+
+protected:
+  ResolverBase ()
+    : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ()),
+      resolved_node (UNKNOWN_NODEID)
+  {}
+
+  /**
+   * Resolve a visibility's path through the name resolver
+   */
+  bool resolve_visibility (const AST::Visibility &vis);
+
+  Resolver *resolver;
+  Analysis::Mappings *mappings;
+  NodeId resolved_node;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_BASE_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
new file mode 100644
index 00000000000..4cc4e26e3e9
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -0,0 +1,574 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-resolve-stmt.h"
+#include "rust-ast-resolve-struct-expr-field.h"
+#include "rust-ast-verify-assignee.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-path.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveExpr::go (AST::Expr *expr, const CanonicalPath &prefix,
+		 const CanonicalPath &canonical_prefix)
+{
+  ResolveExpr resolver (prefix, canonical_prefix);
+  expr->accept_vis (resolver);
+}
+
+void
+ResolveExpr::visit (AST::TupleIndexExpr &expr)
+{
+  ResolveExpr::go (expr.get_tuple_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::TupleExpr &expr)
+{
+  if (expr.is_unit ())
+    return;
+
+  for (auto &elem : expr.get_tuple_elems ())
+    ResolveExpr::go (elem.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::PathInExpression &expr)
+{
+  ResolvePath::go (&expr);
+}
+
+void
+ResolveExpr::visit (AST::QualifiedPathInExpression &expr)
+{
+  ResolvePath::go (&expr);
+}
+
+void
+ResolveExpr::visit (AST::ReturnExpr &expr)
+{
+  if (expr.has_returned_expr ())
+    ResolveExpr::go (expr.get_returned_expr ().get (), prefix,
+		     canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::CallExpr &expr)
+{
+  ResolveExpr::go (expr.get_function_expr ().get (), prefix, canonical_prefix);
+  for (auto &param : expr.get_params ())
+    ResolveExpr::go (param.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::MethodCallExpr &expr)
+{
+  ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix);
+
+  if (expr.get_method_name ().has_generic_args ())
+    {
+      AST::GenericArgs &args = expr.get_method_name ().get_generic_args ();
+      ResolveGenericArgs::go (args, prefix, canonical_prefix);
+    }
+
+  auto const &in_params = expr.get_params ();
+  for (auto &param : in_params)
+    ResolveExpr::go (param.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::AssignmentExpr &expr)
+{
+  ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+
+  // need to verify the assignee
+  VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ());
+}
+
+void
+ResolveExpr::visit (AST::IdentifierExpr &expr)
+{
+  if (resolver->get_name_scope ().lookup (
+	CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
+	&resolved_node))
+    {
+      resolver->insert_resolved_name (expr.get_node_id (), resolved_node);
+    }
+  else if (resolver->get_type_scope ().lookup (
+	     CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
+	     &resolved_node))
+    {
+      resolver->insert_resolved_type (expr.get_node_id (), resolved_node);
+    }
+  else
+    {
+      rust_error_at (expr.get_locus (), "failed to find name: %s",
+		     expr.as_string ().c_str ());
+    }
+}
+
+void
+ResolveExpr::visit (AST::ArithmeticOrLogicalExpr &expr)
+{
+  ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::CompoundAssignmentExpr &expr)
+{
+  ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+
+  // need to verify the assignee
+  VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ());
+}
+
+void
+ResolveExpr::visit (AST::ComparisonExpr &expr)
+{
+  ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::LazyBooleanExpr &expr)
+{
+  ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::NegationExpr &expr)
+{
+  ResolveExpr::go (expr.get_negated_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::TypeCastExpr &expr)
+{
+  ResolveType::go (expr.get_type_to_cast_to ().get ());
+  ResolveExpr::go (expr.get_casted_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfExpr &expr)
+{
+  ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfExprConseqElse &expr)
+{
+  ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_else_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfExprConseqIf &expr)
+{
+  ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_conseq_if_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfLetExpr &expr)
+{
+  ResolveExpr::go (expr.get_value_expr ().get (), prefix, canonical_prefix);
+
+  NodeId scope_node_id = expr.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  for (auto &pattern : expr.get_patterns ())
+    {
+      PatternDeclaration::go (pattern.get ());
+    }
+
+  ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExpr::visit (AST::BlockExpr &expr)
+{
+  NodeId scope_node_id = expr.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  for (auto &s : expr.get_statements ())
+    {
+      if (s->is_item ())
+	ResolveStmt::go (s.get (), prefix, canonical_prefix,
+			 CanonicalPath::create_empty ());
+    }
+
+  for (auto &s : expr.get_statements ())
+    {
+      if (!s->is_item ())
+	ResolveStmt::go (s.get (), prefix, canonical_prefix,
+			 CanonicalPath::create_empty ());
+    }
+
+  if (expr.has_tail_expr ())
+    ResolveExpr::go (expr.get_tail_expr ().get (), prefix, canonical_prefix);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
+{
+  expr.get_block_expr ()->accept_vis (*this);
+}
+
+void
+ResolveExpr::visit (AST::ArrayElemsValues &elems)
+{
+  for (auto &elem : elems.get_values ())
+    ResolveExpr::go (elem.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::ArrayExpr &expr)
+{
+  expr.get_array_elems ()->accept_vis (*this);
+}
+
+void
+ResolveExpr::visit (AST::ArrayIndexExpr &expr)
+{
+  ResolveExpr::go (expr.get_array_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_index_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::ArrayElemsCopied &expr)
+{
+  ResolveExpr::go (expr.get_num_copies ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_elem_to_copy ().get (), prefix, canonical_prefix);
+}
+
+// this this an empty struct constructor like 'S {}'
+void
+ResolveExpr::visit (AST::StructExprStruct &struct_expr)
+{
+  ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix);
+}
+
+// this this a struct constructor with fields
+void
+ResolveExpr::visit (AST::StructExprStructFields &struct_expr)
+{
+  ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix);
+
+  if (struct_expr.has_struct_base ())
+    {
+      AST::StructBase &base = struct_expr.get_struct_base ();
+      ResolveExpr::go (base.get_base_struct ().get (), prefix,
+		       canonical_prefix);
+    }
+
+  auto const &struct_fields = struct_expr.get_fields ();
+  for (auto &struct_field : struct_fields)
+    {
+      ResolveStructExprField::go (struct_field.get (), prefix,
+				  canonical_prefix);
+    }
+}
+
+void
+ResolveExpr::visit (AST::GroupedExpr &expr)
+{
+  ResolveExpr::go (expr.get_expr_in_parens ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::FieldAccessExpr &expr)
+{
+  ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::LoopExpr &expr)
+{
+  if (expr.has_loop_label ())
+    {
+      auto label = expr.get_loop_label ();
+      if (label.get_lifetime ().get_lifetime_type ()
+	  != AST::Lifetime::LifetimeType::NAMED)
+	{
+	  rust_error_at (label.get_locus (),
+			 "Labels must be a named lifetime value");
+	  return;
+	}
+
+      auto label_name = label.get_lifetime ().get_lifetime_name ();
+      auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
+      resolver->get_label_scope ().insert (
+	CanonicalPath::new_seg (expr.get_node_id (), label_name),
+	label_lifetime_node_id, label.get_locus (), false,
+	[&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	  rust_error_at (label.get_locus (), "label redefined multiple times");
+	  rust_error_at (locus, "was defined here");
+	});
+    }
+  ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::BreakExpr &expr)
+{
+  if (expr.has_label ())
+    {
+      auto label = expr.get_label ();
+      if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
+	{
+	  rust_error_at (label.get_locus (),
+			 "Labels must be a named lifetime value");
+	  return;
+	}
+
+      NodeId resolved_node = UNKNOWN_NODEID;
+      if (!resolver->get_label_scope ().lookup (
+	    CanonicalPath::new_seg (label.get_node_id (),
+				    label.get_lifetime_name ()),
+	    &resolved_node))
+	{
+	  rust_error_at (expr.get_label ().get_locus (),
+			 "failed to resolve label");
+	  return;
+	}
+      resolver->insert_resolved_label (label.get_node_id (), resolved_node);
+    }
+
+  if (expr.has_break_expr ())
+    ResolveExpr::go (expr.get_break_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::WhileLoopExpr &expr)
+{
+  if (expr.has_loop_label ())
+    {
+      auto label = expr.get_loop_label ();
+      if (label.get_lifetime ().get_lifetime_type ()
+	  != AST::Lifetime::LifetimeType::NAMED)
+	{
+	  rust_error_at (label.get_locus (),
+			 "Labels must be a named lifetime value");
+	  return;
+	}
+
+      auto label_name = label.get_lifetime ().get_lifetime_name ();
+      auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
+      resolver->get_label_scope ().insert (
+	CanonicalPath::new_seg (label.get_node_id (), label_name),
+	label_lifetime_node_id, label.get_locus (), false,
+	[&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	  rust_error_at (label.get_locus (), "label redefined multiple times");
+	  rust_error_at (locus, "was defined here");
+	});
+    }
+
+  ResolveExpr::go (expr.get_predicate_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::ForLoopExpr &expr)
+{
+  if (expr.has_loop_label ())
+    {
+      auto label = expr.get_loop_label ();
+      if (label.get_lifetime ().get_lifetime_type ()
+	  != AST::Lifetime::LifetimeType::NAMED)
+	{
+	  rust_error_at (label.get_locus (),
+			 "Labels must be a named lifetime value");
+	  return;
+	}
+
+      auto label_name = label.get_lifetime ().get_lifetime_name ();
+      auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
+      resolver->get_label_scope ().insert (
+	CanonicalPath::new_seg (label.get_node_id (), label_name),
+	label_lifetime_node_id, label.get_locus (), false,
+	[&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	  rust_error_at (label.get_locus (), "label redefined multiple times");
+	  rust_error_at (locus, "was defined here");
+	});
+    }
+
+  // this needs a new rib to contain the pattern
+  NodeId scope_node_id = expr.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  // resolve the expression
+  PatternDeclaration::go (expr.get_pattern ().get ());
+  ResolveExpr::go (expr.get_iterator_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
+
+  // done
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExpr::visit (AST::ContinueExpr &expr)
+{
+  if (expr.has_label ())
+    {
+      auto label = expr.get_label ();
+      if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
+	{
+	  rust_error_at (label.get_locus (),
+			 "Labels must be a named lifetime value");
+	  return;
+	}
+
+      NodeId resolved_node = UNKNOWN_NODEID;
+      if (!resolver->get_label_scope ().lookup (
+	    CanonicalPath::new_seg (label.get_node_id (),
+				    label.get_lifetime_name ()),
+	    &resolved_node))
+	{
+	  rust_error_at (expr.get_label ().get_locus (),
+			 "failed to resolve label");
+	  return;
+	}
+      resolver->insert_resolved_label (label.get_node_id (), resolved_node);
+    }
+}
+
+void
+ResolveExpr::visit (AST::BorrowExpr &expr)
+{
+  ResolveExpr::go (expr.get_borrowed_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::DereferenceExpr &expr)
+{
+  ResolveExpr::go (expr.get_dereferenced_expr ().get (), prefix,
+		   canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::MatchExpr &expr)
+{
+  ResolveExpr::go (expr.get_scrutinee_expr ().get (), prefix, canonical_prefix);
+  for (auto &match_case : expr.get_match_cases ())
+    {
+      // each arm is in its own scope
+      NodeId scope_node_id = match_case.get_node_id ();
+      resolver->get_name_scope ().push (scope_node_id);
+      resolver->get_type_scope ().push (scope_node_id);
+      resolver->get_label_scope ().push (scope_node_id);
+      resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+      resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+      resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+      // resolve
+      AST::MatchArm &arm = match_case.get_arm ();
+      if (arm.has_match_arm_guard ())
+	ResolveExpr::go (arm.get_guard_expr ().get (), prefix,
+			 canonical_prefix);
+
+      // insert any possible new patterns
+      for (auto &pattern : arm.get_patterns ())
+	{
+	  PatternDeclaration::go (pattern.get ());
+	}
+
+      // resolve the body
+      ResolveExpr::go (match_case.get_expr ().get (), prefix, canonical_prefix);
+
+      // done
+      resolver->get_name_scope ().pop ();
+      resolver->get_type_scope ().pop ();
+      resolver->get_label_scope ().pop ();
+    }
+}
+
+void
+ResolveExpr::visit (AST::RangeFromToExpr &expr)
+{
+  ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::RangeFromExpr &expr)
+{
+  ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::RangeToExpr &expr)
+{
+  ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::RangeFullExpr &expr)
+{
+  // nothing to do
+}
+
+void
+ResolveExpr::visit (AST::RangeFromToInclExpr &expr)
+{
+  ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
+  ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
+}
+
+ResolveExpr::ResolveExpr (const CanonicalPath &prefix,
+			  const CanonicalPath &canonical_prefix)
+  : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
new file mode 100644
index 00000000000..11a846ac8cd
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -0,0 +1,133 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_EXPR_H
+#define RUST_AST_RESOLVE_EXPR_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveExpr : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::Expr *expr, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+  void visit (AST::TupleIndexExpr &expr) override;
+
+  void visit (AST::TupleExpr &expr) override;
+
+  void visit (AST::PathInExpression &expr) override;
+
+  void visit (AST::QualifiedPathInExpression &expr) override;
+
+  void visit (AST::ReturnExpr &expr) override;
+
+  void visit (AST::CallExpr &expr) override;
+
+  void visit (AST::MethodCallExpr &expr) override;
+
+  void visit (AST::AssignmentExpr &expr) override;
+
+  void visit (AST::IdentifierExpr &expr) override;
+
+  void visit (AST::ArithmeticOrLogicalExpr &expr) override;
+
+  void visit (AST::CompoundAssignmentExpr &expr) override;
+
+  void visit (AST::ComparisonExpr &expr) override;
+
+  void visit (AST::LazyBooleanExpr &expr) override;
+
+  void visit (AST::NegationExpr &expr) override;
+
+  void visit (AST::TypeCastExpr &expr) override;
+
+  void visit (AST::IfExpr &expr) override;
+
+  void visit (AST::IfExprConseqElse &expr) override;
+
+  void visit (AST::IfExprConseqIf &expr) override;
+
+  void visit (AST::IfLetExpr &expr) override;
+
+  void visit (AST::BlockExpr &expr) override;
+
+  void visit (AST::UnsafeBlockExpr &expr) override;
+
+  void visit (AST::ArrayElemsValues &elems) override;
+
+  void visit (AST::ArrayExpr &expr) override;
+
+  void visit (AST::ArrayIndexExpr &expr) override;
+
+  void visit (AST::ArrayElemsCopied &elems) override;
+
+  // this this an empty struct constructor like 'S {}'
+  void visit (AST::StructExprStruct &struct_expr) override;
+
+  // this this a struct constructor with fields
+  void visit (AST::StructExprStructFields &struct_expr) override;
+
+  void visit (AST::GroupedExpr &expr) override;
+
+  void visit (AST::FieldAccessExpr &expr) override;
+
+  void visit (AST::LoopExpr &expr) override;
+
+  void visit (AST::BreakExpr &expr) override;
+
+  void visit (AST::WhileLoopExpr &expr) override;
+
+  void visit (AST::ForLoopExpr &expr) override;
+
+  void visit (AST::ContinueExpr &expr) override;
+
+  void visit (AST::BorrowExpr &expr) override;
+
+  void visit (AST::DereferenceExpr &expr) override;
+
+  void visit (AST::MatchExpr &expr) override;
+
+  void visit (AST::RangeFromToExpr &expr) override;
+
+  void visit (AST::RangeFromExpr &expr) override;
+
+  void visit (AST::RangeToExpr &expr) override;
+
+  void visit (AST::RangeFullExpr &expr) override;
+
+  void visit (AST::RangeFromToInclExpr &expr) override;
+
+private:
+  ResolveExpr (const CanonicalPath &prefix,
+	       const CanonicalPath &canonical_prefix);
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_EXPR_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h
new file mode 100644
index 00000000000..29dbe3436f5
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h
@@ -0,0 +1,275 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_IMPLITEM_H
+#define RUST_AST_RESOLVE_IMPLITEM_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveToplevelImplItem : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::InherentImplItem *item, const CanonicalPath &prefix)
+  {
+    if (item->is_marked_for_strip ())
+      return;
+
+    ResolveToplevelImplItem resolver (prefix);
+    item->accept_vis (resolver);
+  }
+
+  static void go (AST::TraitImplItem *item, const CanonicalPath &prefix)
+  {
+    if (item->is_marked_for_strip ())
+      return;
+
+    ResolveToplevelImplItem resolver (prefix);
+    item->accept_vis (resolver);
+  }
+
+  void visit (AST::TypeAlias &type) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (type.get_node_id (), type.get_new_type_name ());
+    auto path = prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, type.get_node_id (), type.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (type.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+  void visit (AST::ConstantItem &constant) override
+  {
+    auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+					constant.get_identifier ());
+    auto path = prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, constant.get_node_id (), constant.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (constant.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+  void visit (AST::Function &function) override
+  {
+    auto decl = CanonicalPath::new_seg (function.get_node_id (),
+					function.get_function_name ());
+    auto path = prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, function.get_node_id (), function.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (function.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+  void visit (AST::Method &method) override
+  {
+    auto decl = CanonicalPath::new_seg (method.get_node_id (),
+					method.get_method_name ());
+    auto path = prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, method.get_node_id (), method.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (method.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+private:
+  ResolveToplevelImplItem (const CanonicalPath &prefix)
+    : ResolverBase (), prefix (prefix)
+  {
+    rust_assert (!prefix.is_empty ());
+  }
+
+  const CanonicalPath &prefix;
+};
+
+class ResolveTopLevelTraitItems : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::TraitItem *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix)
+  {
+    ResolveTopLevelTraitItems resolver (prefix, canonical_prefix);
+    item->accept_vis (resolver);
+  };
+
+  void visit (AST::TraitItemFunc &function) override
+  {
+    auto decl = CanonicalPath::new_seg (
+      function.get_node_id (),
+      function.get_trait_function_decl ().get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, function.get_node_id (), function.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (function.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (function.get_node_id (), cpath);
+  }
+
+  void visit (AST::TraitItemMethod &method) override
+  {
+    auto decl = CanonicalPath::new_seg (
+      method.get_node_id (), method.get_trait_method_decl ().get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, method.get_node_id (), method.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (method.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (method.get_node_id (), cpath);
+  }
+
+  void visit (AST::TraitItemConst &constant) override
+  {
+    auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+					constant.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, constant.get_node_id (), constant.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (constant.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (constant.get_node_id (), cpath);
+  }
+
+  void visit (AST::TraitItemType &type) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (type.get_node_id (), type.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, type.get_node_id (), type.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (type.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (type.get_node_id (), cpath);
+  }
+
+private:
+  ResolveTopLevelTraitItems (const CanonicalPath &prefix,
+			     const CanonicalPath &canonical_prefix)
+    : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+  {}
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+class ResolveToplevelExternItem : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::ExternalItem *item, const CanonicalPath &prefix)
+  {
+    ResolveToplevelExternItem resolver (prefix);
+    item->accept_vis (resolver);
+  };
+
+  void visit (AST::ExternalFunctionItem &function) override
+  {
+    auto decl = CanonicalPath::new_seg (function.get_node_id (),
+					function.get_identifier ());
+    auto path = prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, function.get_node_id (), function.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (function.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+  }
+
+  void visit (AST::ExternalStaticItem &item) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+    auto path = prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+  }
+
+private:
+  ResolveToplevelExternItem (const CanonicalPath &prefix)
+    : ResolverBase (), prefix (prefix)
+  {}
+
+  const CanonicalPath &prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_IMPLITEM_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
new file mode 100644
index 00000000000..0c38f28d530
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -0,0 +1,1237 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-path.h"
+#include "selftest.h"
+
+namespace Rust {
+namespace Resolver {
+
+ResolveTraitItems::ResolveTraitItems (const CanonicalPath &prefix,
+				      const CanonicalPath &canonical_prefix)
+  : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+void
+ResolveTraitItems::go (AST::TraitItem *item, const CanonicalPath &prefix,
+		       const CanonicalPath &canonical_prefix)
+{
+  if (item->is_marked_for_strip ())
+    return;
+
+  ResolveTraitItems resolver (prefix, canonical_prefix);
+  item->accept_vis (resolver);
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemType &type)
+{
+  auto decl
+    = CanonicalPath::new_seg (type.get_node_id (), type.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (type.get_node_id (), cpath);
+
+  for (auto &bound : type.get_type_param_bounds ())
+    ResolveTypeBound::go (bound.get ());
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemFunc &func)
+{
+  auto decl = CanonicalPath::new_seg (
+    func.get_node_id (), func.get_trait_function_decl ().get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (func.get_node_id (), cpath);
+
+  NodeId scope_node_id = func.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  AST::TraitFunctionDecl &function = func.get_trait_function_decl ();
+  if (function.has_generics ())
+    for (auto &generic : function.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (function.has_return_type ())
+    ResolveType::go (function.get_return_type ().get ());
+
+  // we make a new scope so the names of parameters are resolved and shadowed
+  // correctly
+  for (auto &param : function.get_function_params ())
+    {
+      ResolveType::go (param.get_type ().get ());
+      PatternDeclaration::go (param.get_pattern ().get ());
+    }
+
+  if (function.has_where_clause ())
+    ResolveWhereClause::Resolve (function.get_where_clause ());
+
+  // trait items have an optional body
+  if (func.has_definition ())
+    ResolveExpr::go (func.get_definition ().get (), path, cpath);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemMethod &func)
+{
+  auto decl
+    = CanonicalPath::new_seg (func.get_node_id (),
+			      func.get_trait_method_decl ().get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (func.get_node_id (), cpath);
+
+  NodeId scope_node_id = func.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  AST::TraitMethodDecl &function = func.get_trait_method_decl ();
+  if (function.has_generics ())
+    for (auto &generic : function.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (function.has_return_type ())
+    ResolveType::go (function.get_return_type ().get ());
+
+  // self turns into (self: Self) as a function param
+  AST::SelfParam &self_param = function.get_self_param ();
+  AST::IdentifierPattern self_pattern (self_param.get_node_id (), "self",
+				       self_param.get_locus (),
+				       self_param.get_has_ref (),
+				       self_param.get_is_mut (),
+				       std::unique_ptr<AST::Pattern> (nullptr));
+
+  std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+  segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+    new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+
+  AST::TypePath self_type_path (std::move (segments), self_param.get_locus ());
+
+  ResolveType::go (&self_type_path);
+  PatternDeclaration::go (&self_pattern);
+
+  // we make a new scope so the names of parameters are resolved and shadowed
+  // correctly
+  for (auto &param : function.get_function_params ())
+    {
+      ResolveType::go (param.get_type ().get ());
+      PatternDeclaration::go (param.get_pattern ().get ());
+    }
+
+  if (function.has_where_clause ())
+    ResolveWhereClause::Resolve (function.get_where_clause ());
+
+  // trait items have an optional body
+  if (func.has_definition ())
+    ResolveExpr::go (func.get_definition ().get (), path, cpath);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemConst &constant)
+{
+  auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+				      constant.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (constant.get_node_id (), cpath);
+
+  ResolveType::go (constant.get_type ().get ());
+
+  if (constant.has_expr ())
+    ResolveExpr::go (constant.get_expr ().get (), path, cpath);
+}
+
+ResolveItem::ResolveItem (const CanonicalPath &prefix,
+			  const CanonicalPath &canonical_prefix)
+  : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+void
+ResolveItem::go (AST::Item *item, const CanonicalPath &prefix,
+		 const CanonicalPath &canonical_prefix)
+{
+  ResolveItem resolver (prefix, canonical_prefix);
+  item->accept_vis (resolver);
+}
+
+void
+ResolveItem::visit (AST::TypeAlias &alias)
+{
+  auto talias
+    = CanonicalPath::new_seg (alias.get_node_id (), alias.get_new_type_name ());
+  auto path = prefix.append (talias);
+  auto cpath = canonical_prefix.append (talias);
+  mappings->insert_canonical_path (alias.get_node_id (), cpath);
+
+  NodeId scope_node_id = alias.get_node_id ();
+  resolver->get_type_scope ().push (scope_node_id);
+
+  if (alias.has_generics ())
+    for (auto &generic : alias.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (alias.has_where_clause ())
+    ResolveWhereClause::Resolve (alias.get_where_clause ());
+
+  ResolveType::go (alias.get_type_aliased ().get ());
+
+  resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Module &module)
+{
+  auto mod = CanonicalPath::new_seg (module.get_node_id (), module.get_name ());
+  auto path = prefix.append (mod);
+  auto cpath = canonical_prefix.append (mod);
+  mappings->insert_canonical_path (module.get_node_id (), cpath);
+
+  resolve_visibility (module.get_visibility ());
+
+  NodeId scope_node_id = module.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  // FIXME: Should we reinsert a child here? Any reason we ResolveTopLevel::go
+  // in ResolveTopLevel::visit (AST::Module) as well as here?
+  for (auto &item : module.get_items ())
+    ResolveTopLevel::go (item.get (), CanonicalPath::create_empty (), cpath);
+
+  resolver->push_new_module_scope (module.get_node_id ());
+  for (auto &item : module.get_items ())
+    ResolveItem::go (item.get (), path, cpath);
+
+  resolver->pop_module_scope ();
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::TupleStruct &struct_decl)
+{
+  auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+				      struct_decl.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+  resolve_visibility (struct_decl.get_visibility ());
+
+  NodeId scope_node_id = struct_decl.get_node_id ();
+  resolver->get_type_scope ().push (scope_node_id);
+
+  if (struct_decl.has_generics ())
+    for (auto &generic : struct_decl.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (struct_decl.has_where_clause ())
+    ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
+
+  for (AST::TupleField &field : struct_decl.get_fields ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      resolve_visibility (field.get_visibility ());
+
+      ResolveType::go (field.get_field_type ().get ());
+    }
+
+  resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Enum &enum_decl)
+{
+  auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (),
+				      enum_decl.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
+
+  resolve_visibility (enum_decl.get_visibility ());
+
+  NodeId scope_node_id = enum_decl.get_node_id ();
+  resolver->get_type_scope ().push (scope_node_id);
+
+  if (enum_decl.has_generics ())
+    for (auto &generic : enum_decl.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, cpath);
+
+  if (enum_decl.has_where_clause ())
+    ResolveWhereClause::Resolve (enum_decl.get_where_clause ());
+
+  /* The actual fields are inside the variants.  */
+  for (auto &variant : enum_decl.get_variants ())
+    ResolveItem::go (variant.get (), path, cpath);
+
+  resolver->get_type_scope ().pop ();
+}
+
+/* EnumItem doesn't need to be handled, no fields.  */
+void
+ResolveItem::visit (AST::EnumItem &item)
+{
+  // Since at this point we cannot have visibilities on enum items anymore, we
+  // can skip handling them
+
+  auto decl
+    = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (item.get_node_id (), cpath);
+}
+
+void
+ResolveItem::visit (AST::EnumItemTuple &item)
+{
+  auto decl
+    = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+  for (auto &field : item.get_tuple_fields ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      ResolveType::go (field.get_field_type ().get ());
+    }
+}
+
+void
+ResolveItem::visit (AST::EnumItemStruct &item)
+{
+  auto decl
+    = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+  for (auto &field : item.get_struct_fields ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      ResolveType::go (field.get_field_type ().get ());
+    }
+}
+
+void
+ResolveItem::visit (AST::EnumItemDiscriminant &item)
+{
+  auto decl
+    = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+
+  mappings->insert_canonical_path (item.get_node_id (), cpath);
+}
+
+void
+ResolveItem::visit (AST::StructStruct &struct_decl)
+{
+  auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+				      struct_decl.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+  resolve_visibility (struct_decl.get_visibility ());
+
+  NodeId scope_node_id = struct_decl.get_node_id ();
+  resolver->get_type_scope ().push (scope_node_id);
+
+  if (struct_decl.has_generics ())
+    for (auto &generic : struct_decl.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (struct_decl.has_where_clause ())
+    ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
+
+  for (AST::StructField &field : struct_decl.get_fields ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      resolve_visibility (field.get_visibility ());
+
+      ResolveType::go (field.get_field_type ().get ());
+    }
+
+  resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Union &union_decl)
+{
+  auto decl = CanonicalPath::new_seg (union_decl.get_node_id (),
+				      union_decl.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (union_decl.get_node_id (), cpath);
+
+  resolve_visibility (union_decl.get_visibility ());
+
+  NodeId scope_node_id = union_decl.get_node_id ();
+  resolver->get_type_scope ().push (scope_node_id);
+
+  if (union_decl.has_generics ())
+    for (auto &generic : union_decl.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (union_decl.has_where_clause ())
+    ResolveWhereClause::Resolve (union_decl.get_where_clause ());
+
+  for (AST::StructField &field : union_decl.get_variants ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      ResolveType::go (field.get_field_type ().get ());
+    }
+
+  resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::StaticItem &var)
+{
+  auto decl
+    = CanonicalPath::new_seg (var.get_node_id (), var.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (var.get_node_id (), cpath);
+
+  ResolveType::go (var.get_type ().get ());
+  ResolveExpr::go (var.get_expr ().get (), path, cpath);
+}
+
+void
+ResolveItem::visit (AST::ConstantItem &constant)
+{
+  auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+				      constant.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (constant.get_node_id (), cpath);
+
+  resolve_visibility (constant.get_visibility ());
+
+  ResolveType::go (constant.get_type ().get ());
+  ResolveExpr::go (constant.get_expr ().get (), path, cpath);
+}
+
+void
+ResolveItem::visit (AST::Function &function)
+{
+  auto decl = CanonicalPath::new_seg (function.get_node_id (),
+				      function.get_function_name ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+
+  mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+  resolve_visibility (function.get_visibility ());
+
+  NodeId scope_node_id = function.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  if (function.has_generics ())
+    for (auto &generic : function.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  // resolve any where clause items
+  if (function.has_where_clause ())
+    ResolveWhereClause::Resolve (function.get_where_clause ());
+
+  if (function.has_return_type ())
+    ResolveType::go (function.get_return_type ().get ());
+
+  // we make a new scope so the names of parameters are resolved and shadowed
+  // correctly
+  for (auto &param : function.get_function_params ())
+    {
+      ResolveType::go (param.get_type ().get ());
+      PatternDeclaration::go (param.get_pattern ().get ());
+
+      // the mutability checker needs to verify for immutable decls the number
+      // of assignments are <1. This marks an implicit assignment
+    }
+
+  // resolve the function body
+  ResolveExpr::go (function.get_definition ().get (), path, cpath);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::InherentImpl &impl_block)
+{
+  NodeId scope_node_id = impl_block.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+  resolve_visibility (impl_block.get_visibility ());
+
+  if (impl_block.has_generics ())
+    for (auto &generic : impl_block.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  // resolve any where clause items
+  if (impl_block.has_where_clause ())
+    ResolveWhereClause::Resolve (impl_block.get_where_clause ());
+
+  // FIXME this needs to be protected behind nominal type-checks see:
+  // rustc --explain E0118
+  ResolveType::go (impl_block.get_type ().get ());
+
+  // Setup paths
+  CanonicalPath self_cpath = CanonicalPath::create_empty ();
+  bool ok = ResolveTypeToCanonicalPath::go (impl_block.get_type ().get (),
+					    self_cpath);
+  rust_assert (ok);
+  rust_debug ("AST::InherentImpl resolve Self: {%s}",
+	      self_cpath.get ().c_str ());
+
+  CanonicalPath impl_type = self_cpath;
+  CanonicalPath impl_prefix = prefix.append (impl_type);
+
+  // see https://godbolt.org/z/a3vMbsT6W
+  CanonicalPath cpath = CanonicalPath::create_empty ();
+  if (canonical_prefix.size () <= 1)
+    {
+      cpath = self_cpath;
+    }
+  else
+    {
+      std::string seg_buf = "<impl " + self_cpath.get () + ">";
+      CanonicalPath seg
+	= CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf);
+      cpath = canonical_prefix.append (seg);
+    }
+
+  // done setup paths
+
+  auto Self
+    = CanonicalPath::get_big_self (impl_block.get_type ()->get_node_id ());
+
+  resolver->get_type_scope ().insert (Self,
+				      impl_block.get_type ()->get_node_id (),
+				      impl_block.get_type ()->get_locus ());
+
+  for (auto &impl_item : impl_block.get_impl_items ())
+    {
+      rust_debug (
+	"AST::InherentImpl resolve_impl_item: impl_prefix={%s} cpath={%s}",
+	impl_prefix.get ().c_str (), cpath.get ().c_str ());
+      resolve_impl_item (impl_item.get (), impl_prefix, cpath);
+    }
+
+  resolver->get_type_scope ().peek ()->clear_name (
+    Self, impl_block.get_type ()->get_node_id ());
+
+  resolver->get_type_scope ().pop ();
+  resolver->get_name_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Method &method)
+{
+  auto decl
+    = CanonicalPath::new_seg (method.get_node_id (), method.get_method_name ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (method.get_node_id (), cpath);
+
+  NodeId scope_node_id = method.get_node_id ();
+
+  resolve_visibility (method.get_visibility ());
+
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  if (method.has_generics ())
+    for (auto &generic : method.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  // resolve any where clause items
+  if (method.has_where_clause ())
+    ResolveWhereClause::Resolve (method.get_where_clause ());
+
+  if (method.has_return_type ())
+    ResolveType::go (method.get_return_type ().get ());
+
+  // self turns into (self: Self) as a function param
+  AST::SelfParam &self_param = method.get_self_param ();
+  AST::IdentifierPattern self_pattern (self_param.get_node_id (), "self",
+				       self_param.get_locus (),
+				       self_param.get_has_ref (),
+				       self_param.get_is_mut (),
+				       std::unique_ptr<AST::Pattern> (nullptr));
+
+  std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+  segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+    new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+
+  AST::TypePath self_type_path (std::move (segments), self_param.get_locus ());
+
+  ResolveType::go (&self_type_path);
+  PatternDeclaration::go (&self_pattern);
+
+  // we make a new scope so the names of parameters are resolved and shadowed
+  // correctly
+  for (auto &param : method.get_function_params ())
+    {
+      ResolveType::go (param.get_type ().get ());
+      PatternDeclaration::go (param.get_pattern ().get ());
+    }
+
+  // resolve any where clause items
+  if (method.has_where_clause ())
+    ResolveWhereClause::Resolve (method.get_where_clause ());
+
+  // resolve the function body
+  ResolveExpr::go (method.get_definition ().get (), path, cpath);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::TraitImpl &impl_block)
+{
+  NodeId scope_node_id = impl_block.get_node_id ();
+
+  resolve_visibility (impl_block.get_visibility ());
+
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+  if (impl_block.has_generics ())
+    for (auto &generic : impl_block.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  // resolve any where clause items
+  if (impl_block.has_where_clause ())
+    ResolveWhereClause::Resolve (impl_block.get_where_clause ());
+
+  // CanonicalPath canonical_trait_type = CanonicalPath::create_empty ();
+  NodeId trait_resolved_node = ResolveType::go (&impl_block.get_trait_path ());
+  if (trait_resolved_node == UNKNOWN_NODEID)
+    {
+      resolver->get_type_scope ().pop ();
+      resolver->get_name_scope ().pop ();
+      return;
+    }
+
+  //   CanonicalPath canonical_impl_type = CanonicalPath::create_empty ();
+  NodeId type_resolved_node = ResolveType::go (impl_block.get_type ().get ());
+  if (type_resolved_node == UNKNOWN_NODEID)
+    {
+      resolver->get_type_scope ().pop ();
+      resolver->get_name_scope ().pop ();
+      return;
+    }
+
+  bool ok;
+  // setup paths
+  CanonicalPath canonical_trait_type = CanonicalPath::create_empty ();
+  ok = ResolveTypeToCanonicalPath::go (&impl_block.get_trait_path (),
+				       canonical_trait_type);
+  rust_assert (ok);
+
+  rust_debug ("AST::TraitImpl resolve trait type: {%s}",
+	      canonical_trait_type.get ().c_str ());
+
+  CanonicalPath canonical_impl_type = CanonicalPath::create_empty ();
+  ok = ResolveTypeToCanonicalPath::go (impl_block.get_type ().get (),
+				       canonical_impl_type);
+  rust_assert (ok);
+
+  rust_debug ("AST::TraitImpl resolve self: {%s}",
+	      canonical_impl_type.get ().c_str ());
+
+  // raw paths
+  CanonicalPath impl_type_seg = canonical_impl_type;
+  CanonicalPath trait_type_seg = canonical_trait_type;
+  CanonicalPath projection
+    = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (),
+						trait_type_seg, impl_type_seg);
+  CanonicalPath impl_prefix = prefix.append (projection);
+
+  // setup canonical-path
+  CanonicalPath canonical_projection
+    = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (),
+						canonical_trait_type,
+						canonical_impl_type);
+  CanonicalPath cpath = CanonicalPath::create_empty ();
+  if (canonical_prefix.size () <= 1)
+    {
+      cpath = canonical_projection;
+    }
+  else
+    {
+      std::string projection_str = canonical_projection.get ();
+      std::string seg_buf
+	= "<impl " + projection_str.substr (1, projection_str.size () - 2)
+	  + ">";
+      CanonicalPath seg
+	= CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf);
+      cpath = canonical_prefix.append (seg);
+    }
+
+  // DONE setup canonical-path
+
+  auto Self
+    = CanonicalPath::get_big_self (impl_block.get_type ()->get_node_id ());
+
+  resolver->get_type_scope ().insert (Self,
+				      impl_block.get_type ()->get_node_id (),
+				      impl_block.get_type ()->get_locus ());
+
+  for (auto &impl_item : impl_block.get_impl_items ())
+    {
+      rust_debug (
+	"AST::TraitImpl resolve_impl_item: impl_prefix={%s} cpath={%s}",
+	impl_prefix.get ().c_str (), cpath.get ().c_str ());
+      resolve_impl_item (impl_item.get (), impl_prefix, cpath);
+    }
+
+  resolver->get_type_scope ().peek ()->clear_name (
+    Self, impl_block.get_type ()->get_node_id ());
+  resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Trait &trait)
+{
+  NodeId scope_node_id = trait.get_node_id ();
+
+  resolve_visibility (trait.get_visibility ());
+
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+  // we need to inject an implicit self TypeParam here
+  AST::TypeParam *implicit_self
+    = new AST::TypeParam ("Self", trait.get_locus ());
+  trait.insert_implict_self (
+    std::unique_ptr<AST::GenericParam> (implicit_self));
+  CanonicalPath Self = CanonicalPath::get_big_self (trait.get_node_id ());
+
+  for (auto &generic : trait.get_generic_params ())
+    ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  // Self is an implicit TypeParam so lets mark it as such
+  resolver->get_type_scope ().append_reference_for_def (
+    Self.get_node_id (), implicit_self->get_node_id ());
+
+  if (trait.has_type_param_bounds ())
+    {
+      for (auto &bound : trait.get_type_param_bounds ())
+	{
+	  ResolveTypeBound::go (bound.get ());
+	}
+    }
+
+  // resolve any where clause items
+  if (trait.has_where_clause ())
+    ResolveWhereClause::Resolve (trait.get_where_clause ());
+
+  // resolve the paths
+  CanonicalPath path = CanonicalPath::create_empty ();
+  CanonicalPath cpath = CanonicalPath::create_empty ();
+  //
+
+  for (auto &item : trait.get_trait_items ())
+    {
+      ResolveTraitItems::go (item.get (), path, cpath);
+    }
+
+  resolver->get_type_scope ().pop ();
+  resolver->get_name_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::ExternBlock &extern_block)
+{
+  resolve_visibility (extern_block.get_visibility ());
+
+  for (auto &item : extern_block.get_extern_items ())
+    {
+      resolve_extern_item (item.get ());
+    }
+}
+
+void
+ResolveItem::resolve_impl_item (AST::TraitImplItem *item,
+				const CanonicalPath &prefix,
+				const CanonicalPath &canonical_prefix)
+{
+  ResolveImplItems::go (item, prefix, canonical_prefix);
+}
+
+void
+ResolveItem::resolve_impl_item (AST::InherentImplItem *item,
+				const CanonicalPath &prefix,
+				const CanonicalPath &canonical_prefix)
+{
+  ResolveImplItems::go (item, prefix, canonical_prefix);
+}
+
+void
+ResolveItem::resolve_extern_item (AST::ExternalItem *item)
+{
+  ResolveExternItem::go (item, prefix, canonical_prefix);
+}
+
+static void
+flatten_glob (const AST::UseTreeGlob &glob,
+	      std::vector<AST::SimplePath> &paths);
+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);
+
+static void
+flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
+{
+  switch (tree->get_kind ())
+    {
+      case AST::UseTree::Glob: {
+	auto glob = static_cast<const AST::UseTreeGlob *> (tree);
+	flatten_glob (*glob, paths);
+	break;
+      }
+      case AST::UseTree::Rebind: {
+	auto rebind = static_cast<const AST::UseTreeRebind *> (tree);
+	flatten_rebind (*rebind, paths);
+	break;
+      }
+      case AST::UseTree::List: {
+	auto list = static_cast<const AST::UseTreeList *> (tree);
+	flatten_list (*list, paths);
+	break;
+      }
+      break;
+    }
+}
+
+static void
+flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
+{
+  if (glob.has_path ())
+    paths.emplace_back (glob.get_path ());
+}
+
+static void
+flatten_rebind (const AST::UseTreeRebind &rebind,
+		std::vector<AST::SimplePath> &paths)
+{
+  auto path = rebind.get_path ();
+  if (rebind.has_path ())
+    paths.emplace_back (path);
+
+  // FIXME: Do we want to emplace the rebind here as well?
+  if (rebind.has_identifier ())
+    {
+      auto rebind_path = path;
+      auto new_seg = rebind.get_identifier ();
+
+      // Add the identifier as a new path
+      rebind_path.get_segments ().back ()
+	= AST::SimplePathSegment (new_seg, Location ());
+
+      paths.emplace_back (rebind_path);
+    }
+}
+
+static void
+flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
+{
+  auto prefix = AST::SimplePath::create_empty ();
+  if (list.has_path ())
+    prefix = list.get_path ();
+
+  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 ()));
+
+	  paths.emplace_back (new_path);
+	}
+    }
+}
+
+/**
+ * Flatten a UseDeclaration's UseTree into multiple simple paths to resolve.
+ *
+ * Given the following use declarations:
+ * ```
+ * use some::path::to_resolve; #1
+ * use some::path::to_glob::*; #2
+ * use some::path::{one, two}; #2
+ * ```
+ *
+ * In the first case, we simply want to return a vector with a single
+ * SimplePath:
+ * [some::path::to_resolve]
+ *
+ * In the second case, we want to resolve the glob's "origin path":
+ * [some::path::to_glob]
+ *
+ * Finally in the third case, we want to create two SimplePaths to resolve:
+ * [some::path::one, some::path::two]
+ */
+static std::vector<AST::SimplePath>
+flatten_use_dec_to_paths (const AST::UseDeclaration &use_item)
+{
+  auto paths = std::vector<AST::SimplePath> ();
+
+  const auto &tree = use_item.get_tree ();
+  flatten (tree.get (), paths);
+
+  return paths;
+}
+
+void
+ResolveItem::visit (AST::UseDeclaration &use_item)
+{
+  auto to_resolve = flatten_use_dec_to_paths (use_item);
+
+  for (auto &path : to_resolve)
+    ResolvePath::go (&path);
+}
+
+ResolveImplItems::ResolveImplItems (const CanonicalPath &prefix,
+				    const CanonicalPath &canonical_prefix)
+  : ResolveItem (prefix, canonical_prefix)
+{}
+
+void
+ResolveImplItems::go (AST::InherentImplItem *item, const CanonicalPath &prefix,
+		      const CanonicalPath &canonical_prefix)
+{
+  if (item->is_marked_for_strip ())
+    return;
+
+  ResolveImplItems resolver (prefix, canonical_prefix);
+  item->accept_vis (resolver);
+}
+
+void
+ResolveImplItems::go (AST::TraitImplItem *item, const CanonicalPath &prefix,
+		      const CanonicalPath &canonical_prefix)
+{
+  if (item->is_marked_for_strip ())
+    return;
+
+  ResolveImplItems resolver (prefix, canonical_prefix);
+  item->accept_vis (resolver);
+}
+
+void
+ResolveImplItems::visit (AST::TypeAlias &alias)
+{
+  ResolveItem::visit (alias);
+
+  resolve_visibility (alias.get_visibility ());
+
+  // FIXME this stops the erronious unused decls which will be fixed later on
+  resolver->get_type_scope ().append_reference_for_def (alias.get_node_id (),
+							alias.get_node_id ());
+}
+
+void
+ResolveExternItem::go (AST::ExternalItem *item, const CanonicalPath &prefix,
+		       const CanonicalPath &canonical_prefix)
+{
+  ResolveExternItem resolver (prefix, canonical_prefix);
+  item->accept_vis (resolver);
+}
+
+void
+ResolveExternItem::visit (AST::ExternalFunctionItem &function)
+{
+  NodeId scope_node_id = function.get_node_id ();
+  auto decl = CanonicalPath::new_seg (function.get_node_id (),
+				      function.get_identifier ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+
+  mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+  resolve_visibility (function.get_visibility ());
+
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  // resolve the generics
+  if (function.has_generics ())
+    for (auto &generic : function.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (function.has_return_type ())
+    ResolveType::go (function.get_return_type ().get ());
+
+  // we make a new scope so the names of parameters are resolved and shadowed
+  // correctly
+  for (auto &param : function.get_function_params ())
+    {
+      ResolveType::go (param.get_type ().get ());
+    }
+
+  // done
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExternItem::visit (AST::ExternalStaticItem &item)
+{
+  resolve_visibility (item.get_visibility ());
+
+  ResolveType::go (item.get_type ().get ());
+}
+
+} // namespace Resolver
+} // namespace Rust
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+rust_flatten_nested_glob (void)
+{
+  auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+  auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+  auto foobar = Rust::AST::SimplePath ({foo, bar});
+
+  auto glob
+    = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
+			      foobar, Location ());
+
+  auto paths = std::vector<Rust::AST::SimplePath> ();
+  Rust::Resolver::flatten_glob (glob, paths);
+
+  ASSERT_TRUE (!paths.empty ());
+  ASSERT_EQ (paths.size (), 1);
+  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+}
+
+static void
+rust_flatten_glob (void)
+{
+  auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ());
+
+  auto glob
+    = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
+			      frob, Location ());
+
+  auto paths = std::vector<Rust::AST::SimplePath> ();
+  Rust::Resolver::flatten_glob (glob, paths);
+
+  ASSERT_TRUE (!paths.empty ());
+  ASSERT_EQ (paths.size (), 1);
+  ASSERT_EQ (paths[0], "frobulator");
+}
+
+static void
+rust_flatten_rebind_none (void)
+{
+  auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+  auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+  auto foobar = Rust::AST::SimplePath ({foo, bar});
+
+  auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE,
+					  foobar, Location ());
+
+  auto paths = std::vector<Rust::AST::SimplePath> ();
+  Rust::Resolver::flatten_rebind (rebind, paths);
+
+  ASSERT_TRUE (!paths.empty ());
+  ASSERT_EQ (paths.size (), 1);
+  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+}
+
+static void
+rust_flatten_rebind (void)
+{
+  auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ());
+
+  auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
+					  frob, Location (), "saindoux");
+
+  auto paths = std::vector<Rust::AST::SimplePath> ();
+  Rust::Resolver::flatten_rebind (rebind, paths);
+
+  ASSERT_TRUE (!paths.empty ());
+  ASSERT_EQ (paths.size (), 2);
+  ASSERT_EQ (paths[0], "frobulator");
+  ASSERT_EQ (paths[1], "saindoux");
+}
+
+static void
+rust_flatten_rebind_nested (void)
+{
+  auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+  auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+  auto baz = Rust::AST::SimplePathSegment ("baz", Location ());
+
+  auto foo_bar_baz = Rust::AST::SimplePath ({foo, bar, baz});
+
+  auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
+					  foo_bar_baz, Location (), "saindoux");
+
+  auto paths = std::vector<Rust::AST::SimplePath> ();
+  Rust::Resolver::flatten_rebind (rebind, paths);
+
+  ASSERT_TRUE (!paths.empty ());
+  ASSERT_EQ (paths.size (), 2);
+  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
+  ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "saindoux");
+}
+
+static void
+rust_flatten_list (void)
+{
+  auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+  auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+  auto foo_bar = Rust::AST::SimplePath ({foo, bar});
+
+  auto baz = Rust::AST::SimplePath::from_str ("baz", Location ());
+  auto bul = Rust::AST::SimplePath::from_str ("bul", Location ());
+
+  // use foo::bar::{baz, bul};
+
+  auto use0 = std::unique_ptr<Rust::AST::UseTree> (
+    new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, baz,
+				  Location ()));
+  auto use1 = std::unique_ptr<Rust::AST::UseTree> (
+    new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, bul,
+				  Location ()));
+
+  auto uses = std::vector<std::unique_ptr<Rust::AST::UseTree>> ();
+  uses.emplace_back (std::move (use0));
+  uses.emplace_back (std::move (use1));
+
+  auto list = Rust::AST::UseTreeList (Rust::AST::UseTreeList::PATH_PREFIXED,
+				      foo_bar, std::move (uses), Location ());
+
+  auto paths = std::vector<Rust::AST::SimplePath> ();
+  Rust::Resolver::flatten_list (list, paths);
+
+  for (auto &path : paths)
+    fprintf (stderr, "%s\n", path.as_string ().c_str ());
+
+  ASSERT_TRUE (!paths.empty ());
+  ASSERT_EQ (paths.size (), 2);
+  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
+  ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "bul");
+}
+
+static void
+rust_use_dec_flattening (void)
+{
+  rust_flatten_glob ();
+  rust_flatten_nested_glob ();
+  rust_flatten_rebind_none ();
+  rust_flatten_rebind ();
+  rust_flatten_rebind_nested ();
+  rust_flatten_list ();
+}
+
+void
+rust_simple_path_resolve_test (void)
+{
+  rust_use_dec_flattening ();
+}
+
+} // namespace selftest
+
+#endif // CHECKING_P
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
new file mode 100644
index 00000000000..ce521f057f6
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -0,0 +1,149 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_ITEM_H
+#define RUST_AST_RESOLVE_ITEM_H
+
+#include "rust-ast-full-decls.h"
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+#include "rust-ast-resolve-toplevel.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-stmt.h"
+#include "config.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveTraitItems : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::TraitItem *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+  void visit (AST::TraitItemType &type) override;
+  void visit (AST::TraitItemFunc &func) override;
+  void visit (AST::TraitItemMethod &func) override;
+  void visit (AST::TraitItemConst &constant) override;
+
+private:
+  ResolveTraitItems (const CanonicalPath &prefix,
+		     const CanonicalPath &canonical_prefix);
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+class ResolveItem : public ResolverBase
+{
+public:
+  using Rust::Resolver::ResolverBase::visit;
+
+  static void go (AST::Item *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+  void visit (AST::TypeAlias &alias) override;
+  void visit (AST::Module &module) override;
+  void visit (AST::TupleStruct &struct_decl) override;
+  void visit (AST::Enum &enum_decl) override;
+  /* EnumItem doesn't need to be handled, no fields.  */
+  void visit (AST::EnumItem &item) override;
+  void visit (AST::EnumItemTuple &item) override;
+  void visit (AST::EnumItemStruct &item) override;
+  void visit (AST::EnumItemDiscriminant &item) override;
+  void visit (AST::StructStruct &struct_decl) override;
+  void visit (AST::Union &union_decl) override;
+  void visit (AST::StaticItem &var) override;
+  void visit (AST::ConstantItem &constant) override;
+  void visit (AST::Function &function) override;
+  void visit (AST::InherentImpl &impl_block) override;
+  void visit (AST::Method &method) override;
+  void visit (AST::TraitImpl &impl_block) override;
+  void visit (AST::Trait &trait) override;
+  void visit (AST::ExternBlock &extern_block) override;
+  void visit (AST::UseDeclaration &) override;
+
+protected:
+  void resolve_impl_item (AST::TraitImplItem *item, const CanonicalPath &prefix,
+			  const CanonicalPath &canonical_prefix);
+  void resolve_impl_item (AST::InherentImplItem *item,
+			  const CanonicalPath &prefix,
+			  const CanonicalPath &canonical_prefix);
+  void resolve_extern_item (AST::ExternalItem *item);
+
+  ResolveItem (const CanonicalPath &prefix,
+	       const CanonicalPath &canonical_prefix);
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+class ResolveImplItems : public ResolveItem
+{
+  using Rust::Resolver::ResolveItem::visit;
+
+public:
+  static void go (AST::InherentImplItem *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+  static void go (AST::TraitImplItem *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+  void visit (AST::TypeAlias &alias) override;
+
+private:
+  ResolveImplItems (const CanonicalPath &prefix,
+		    const CanonicalPath &canonical_prefix);
+};
+
+class ResolveExternItem : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::ExternalItem *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+  void visit (AST::ExternalFunctionItem &function) override;
+  void visit (AST::ExternalStaticItem &item) override;
+
+private:
+  ResolveExternItem (const CanonicalPath &prefix,
+		     const CanonicalPath &canonical_prefix)
+    : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+  {}
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#if CHECKING_P
+
+namespace selftest {
+extern void
+rust_simple_path_resolve_test (void);
+} // namespace selftest
+
+#endif // CHECKING_P
+
+#endif // RUST_AST_RESOLVE_ITEM_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc
new file mode 100644
index 00000000000..b139c6a8720
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-path.cc
@@ -0,0 +1,384 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-path.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-path.h"
+
+namespace Rust {
+namespace Resolver {
+
+ResolvePath::ResolvePath () : ResolverBase () {}
+
+void
+ResolvePath::go (AST::PathInExpression *expr)
+{
+  ResolvePath resolver;
+  resolver.resolve_path (expr);
+}
+
+void
+ResolvePath::go (AST::QualifiedPathInExpression *expr)
+{
+  ResolvePath resolver;
+  resolver.resolve_path (expr);
+}
+
+void
+ResolvePath::go (AST::SimplePath *expr)
+{
+  ResolvePath resolver;
+  resolver.resolve_path (expr);
+}
+
+void
+ResolvePath::resolve_path (AST::PathInExpression *expr)
+{
+  NodeId resolved_node_id = UNKNOWN_NODEID;
+  NodeId module_scope_id = resolver->peek_current_module_scope ();
+  NodeId previous_resolved_node_id = module_scope_id;
+  for (size_t i = 0; i < expr->get_segments ().size (); i++)
+    {
+      auto &segment = expr->get_segments ().at (i);
+      const AST::PathIdentSegment &ident_seg = segment.get_ident_segment ();
+      bool is_first_segment = i == 0;
+      resolved_node_id = UNKNOWN_NODEID;
+
+      bool in_middle_of_path = i > 0;
+      if (in_middle_of_path && segment.is_lower_self_seg ())
+	{
+	  // error[E0433]: failed to resolve: `self` in paths can only be used
+	  // in start position
+	  rust_error_at (segment.get_locus (),
+			 "failed to resolve: %<%s%> in paths can only be used "
+			 "in start position",
+			 segment.as_string ().c_str ());
+	  return;
+	}
+
+      NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+      if (segment.is_crate_path_seg ())
+	{
+	  // what is the current crate scope node id?
+	  module_scope_id = crate_scope_id;
+	  previous_resolved_node_id = module_scope_id;
+	  resolver->insert_resolved_name (segment.get_node_id (),
+					  module_scope_id);
+	  continue;
+	}
+      else if (segment.is_super_path_seg ())
+	{
+	  if (module_scope_id == crate_scope_id)
+	    {
+	      rust_error_at (segment.get_locus (),
+			     "cannot use %<super%> at the crate scope");
+	      return;
+	    }
+
+	  module_scope_id = resolver->peek_parent_module_scope ();
+	  previous_resolved_node_id = module_scope_id;
+	  resolver->insert_resolved_name (segment.get_node_id (),
+					  module_scope_id);
+	  continue;
+	}
+
+      // resolve any generic args
+      if (segment.has_generic_args ())
+	ResolveGenericArgs::go (segment.get_generic_args ());
+
+      // logic is awkward here there are a few cases
+      //
+      // T::Default
+      // mod::foo::impl_item
+      // super::super::module::item
+      // self
+      // self::foo
+      // self::foo::baz
+      //
+      // T::Default we can only resolve the T and cant do anything about Default
+      // its dependant on associated types
+      //
+      // mod::foo::impl_item
+      // we can resolve mod::foo but nothing about impl_item but we need to
+      // _always resolve generic arguments
+      //
+      // self is a simple single lookup
+      //
+      // we have module_scope_id for the next module_scope to lookup
+      // resolved_node_id is the thing we have resolve this segment to
+      //
+      // new algo?
+      // we can only use module resolution when the previous segment is either
+      // unknown or equal to this module_scope_id
+      //
+      // can only use old resolution when previous segment is unkown
+
+      if (is_first_segment)
+	{
+	  // name scope first
+	  NodeId resolved_node = UNKNOWN_NODEID;
+	  const CanonicalPath path
+	    = CanonicalPath::new_seg (segment.get_node_id (),
+				      ident_seg.as_string ());
+	  if (resolver->get_name_scope ().lookup (path, &resolved_node))
+	    {
+	      resolver->insert_resolved_name (segment.get_node_id (),
+					      resolved_node);
+	      resolved_node_id = resolved_node;
+	    }
+	  // check the type scope
+	  else if (resolver->get_type_scope ().lookup (path, &resolved_node))
+	    {
+	      resolver->insert_resolved_type (segment.get_node_id (),
+					      resolved_node);
+	      resolved_node_id = resolved_node;
+	    }
+	  else if (segment.is_lower_self_seg ())
+	    {
+	      module_scope_id = crate_scope_id;
+	      previous_resolved_node_id = module_scope_id;
+	      resolver->insert_resolved_name (segment.get_node_id (),
+					      module_scope_id);
+	      continue;
+	    }
+	  else
+	    {
+	      // no error handling here since we might be able to resolve via
+	      // the module hierarchy and handle errors at the end
+	    }
+	}
+
+      if (resolved_node_id == UNKNOWN_NODEID
+	  && previous_resolved_node_id == module_scope_id)
+	{
+	  Optional<CanonicalPath &> resolved_child
+	    = mappings->lookup_module_child (module_scope_id,
+					     ident_seg.as_string ());
+	  if (resolved_child.is_some ())
+	    {
+	      NodeId resolved_node = resolved_child->get_node_id ();
+	      if (resolver->get_name_scope ().decl_was_declared_here (
+		    resolved_node))
+		{
+		  resolved_node_id = resolved_node;
+		  resolver->insert_resolved_name (segment.get_node_id (),
+						  resolved_node);
+		}
+	      else if (resolver->get_type_scope ().decl_was_declared_here (
+			 resolved_node))
+		{
+		  resolved_node_id = resolved_node;
+		  resolver->insert_resolved_type (segment.get_node_id (),
+						  resolved_node);
+		}
+	      else
+		{
+		  rust_error_at (segment.get_locus (),
+				 "Cannot find path %<%s%> in this scope",
+				 segment.as_string ().c_str ());
+		  return;
+		}
+	    }
+	}
+
+      bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID;
+      if (did_resolve_segment)
+	{
+	  if (mappings->node_is_module (resolved_node_id)
+	      || mappings->node_is_crate (resolved_node_id))
+	    {
+	      module_scope_id = resolved_node_id;
+	    }
+	  previous_resolved_node_id = resolved_node_id;
+	}
+      else if (is_first_segment)
+	{
+	  rust_error_at (segment.get_locus (),
+			 "Cannot find path %<%s%> in this scope",
+			 segment.as_string ().c_str ());
+	  return;
+	}
+    }
+
+  resolved_node = resolved_node_id;
+  if (resolved_node_id != UNKNOWN_NODEID)
+    {
+      // name scope first
+      if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+	{
+	  resolver->insert_resolved_name (expr->get_node_id (),
+					  resolved_node_id);
+	}
+      // check the type scope
+      else if (resolver->get_type_scope ().decl_was_declared_here (
+		 resolved_node_id))
+	{
+	  resolver->insert_resolved_type (expr->get_node_id (),
+					  resolved_node_id);
+	}
+      else
+	{
+	  gcc_unreachable ();
+	}
+    }
+}
+
+void
+ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr)
+{
+  AST::QualifiedPathType &root_segment = expr->get_qualified_path_type ();
+  ResolveType::go (root_segment.get_type ().get ());
+  if (root_segment.has_as_clause ())
+    ResolveType::go (&root_segment.get_as_type_path ());
+
+  for (auto &segment : expr->get_segments ())
+    {
+      // we cant actually do anything with the segment itself since this is all
+      // the job of the type system to figure it out but we can resolve any
+      // generic arguments used
+      if (segment.has_generic_args ())
+	ResolveGenericArgs::go (segment.get_generic_args ());
+    }
+}
+
+void
+ResolvePath::resolve_path (AST::SimplePath *expr)
+{
+  NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+  NodeId module_scope_id = resolver->peek_current_module_scope ();
+
+  NodeId resolved_node_id = UNKNOWN_NODEID;
+  for (size_t i = 0; i < expr->get_segments ().size (); i++)
+    {
+      auto &segment = expr->get_segments ().at (i);
+      bool is_first_segment = i == 0;
+      resolved_node_id = UNKNOWN_NODEID;
+
+      if (segment.is_crate_path_seg ())
+	{
+	  // what is the current crate scope node id?
+	  module_scope_id = crate_scope_id;
+	  resolver->insert_resolved_name (segment.get_node_id (),
+					  module_scope_id);
+	  continue;
+	}
+      else if (segment.is_super_path_seg ())
+	{
+	  if (module_scope_id == crate_scope_id)
+	    {
+	      rust_error_at (segment.get_locus (),
+			     "cannot use %<super%> at the crate scope");
+	      return;
+	    }
+
+	  module_scope_id = resolver->peek_parent_module_scope ();
+	  resolver->insert_resolved_name (segment.get_node_id (),
+					  module_scope_id);
+	  continue;
+	}
+
+      Optional<CanonicalPath &> resolved_child
+	= mappings->lookup_module_child (module_scope_id,
+					 segment.get_segment_name ());
+      if (resolved_child.is_some ())
+	{
+	  NodeId resolved_node = resolved_child->get_node_id ();
+	  if (resolver->get_name_scope ().decl_was_declared_here (
+		resolved_node))
+	    {
+	      resolved_node_id = resolved_node;
+	      resolver->insert_resolved_name (segment.get_node_id (),
+					      resolved_node);
+	    }
+	  else if (resolver->get_type_scope ().decl_was_declared_here (
+		     resolved_node))
+	    {
+	      resolved_node_id = resolved_node;
+	      resolver->insert_resolved_type (segment.get_node_id (),
+					      resolved_node);
+	    }
+	  else
+	    {
+	      rust_error_at (segment.get_locus (),
+			     "Cannot find path %<%s%> in this scope",
+			     segment.as_string ().c_str ());
+	      return;
+	    }
+	}
+
+      if (resolved_node_id == UNKNOWN_NODEID && is_first_segment)
+	{
+	  // name scope first
+	  NodeId resolved_node = UNKNOWN_NODEID;
+	  const CanonicalPath path
+	    = CanonicalPath::new_seg (segment.get_node_id (),
+				      segment.get_segment_name ());
+	  if (resolver->get_name_scope ().lookup (path, &resolved_node))
+	    {
+	      resolved_node_id = resolved_node;
+	      resolver->insert_resolved_name (segment.get_node_id (),
+					      resolved_node);
+	    }
+	  // check the type scope
+	  else if (resolver->get_type_scope ().lookup (path, &resolved_node))
+	    {
+	      resolved_node_id = resolved_node;
+	      resolver->insert_resolved_type (segment.get_node_id (),
+					      resolved_node);
+	    }
+	}
+
+      if (resolved_node_id == UNKNOWN_NODEID)
+	{
+	  rust_error_at (segment.get_locus (),
+			 "cannot find simple path segment %<%s%> in this scope",
+			 segment.as_string ().c_str ());
+	  return;
+	}
+
+      if (mappings->node_is_module (resolved_node_id))
+	{
+	  module_scope_id = resolved_node_id;
+	}
+    }
+
+  resolved_node = resolved_node_id;
+  if (resolved_node_id != UNKNOWN_NODEID)
+    {
+      // name scope first
+      if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+	{
+	  resolver->insert_resolved_name (expr->get_node_id (),
+					  resolved_node_id);
+	}
+      // check the type scope
+      else if (resolver->get_type_scope ().decl_was_declared_here (
+		 resolved_node_id))
+	{
+	  resolver->insert_resolved_type (expr->get_node_id (),
+					  resolved_node_id);
+	}
+      else
+	{
+	  gcc_unreachable ();
+	}
+    }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.h b/gcc/rust/resolve/rust-ast-resolve-path.h
new file mode 100644
index 00000000000..a9af0c5819c
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-path.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_PATH_H
+#define RUST_AST_RESOLVE_PATH_H
+
+#include "rust-ast-resolve-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolvePath : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::PathInExpression *expr);
+  static void go (AST::QualifiedPathInExpression *expr);
+  static void go (AST::SimplePath *expr);
+
+private:
+  ResolvePath ();
+
+  void resolve_path (AST::PathInExpression *expr);
+  void resolve_path (AST::QualifiedPathInExpression *expr);
+  void resolve_path (AST::SimplePath *expr);
+
+  void
+  resolve_simple_path_segments (CanonicalPath prefix, size_t offs,
+				const std::vector<AST::SimplePathSegment> &segs,
+				NodeId expr_node_id, Location expr_locus);
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // !RUST_AST_RESOLVE_PATH_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
new file mode 100644
index 00000000000..9386d36d25e
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
@@ -0,0 +1,163 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-path.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+PatternDeclaration::visit (AST::PathInExpression &pattern)
+{
+  ResolvePath::go (&pattern);
+}
+
+void
+PatternDeclaration::visit (AST::TupleStructPattern &pattern)
+{
+  ResolvePath::go (&pattern.get_path ());
+
+  std::unique_ptr<AST::TupleStructItems> &items = pattern.get_items ();
+  switch (items->get_item_type ())
+    {
+      case AST::TupleStructItems::RANGE: {
+	// TODO
+	gcc_unreachable ();
+      }
+      break;
+
+      case AST::TupleStructItems::NO_RANGE: {
+	AST::TupleStructItemsNoRange &items_no_range
+	  = static_cast<AST::TupleStructItemsNoRange &> (*items.get ());
+
+	for (auto &inner_pattern : items_no_range.get_patterns ())
+	  {
+	    PatternDeclaration::go (inner_pattern.get ());
+	  }
+      }
+      break;
+    }
+}
+
+void
+PatternDeclaration::visit (AST::StructPattern &pattern)
+{
+  ResolvePath::go (&pattern.get_path ());
+
+  auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+  for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
+    {
+      switch (field->get_item_type ())
+	{
+	  case AST::StructPatternField::ItemType::TUPLE_PAT: {
+	    // TODO
+	    gcc_unreachable ();
+	  }
+	  break;
+
+	  case AST::StructPatternField::ItemType::IDENT_PAT: {
+	    // TODO
+	    gcc_unreachable ();
+	  }
+	  break;
+
+	  case AST::StructPatternField::ItemType::IDENT: {
+	    AST::StructPatternFieldIdent &ident
+	      = static_cast<AST::StructPatternFieldIdent &> (*field.get ());
+
+	    resolver->get_name_scope ().insert (
+	      CanonicalPath::new_seg (ident.get_node_id (),
+				      ident.get_identifier ()),
+	      ident.get_node_id (), ident.get_locus ());
+	  }
+	  break;
+	}
+    }
+
+  // TODO
+  rust_assert (!struct_pattern_elems.has_etc ());
+}
+
+void
+PatternDeclaration::visit (AST::TuplePattern &pattern)
+{
+  std::unique_ptr<AST::TuplePatternItems> &items = pattern.get_items ();
+  switch (items->get_pattern_type ())
+    {
+      case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: {
+	AST::TuplePatternItemsMultiple &ref
+	  = *static_cast<AST::TuplePatternItemsMultiple *> (
+	    pattern.get_items ().get ());
+
+	for (auto &p : ref.get_patterns ())
+	  p->accept_vis (*this);
+      }
+      break;
+
+      case AST::TuplePatternItems::TuplePatternItemType::RANGED: {
+	AST::TuplePatternItemsRanged &ref
+	  = *static_cast<AST::TuplePatternItemsRanged *> (
+	    pattern.get_items ().get ());
+
+	for (auto &p : ref.get_lower_patterns ())
+	  p->accept_vis (*this);
+	for (auto &p : ref.get_upper_patterns ())
+	  p->accept_vis (*this);
+      }
+      break;
+    }
+}
+
+static void
+resolve_range_pattern_bound (AST::RangePatternBound *bound)
+{
+  switch (bound->get_bound_type ())
+    {
+    case AST::RangePatternBound::RangePatternBoundType::LITERAL:
+      // Nothing to resolve for a literal.
+      break;
+
+      case AST::RangePatternBound::RangePatternBoundType::PATH: {
+	AST::RangePatternBoundPath &ref
+	  = *static_cast<AST::RangePatternBoundPath *> (bound);
+
+	ResolvePath::go (&ref.get_path ());
+      }
+      break;
+
+      case AST::RangePatternBound::RangePatternBoundType::QUALPATH: {
+	AST::RangePatternBoundQualPath &ref
+	  = *static_cast<AST::RangePatternBoundQualPath *> (bound);
+
+	ResolvePath::go (&ref.get_qualified_path ());
+      }
+      break;
+    }
+}
+
+void
+PatternDeclaration::visit (AST::RangePattern &pattern)
+{
+  resolve_range_pattern_bound (pattern.get_upper_bound ().get ());
+  resolve_range_pattern_bound (pattern.get_lower_bound ().get ());
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h
new file mode 100644
index 00000000000..fcbb23fdf08
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h
@@ -0,0 +1,98 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_PATTERN_H
+#define RUST_AST_RESOLVE_PATTERN_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolvePattern : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::Pattern *pattern)
+  {
+    ResolvePattern resolver;
+    pattern->accept_vis (resolver);
+  }
+
+  void visit (AST::IdentifierPattern &pattern) override
+  {
+    if (resolver->get_name_scope ().lookup (
+	  CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()),
+	  &resolved_node))
+      {
+	resolver->insert_resolved_name (pattern.get_node_id (), resolved_node);
+      }
+  }
+
+private:
+  ResolvePattern () : ResolverBase () {}
+};
+
+class PatternDeclaration : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::Pattern *pattern)
+  {
+    PatternDeclaration resolver;
+    pattern->accept_vis (resolver);
+  };
+
+  void visit (AST::IdentifierPattern &pattern) override
+  {
+    // if we have a duplicate id this then allows for shadowing correctly
+    // as new refs to this decl will match back here so it is ok to overwrite
+    resolver->get_name_scope ().insert (
+      CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()),
+      pattern.get_node_id (), pattern.get_locus ());
+  }
+
+  void visit (AST::WildcardPattern &pattern) override
+  {
+    resolver->get_name_scope ().insert (
+      CanonicalPath::new_seg (pattern.get_node_id (), "_"),
+      pattern.get_node_id (), pattern.get_locus ());
+  }
+
+  // cases in a match expression
+  void visit (AST::PathInExpression &pattern) override;
+
+  void visit (AST::StructPattern &pattern) override;
+
+  void visit (AST::TupleStructPattern &pattern) override;
+
+  void visit (AST::TuplePattern &pattern) override;
+
+  void visit (AST::RangePattern &pattern) override;
+
+private:
+  PatternDeclaration () : ResolverBase () {}
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_PATTERN_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc
new file mode 100644
index 00000000000..1ce3df0891c
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-stmt.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveStmt::visit (AST::ExternBlock &extern_block)
+{
+  resolve_visibility (extern_block.get_visibility ());
+  for (auto &item : extern_block.get_extern_items ())
+    {
+      ResolveToplevelExternItem::go (item.get (),
+				     CanonicalPath::create_empty ());
+      ResolveExternItem::go (item.get (), prefix, canonical_prefix);
+    }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
new file mode 100644
index 00000000000..6f21bc35a33
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -0,0 +1,378 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_STMT_H
+#define RUST_AST_RESOLVE_STMT_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveStmt : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::Stmt *stmt, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix,
+		  const CanonicalPath &enum_prefix)
+  {
+    if (stmt->is_marked_for_strip ())
+      return;
+
+    ResolveStmt resolver (prefix, canonical_prefix, enum_prefix);
+    stmt->accept_vis (resolver);
+  }
+
+  void visit (AST::ExprStmtWithBlock &stmt) override
+  {
+    ResolveExpr::go (stmt.get_expr ().get (), prefix, canonical_prefix);
+  }
+
+  void visit (AST::ExprStmtWithoutBlock &stmt) override
+  {
+    ResolveExpr::go (stmt.get_expr ().get (), prefix, canonical_prefix);
+  }
+
+  void visit (AST::ConstantItem &constant) override
+  {
+    auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+					constant.get_identifier ());
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (constant.get_node_id (), cpath);
+
+    resolver->get_name_scope ().insert (
+      path, constant.get_node_id (), constant.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (constant.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    ResolveType::go (constant.get_type ().get ());
+    ResolveExpr::go (constant.get_expr ().get (), prefix, canonical_prefix);
+  }
+
+  void visit (AST::LetStmt &stmt) override
+  {
+    if (stmt.has_init_expr ())
+      {
+	ResolveExpr::go (stmt.get_init_expr ().get (), prefix,
+			 canonical_prefix);
+      }
+
+    PatternDeclaration::go (stmt.get_pattern ().get ());
+    if (stmt.has_type ())
+      ResolveType::go (stmt.get_type ().get ());
+  }
+
+  void visit (AST::TupleStruct &struct_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+					struct_decl.get_identifier ());
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (struct_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId scope_node_id = struct_decl.get_node_id ();
+    resolver->get_type_scope ().push (scope_node_id);
+
+    if (struct_decl.has_generics ())
+      {
+	for (auto &generic : struct_decl.get_generic_params ())
+	  ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+      }
+
+    for (AST::TupleField &field : struct_decl.get_fields ())
+      ResolveType::go (field.get_field_type ().get ());
+
+    resolver->get_type_scope ().pop ();
+  }
+
+  void visit (AST::Enum &enum_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (),
+					enum_decl.get_identifier ());
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, enum_decl.get_node_id (), enum_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (enum_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId scope_node_id = enum_decl.get_node_id ();
+    resolver->get_type_scope ().push (scope_node_id);
+
+    if (enum_decl.has_generics ())
+      {
+	for (auto &generic : enum_decl.get_generic_params ())
+	  ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+      }
+
+    for (auto &variant : enum_decl.get_variants ())
+      ResolveStmt::go (variant.get (), path, canonical_prefix, path);
+
+    resolver->get_type_scope ().pop ();
+  }
+
+  void visit (AST::EnumItem &item) override
+  {
+    auto decl = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    // Done, no fields.
+  }
+
+  void visit (AST::EnumItemTuple &item) override
+  {
+    auto decl = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &field : item.get_tuple_fields ())
+      {
+	if (field.get_field_type ()->is_marked_for_strip ())
+	  continue;
+
+	ResolveType::go (field.get_field_type ().get ());
+      }
+  }
+
+  void visit (AST::EnumItemStruct &item) override
+  {
+    auto decl = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &field : item.get_struct_fields ())
+      {
+	if (field.get_field_type ()->is_marked_for_strip ())
+	  continue;
+
+	ResolveType::go (field.get_field_type ().get ());
+      }
+  }
+
+  void visit (AST::EnumItemDiscriminant &item) override
+  {
+    auto decl = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    // Done, no fields.
+  }
+
+  void visit (AST::StructStruct &struct_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+					struct_decl.get_identifier ());
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (struct_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId scope_node_id = struct_decl.get_node_id ();
+    resolver->get_type_scope ().push (scope_node_id);
+
+    if (struct_decl.has_generics ())
+      {
+	for (auto &generic : struct_decl.get_generic_params ())
+	  ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+      }
+
+    for (AST::StructField &field : struct_decl.get_fields ())
+      {
+	if (field.get_field_type ()->is_marked_for_strip ())
+	  continue;
+
+	ResolveType::go (field.get_field_type ().get ());
+      }
+
+    resolver->get_type_scope ().pop ();
+  }
+
+  void visit (AST::Union &union_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (union_decl.get_node_id (),
+					union_decl.get_identifier ());
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (union_decl.get_node_id (), cpath);
+
+    resolver->get_type_scope ().insert (
+      path, union_decl.get_node_id (), union_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (union_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId scope_node_id = union_decl.get_node_id ();
+    resolver->get_type_scope ().push (scope_node_id);
+
+    if (union_decl.has_generics ())
+      for (auto &generic : union_decl.get_generic_params ())
+	ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+    for (AST::StructField &field : union_decl.get_variants ())
+      {
+	if (field.get_field_type ()->is_marked_for_strip ())
+	  continue;
+
+	ResolveType::go (field.get_field_type ().get ());
+      }
+
+    resolver->get_type_scope ().pop ();
+  }
+
+  void visit (AST::Function &function) override
+  {
+    auto decl = CanonicalPath::new_seg (function.get_node_id (),
+					function.get_function_name ());
+    auto path = decl; // this ensures we have the correct relative resolution
+    auto cpath = canonical_prefix.append (decl);
+    mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+    resolver->get_name_scope ().insert (
+      path, function.get_node_id (), function.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (function.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId scope_node_id = function.get_node_id ();
+    resolver->get_name_scope ().push (scope_node_id);
+    resolver->get_type_scope ().push (scope_node_id);
+    resolver->get_label_scope ().push (scope_node_id);
+    resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+    resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+    resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+    if (function.has_generics ())
+      for (auto &generic : function.get_generic_params ())
+	ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+    if (function.has_return_type ())
+      ResolveType::go (function.get_return_type ().get ());
+
+    // we make a new scope so the names of parameters are resolved and shadowed
+    // correctly
+    for (auto &param : function.get_function_params ())
+      {
+	ResolveType::go (param.get_type ().get ());
+	PatternDeclaration::go (param.get_pattern ().get ());
+      }
+
+    // resolve the function body
+    ResolveExpr::go (function.get_definition ().get (), path, cpath);
+
+    resolver->get_name_scope ().pop ();
+    resolver->get_type_scope ().pop ();
+    resolver->get_label_scope ().pop ();
+  }
+
+  void visit (AST::ExternBlock &extern_block) override;
+
+private:
+  ResolveStmt (const CanonicalPath &prefix,
+	       const CanonicalPath &canonical_prefix,
+	       const CanonicalPath &enum_prefix)
+    : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix),
+      enum_prefix (enum_prefix)
+  {}
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+
+  /* item declaration statements are not given a canonical path, but enum items
+   * (variants) do inherit the enum path/identifier name.  */
+  const CanonicalPath &enum_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_STMT_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc
new file mode 100644
index 00000000000..4d8b6c788f3
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-struct-expr-field.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveStructExprField::go (AST::StructExprField *field,
+			    const CanonicalPath &prefix,
+			    const CanonicalPath &canonical_prefix)
+{
+  ResolveStructExprField resolver (prefix, canonical_prefix);
+  field->accept_vis (resolver);
+}
+
+ResolveStructExprField::ResolveStructExprField (
+  const CanonicalPath &prefix, const CanonicalPath &canonical_prefix)
+  : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+void
+ResolveStructExprField::visit (AST::StructExprFieldIdentifierValue &field)
+{
+  ResolveExpr::go (field.get_value ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveStructExprField::visit (AST::StructExprFieldIndexValue &field)
+{
+  ResolveExpr::go (field.get_value ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveStructExprField::visit (AST::StructExprFieldIdentifier &field)
+{
+  AST::IdentifierExpr expr (field.get_field_name (), {}, field.get_locus ());
+  expr.set_node_id (field.get_node_id ());
+
+  ResolveExpr::go (&expr, prefix, canonical_prefix);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h
new file mode 100644
index 00000000000..ce60b136e4b
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_STRUCT_EXPR_FIELD
+#define RUST_AST_RESOLVE_STRUCT_EXPR_FIELD
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+// this resolves values being assigned not that the field actually exists yet.
+
+class ResolveStructExprField : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::StructExprField *field, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+  void visit (AST::StructExprFieldIdentifierValue &field) override;
+
+  void visit (AST::StructExprFieldIndexValue &field) override;
+
+  void visit (AST::StructExprFieldIdentifier &field) override;
+
+private:
+  ResolveStructExprField (const CanonicalPath &prefix,
+			  const CanonicalPath &canonical_prefix);
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_STRUCT_EXPR_FIELD
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
new file mode 100644
index 00000000000..43ae8e47673
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -0,0 +1,460 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_TOPLEVEL_H
+#define RUST_AST_RESOLVE_TOPLEVEL_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-implitem.h"
+#include "rust-ast-full.h"
+#include "rust-name-resolver.h"
+#include "rust-session-manager.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveTopLevel : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::Item *item, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix)
+  {
+    if (item->is_marked_for_strip ())
+      return;
+
+    ResolveTopLevel resolver (prefix, canonical_prefix);
+    item->accept_vis (resolver);
+
+    NodeId current_module = resolver.resolver->peek_current_module_scope ();
+    resolver.mappings->insert_child_item_to_parent_module_mapping (
+      item->get_node_id (), current_module);
+  }
+
+  void visit (AST::Module &module) override
+  {
+    auto mod
+      = CanonicalPath::new_seg (module.get_node_id (), module.get_name ());
+    auto path = prefix.append (mod);
+    auto cpath = canonical_prefix.append (mod);
+
+    resolver->get_name_scope ().insert (
+      path, module.get_node_id (), module.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (module.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, mod);
+    mappings->insert_module_child (current_module, module.get_node_id ());
+
+    resolver->push_new_module_scope (module.get_node_id ());
+    for (auto &item : module.get_items ())
+      ResolveTopLevel::go (item.get (), path, cpath);
+
+    resolver->pop_module_scope ();
+
+    mappings->insert_canonical_path (module.get_node_id (), cpath);
+  }
+
+  void visit (AST::TypeAlias &alias) override
+  {
+    auto talias = CanonicalPath::new_seg (alias.get_node_id (),
+					  alias.get_new_type_name ());
+    auto path = prefix.append (talias);
+    auto cpath = canonical_prefix.append (talias);
+
+    resolver->get_type_scope ().insert (
+      path, alias.get_node_id (), alias.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (alias.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, talias);
+    mappings->insert_canonical_path (alias.get_node_id (), cpath);
+  }
+
+  void visit (AST::TupleStruct &struct_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+					struct_decl.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (struct_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+  }
+
+  void visit (AST::Enum &enum_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (),
+					enum_decl.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, enum_decl.get_node_id (), enum_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (enum_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &variant : enum_decl.get_variants ())
+      ResolveTopLevel::go (variant.get (), path, cpath);
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
+  }
+
+  void visit (AST::EnumItem &item) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+  }
+
+  void visit (AST::EnumItemTuple &item) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+  }
+
+  void visit (AST::EnumItemStruct &item) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+  }
+
+  void visit (AST::EnumItemDiscriminant &item) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (item.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (item.get_node_id (), cpath);
+  }
+
+  void visit (AST::StructStruct &struct_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+					struct_decl.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (struct_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+  }
+
+  void visit (AST::Union &union_decl) override
+  {
+    auto decl = CanonicalPath::new_seg (union_decl.get_node_id (),
+					union_decl.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, union_decl.get_node_id (), union_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (union_decl.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (union_decl.get_node_id (), cpath);
+  }
+
+  void visit (AST::StaticItem &var) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (var.get_node_id (), var.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, var.get_node_id (), var.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (var.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (var.get_node_id (), cpath);
+  }
+
+  void visit (AST::ConstantItem &constant) override
+  {
+    auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+					constant.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, constant.get_node_id (), constant.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (constant.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (constant.get_node_id (), cpath);
+  }
+
+  void visit (AST::Function &function) override
+  {
+    auto decl = CanonicalPath::new_seg (function.get_node_id (),
+					function.get_function_name ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, function.get_node_id (), function.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (function.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (function.get_node_id (), cpath);
+  }
+
+  void visit (AST::InherentImpl &impl_block) override
+  {
+    std::string raw_impl_type_path = impl_block.get_type ()->as_string ();
+    CanonicalPath impl_type
+      = CanonicalPath::new_seg (impl_block.get_type ()->get_node_id (),
+				raw_impl_type_path);
+    CanonicalPath impl_prefix = prefix.append (impl_type);
+
+    for (auto &impl_item : impl_block.get_impl_items ())
+      ResolveToplevelImplItem::go (impl_item.get (), impl_prefix);
+  }
+
+  void visit (AST::TraitImpl &impl_block) override
+  {
+    std::string raw_impl_type_path = impl_block.get_type ()->as_string ();
+    CanonicalPath impl_type_seg
+      = CanonicalPath::new_seg (impl_block.get_type ()->get_node_id (),
+				raw_impl_type_path);
+
+    std::string raw_trait_type_path = impl_block.get_trait_path ().as_string ();
+    CanonicalPath trait_type_seg
+      = CanonicalPath::new_seg (impl_block.get_trait_path ().get_node_id (),
+				raw_trait_type_path);
+
+    CanonicalPath projection
+      = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (),
+						  trait_type_seg,
+						  impl_type_seg);
+    CanonicalPath impl_prefix = prefix.append (projection);
+
+    resolver->get_name_scope ().insert (
+      impl_prefix, impl_block.get_node_id (), impl_block.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (impl_block.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &impl_item : impl_block.get_impl_items ())
+      ResolveToplevelImplItem::go (impl_item.get (), impl_prefix);
+  }
+
+  void visit (AST::Trait &trait) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (trait.get_node_id (), trait.get_identifier ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_type_scope ().insert (
+      path, trait.get_node_id (), trait.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (trait.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &item : trait.get_trait_items ())
+      ResolveTopLevelTraitItems::go (item.get (), path, cpath);
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_canonical_path (trait.get_node_id (), cpath);
+  }
+
+  void visit (AST::ExternBlock &extern_block) override
+  {
+    for (auto &item : extern_block.get_extern_items ())
+      {
+	ResolveToplevelExternItem::go (item.get (), prefix);
+      }
+  }
+
+  void visit (AST::ExternCrate &extern_crate) override
+  {
+    if (extern_crate.is_marked_for_strip ())
+      return;
+
+    NodeId resolved_crate = UNKNOWN_NODEID;
+    if (extern_crate.references_self ())
+      {
+	CrateNum crate_num = mappings->get_current_crate ();
+	bool ok = mappings->crate_num_to_nodeid (crate_num, resolved_crate);
+	rust_assert (ok);
+      }
+    else
+      {
+	CrateNum found_crate_num = UNKNOWN_CREATENUM;
+	bool found
+	  = mappings->lookup_crate_name (extern_crate.get_referenced_crate (),
+					 found_crate_num);
+	if (!found)
+	  {
+	    rust_error_at (extern_crate.get_locus (), "unknown crate %<%s%>",
+			   extern_crate.get_referenced_crate ().c_str ());
+	    return;
+	  }
+
+	bool ok
+	  = mappings->crate_num_to_nodeid (found_crate_num, resolved_crate);
+	if (!ok)
+	  {
+	    rust_internal_error_at (extern_crate.get_locus (),
+				    "failed to resolve crate to nodeid");
+	    return;
+	  }
+      }
+
+    if (resolved_crate == UNKNOWN_NODEID)
+      {
+	rust_error_at (extern_crate.get_locus (), "failed to resolve crate");
+	return;
+      }
+
+    // mark the node as resolved
+    resolver->insert_resolved_name (extern_crate.get_node_id (),
+				    resolved_crate);
+    CanonicalPath decl
+      = extern_crate.has_as_clause ()
+	  ? CanonicalPath::new_seg (extern_crate.get_node_id (),
+				    extern_crate.get_as_clause ())
+	  : CanonicalPath::new_seg (extern_crate.get_node_id (),
+				    extern_crate.get_referenced_crate ());
+
+    resolver->get_type_scope ().insert (
+      decl, resolved_crate, extern_crate.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	RichLocation r (extern_crate.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+private:
+  ResolveTopLevel (const CanonicalPath &prefix,
+		   const CanonicalPath &canonical_prefix)
+    : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+  {}
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_TOPLEVEL_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc
new file mode 100644
index 00000000000..6b08613755a
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -0,0 +1,582 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+// rust-ast-resolve-type.h
+
+void
+ResolveType::visit (AST::ArrayType &type)
+{
+  type.get_elem_type ()->accept_vis (*this);
+  ResolveExpr::go (type.get_size_expr ().get (), CanonicalPath::create_empty (),
+		   CanonicalPath::create_empty ());
+}
+
+void
+ResolveType::visit (AST::TraitObjectTypeOneBound &type)
+{
+  ResolveTypeBound::go (&type.get_trait_bound ());
+}
+
+void
+ResolveType::visit (AST::TraitObjectType &type)
+{
+  for (auto &bound : type.get_type_param_bounds ())
+    {
+      /* NodeId bound_resolved_id = */
+      ResolveTypeBound::go (bound.get ());
+    }
+}
+
+void
+ResolveType::visit (AST::ReferenceType &type)
+{
+  resolved_node = ResolveType::go (type.get_type_referenced ().get ());
+}
+
+void
+ResolveType::visit (AST::RawPointerType &type)
+{
+  resolved_node = ResolveType::go (type.get_type_pointed_to ().get ());
+}
+
+void
+ResolveType::visit (AST::InferredType &type)
+{
+  // FIXME
+}
+
+void
+ResolveType::visit (AST::NeverType &type)
+{
+  // FIXME
+}
+
+void
+ResolveType::visit (AST::SliceType &type)
+{
+  resolved_node = ResolveType::go (type.get_elem_type ().get ());
+}
+
+// resolve relative type-paths
+
+bool
+ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
+{
+  auto resolver = Resolver::get ();
+  auto mappings = Analysis::Mappings::get ();
+
+  NodeId module_scope_id = resolver->peek_current_module_scope ();
+  NodeId previous_resolved_node_id = module_scope_id;
+  for (size_t i = 0; i < path.get_segments ().size (); i++)
+    {
+      auto &segment = path.get_segments ().at (i);
+      const AST::PathIdentSegment &ident_seg = segment->get_ident_segment ();
+      bool is_first_segment = i == 0;
+      resolved_node_id = UNKNOWN_NODEID;
+
+      bool in_middle_of_path = i > 0;
+      if (in_middle_of_path && segment->is_lower_self_seg ())
+	{
+	  // error[E0433]: failed to resolve: `self` in paths can only be used
+	  // in start position
+	  rust_error_at (segment->get_locus (),
+			 "failed to resolve: %<%s%> in paths can only be used "
+			 "in start position",
+			 segment->as_string ().c_str ());
+	  return false;
+	}
+
+      NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+      if (segment->is_crate_path_seg ())
+	{
+	  // what is the current crate scope node id?
+	  module_scope_id = crate_scope_id;
+	  previous_resolved_node_id = module_scope_id;
+	  resolver->insert_resolved_name (segment->get_node_id (),
+					  module_scope_id);
+
+	  continue;
+	}
+      else if (segment->is_super_path_seg ())
+	{
+	  if (module_scope_id == crate_scope_id)
+	    {
+	      rust_error_at (segment->get_locus (),
+			     "cannot use super at the crate scope");
+	      return false;
+	    }
+
+	  module_scope_id = resolver->peek_parent_module_scope ();
+	  previous_resolved_node_id = module_scope_id;
+	  resolver->insert_resolved_name (segment->get_node_id (),
+					  module_scope_id);
+	  continue;
+	}
+
+      switch (segment->get_type ())
+	{
+	  case AST::TypePathSegment::SegmentType::GENERIC: {
+	    AST::TypePathSegmentGeneric *s
+	      = static_cast<AST::TypePathSegmentGeneric *> (segment.get ());
+	    if (s->has_generic_args ())
+	      ResolveGenericArgs::go (s->get_generic_args ());
+	  }
+	  break;
+
+	case AST::TypePathSegment::SegmentType::REG:
+	  // nothing to do
+	  break;
+
+	case AST::TypePathSegment::SegmentType::FUNCTION:
+	  gcc_unreachable ();
+	  break;
+	}
+
+      if (is_first_segment)
+	{
+	  // name scope first
+	  NodeId resolved_node = UNKNOWN_NODEID;
+	  const CanonicalPath path
+	    = CanonicalPath::new_seg (segment->get_node_id (),
+				      ident_seg.as_string ());
+	  if (resolver->get_type_scope ().lookup (path, &resolved_node))
+	    {
+	      resolver->insert_resolved_type (segment->get_node_id (),
+					      resolved_node);
+	      resolved_node_id = resolved_node;
+	    }
+	  else if (resolver->get_name_scope ().lookup (path, &resolved_node))
+	    {
+	      resolver->insert_resolved_name (segment->get_node_id (),
+					      resolved_node);
+	      resolved_node_id = resolved_node;
+	    }
+	  else if (segment->is_lower_self_seg ())
+	    {
+	      // what is the current crate scope node id?
+	      module_scope_id = crate_scope_id;
+	      previous_resolved_node_id = module_scope_id;
+	      resolver->insert_resolved_name (segment->get_node_id (),
+					      module_scope_id);
+
+	      continue;
+	    }
+	}
+
+      if (resolved_node_id == UNKNOWN_NODEID
+	  && previous_resolved_node_id == module_scope_id)
+	{
+	  Optional<CanonicalPath &> resolved_child
+	    = mappings->lookup_module_child (module_scope_id,
+					     ident_seg.as_string ());
+	  if (resolved_child.is_some ())
+	    {
+	      NodeId resolved_node = resolved_child->get_node_id ();
+	      if (resolver->get_name_scope ().decl_was_declared_here (
+		    resolved_node))
+		{
+		  resolved_node_id = resolved_node;
+		  resolver->insert_resolved_name (segment->get_node_id (),
+						  resolved_node);
+		}
+	      else if (resolver->get_type_scope ().decl_was_declared_here (
+			 resolved_node))
+		{
+		  resolved_node_id = resolved_node;
+		  resolver->insert_resolved_type (segment->get_node_id (),
+						  resolved_node);
+		}
+	      else
+		{
+		  rust_error_at (segment->get_locus (),
+				 "Cannot find path %<%s%> in this scope",
+				 segment->as_string ().c_str ());
+		  return false;
+		}
+	    }
+	}
+
+      bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID;
+      if (did_resolve_segment)
+	{
+	  if (mappings->node_is_module (resolved_node_id)
+	      || mappings->node_is_crate (resolved_node_id))
+	    {
+	      module_scope_id = resolved_node_id;
+	    }
+	  previous_resolved_node_id = resolved_node_id;
+	}
+      else if (is_first_segment)
+	{
+	  rust_error_at (segment->get_locus (),
+			 "failed to resolve TypePath: %s in this scope",
+			 segment->as_string ().c_str ());
+	  return false;
+	}
+    }
+
+  if (resolved_node_id != UNKNOWN_NODEID)
+    {
+      // name scope first
+      if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+	{
+	  resolver->insert_resolved_name (path.get_node_id (),
+					  resolved_node_id);
+	}
+      // check the type scope
+      else if (resolver->get_type_scope ().decl_was_declared_here (
+		 resolved_node_id))
+	{
+	  resolver->insert_resolved_type (path.get_node_id (),
+					  resolved_node_id);
+	}
+      else
+	{
+	  gcc_unreachable ();
+	}
+    }
+
+  return true;
+}
+
+// qualified type paths
+
+ResolveRelativeQualTypePath::ResolveRelativeQualTypePath ()
+  : failure_flag (false)
+{}
+
+bool
+ResolveRelativeQualTypePath::go (AST::QualifiedPathInType &path)
+{
+  ResolveRelativeQualTypePath o;
+
+  // resolve the type and trait path
+  auto &qualified_path = path.get_qualified_path_type ();
+  if (!o.resolve_qual_seg (qualified_path))
+    return false;
+
+  // qualified types are similar to other paths in that we cannot guarantee
+  // that we can resolve the path at name resolution. We must look up
+  // associated types and type information to figure this out properly
+
+  std::unique_ptr<AST::TypePathSegment> &associated
+    = path.get_associated_segment ();
+
+  associated->accept_vis (o);
+  if (o.failure_flag)
+    return false;
+
+  for (auto &seg : path.get_segments ())
+    {
+      seg->accept_vis (o);
+      if (o.failure_flag)
+	return false;
+    }
+
+  return true;
+}
+
+bool
+ResolveRelativeQualTypePath::resolve_qual_seg (AST::QualifiedPathType &seg)
+{
+  if (seg.is_error ())
+    {
+      rust_error_at (seg.get_locus (), "segment has error: %s",
+		     seg.as_string ().c_str ());
+      return false;
+    }
+
+  auto type = seg.get_type ().get ();
+  NodeId type_resolved_node = ResolveType::go (type);
+  if (type_resolved_node == UNKNOWN_NODEID)
+    return false;
+
+  if (!seg.has_as_clause ())
+    return true;
+
+  NodeId trait_resolved_node = ResolveType::go (&seg.get_as_type_path ());
+  if (trait_resolved_node == UNKNOWN_NODEID)
+    return false;
+
+  return true;
+}
+
+void
+ResolveRelativeQualTypePath::visit (AST::TypePathSegmentGeneric &seg)
+{
+  if (seg.is_error ())
+    {
+      failure_flag = true;
+      rust_error_at (seg.get_locus (), "segment has error: %s",
+		     seg.as_string ().c_str ());
+      return;
+    }
+
+  ResolveGenericArgs::go (seg.get_generic_args ());
+}
+
+void
+ResolveRelativeQualTypePath::visit (AST::TypePathSegment &seg)
+{
+  if (seg.is_error ())
+    {
+      failure_flag = true;
+      rust_error_at (seg.get_locus (), "segment has error: %s",
+		     seg.as_string ().c_str ());
+      return;
+    }
+}
+
+// resolve to canonical path
+
+bool
+ResolveTypeToCanonicalPath::go (AST::Type *type, CanonicalPath &result)
+{
+  ResolveTypeToCanonicalPath resolver;
+  type->accept_vis (resolver);
+  result = resolver.result;
+  return !resolver.result.is_empty ();
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TypePath &path)
+{
+  NodeId resolved_node = UNKNOWN_NODEID;
+  if (!resolver->lookup_resolved_name (path.get_node_id (), &resolved_node))
+    {
+      resolver->lookup_resolved_type (path.get_node_id (), &resolved_node);
+    }
+
+  if (resolved_node == UNKNOWN_NODEID)
+    return;
+
+  const CanonicalPath *type_path = nullptr;
+  if (mappings->lookup_canonical_path (resolved_node, &type_path))
+    {
+      auto &final_seg = path.get_segments ().back ();
+      switch (final_seg->get_type ())
+	{
+	  case AST::TypePathSegment::SegmentType::GENERIC: {
+	    AST::TypePathSegmentGeneric *s
+	      = static_cast<AST::TypePathSegmentGeneric *> (final_seg.get ());
+
+	    std::vector<CanonicalPath> args;
+	    if (s->has_generic_args ())
+	      {
+		ResolveGenericArgs::go (s->get_generic_args ());
+		for (auto &generic : s->get_generic_args ().get_generic_args ())
+		  {
+		    // FIXME: What do we want to do here in case there is a
+		    // constant or an ambiguous const generic?
+		    // TODO: At that point, will all generics have been
+		    // disambiguated? Can we thus canonical resolve types and
+		    // const and `gcc_unreachable` on ambiguous types?
+		    // This is probably fine as we just want to canonicalize
+		    // types, right?
+		    if (generic.get_kind () == AST::GenericArg::Kind::Type)
+		      {
+			CanonicalPath arg = CanonicalPath::create_empty ();
+			bool ok = ResolveTypeToCanonicalPath::go (
+			  generic.get_type ().get (), arg);
+			if (ok)
+			  args.push_back (std::move (arg));
+		      }
+		  }
+	      }
+
+	    result = *type_path;
+	    if (!args.empty ())
+	      {
+		// append this onto the path
+		std::string buf;
+		for (size_t i = 0; i < args.size (); i++)
+		  {
+		    bool has_next = (i + 1) < args.size ();
+		    const auto &arg = args.at (i);
+
+		    buf += arg.get ();
+		    if (has_next)
+		      buf += ", ";
+		  }
+
+		std::string arg_seg = "<" + buf + ">";
+		CanonicalPath argument_seg
+		  = CanonicalPath::new_seg (s->get_node_id (), arg_seg);
+		result = result.append (argument_seg);
+	      }
+	  }
+	  break;
+
+	default:
+	  result = *type_path;
+	  break;
+	}
+    }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::ReferenceType &type)
+{
+  CanonicalPath path = CanonicalPath::create_empty ();
+  bool ok
+    = ResolveTypeToCanonicalPath::go (type.get_type_referenced ().get (), path);
+  if (ok)
+    {
+      std::string ref_type_str = type.is_mut () ? "mut" : "";
+      std::string ref_path = "&" + ref_type_str + " " + path.get ();
+      result = CanonicalPath::new_seg (type.get_node_id (), ref_path);
+    }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::RawPointerType &type)
+{
+  CanonicalPath path = CanonicalPath::create_empty ();
+  bool ok
+    = ResolveTypeToCanonicalPath::go (type.get_type_pointed_to ().get (), path);
+  if (ok)
+    {
+      std::string ptr_type_str
+	= type.get_pointer_type () == AST::RawPointerType::CONST ? "const"
+								 : "mut";
+      std::string ptr_path = "*" + ptr_type_str + " " + path.get ();
+      result = CanonicalPath::new_seg (type.get_node_id (), ptr_path);
+    }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::SliceType &type)
+{
+  CanonicalPath path = CanonicalPath::create_empty ();
+  bool ok = ResolveTypeToCanonicalPath::go (type.get_elem_type ().get (), path);
+  if (ok)
+    {
+      std::string slice_path = "[" + path.get () + "]";
+      result = CanonicalPath::new_seg (type.get_node_id (), slice_path);
+    }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TraitObjectTypeOneBound &type)
+{
+  CanonicalPath path = CanonicalPath::create_empty ();
+  bool ok
+    = ResolveTypeToCanonicalPath::go (&type.get_trait_bound ().get_type_path (),
+				      path);
+  if (ok)
+    {
+      std::string slice_path = "<dyn " + path.get () + ">";
+      result = CanonicalPath::new_seg (type.get_node_id (), slice_path);
+    }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type)
+{
+  // FIXME is this actually allowed? dyn A+B
+  gcc_unreachable ();
+}
+
+ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath ()
+  : ResolverBase (), result (CanonicalPath::create_empty ())
+{}
+
+bool
+ResolveGenericArgs::is_const_value_name (const CanonicalPath &path)
+{
+  NodeId resolved;
+  auto found = resolver->get_name_scope ().lookup (path, &resolved);
+
+  return found;
+}
+
+bool
+ResolveGenericArgs::is_type_name (const CanonicalPath &path)
+{
+  NodeId resolved;
+  auto found = resolver->get_type_scope ().lookup (path, &resolved);
+
+  return found;
+}
+
+void
+ResolveGenericArgs::disambiguate (AST::GenericArg &arg)
+{
+  auto path = canonical_prefix.append (
+    CanonicalPath::new_seg (UNKNOWN_NODEID, arg.get_path ()));
+
+  auto is_type = is_type_name (path);
+  auto is_value = is_const_value_name (path);
+
+  // In case we cannot find anything, we resolve the ambiguity to a type.
+  // This causes the typechecker to error out properly and when necessary.
+  // But types also take priority over const values in the case of
+  // ambiguities, hence the weird control flow
+  if (is_type || (!is_type && !is_value))
+    arg = arg.disambiguate_to_type ();
+  else if (is_value)
+    arg = arg.disambiguate_to_const ();
+}
+
+void
+ResolveGenericArgs::resolve_disambiguated_generic (AST::GenericArg &arg)
+{
+  switch (arg.get_kind ())
+    {
+    case AST::GenericArg::Kind::Const:
+      ResolveExpr::go (arg.get_expression ().get (), prefix, canonical_prefix);
+      break;
+    case AST::GenericArg::Kind::Type:
+      ResolveType::go (arg.get_type ().get ());
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+void
+ResolveGenericArgs::go (AST::GenericArgs &generic_args)
+{
+  auto empty = CanonicalPath::create_empty ();
+
+  go (generic_args, empty, empty);
+}
+
+void
+ResolveGenericArgs::go (AST::GenericArgs &generic_args,
+			const CanonicalPath &prefix,
+			const CanonicalPath &canonical_prefix)
+{
+  auto resolver = ResolveGenericArgs (prefix, canonical_prefix);
+
+  for (auto &arg : generic_args.get_generic_args ())
+    {
+      if (arg.get_kind () == AST::GenericArg::Kind::Either)
+	resolver.disambiguate (arg);
+
+      resolver.resolve_disambiguated_generic (arg);
+    }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
new file mode 100644
index 00000000000..5a71268c0d4
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -0,0 +1,290 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_TYPE_H
+#define RUST_AST_RESOLVE_TYPE_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveRelativeTypePath
+{
+public:
+  static bool go (AST::TypePath &path, NodeId &resolved_node_id);
+};
+
+class ResolveRelativeQualTypePath : public ResolverBase
+{
+  using ResolverBase::visit;
+
+public:
+  static bool go (AST::QualifiedPathInType &path);
+
+  void visit (AST::TypePathSegmentGeneric &seg) override;
+
+  void visit (AST::TypePathSegment &seg) override;
+
+protected:
+  bool resolve_qual_seg (AST::QualifiedPathType &seg);
+
+private:
+  ResolveRelativeQualTypePath ();
+
+  bool failure_flag;
+};
+
+class ResolveType : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static NodeId go (AST::Type *type)
+  {
+    ResolveType resolver;
+    type->accept_vis (resolver);
+    return resolver.resolved_node;
+  }
+
+  void visit (AST::BareFunctionType &fntype) override
+  {
+    for (auto &param : fntype.get_function_params ())
+      ResolveType::go (param.get_type ().get ());
+
+    if (fntype.has_return_type ())
+      ResolveType::go (fntype.get_return_type ().get ());
+  }
+
+  void visit (AST::TupleType &tuple) override
+  {
+    if (tuple.is_unit_type ())
+      {
+	resolved_node = resolver->get_unit_type_node_id ();
+	return;
+      }
+
+    for (auto &elem : tuple.get_elems ())
+      ResolveType::go (elem.get ());
+  }
+
+  void visit (AST::TypePath &path) override
+  {
+    ResolveRelativeTypePath::go (path, resolved_node);
+  }
+
+  void visit (AST::QualifiedPathInType &path) override
+  {
+    ResolveRelativeQualTypePath::go (path);
+  }
+
+  void visit (AST::ArrayType &type) override;
+
+  void visit (AST::ReferenceType &type) override;
+
+  void visit (AST::InferredType &type) override;
+
+  void visit (AST::NeverType &type) override;
+
+  void visit (AST::RawPointerType &type) override;
+
+  void visit (AST::TraitObjectTypeOneBound &type) override;
+
+  void visit (AST::TraitObjectType &type) override;
+
+  void visit (AST::SliceType &type) override;
+
+private:
+  ResolveType () : ResolverBase () {}
+};
+
+class ResolveTypeBound : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static NodeId go (AST::TypeParamBound *type)
+  {
+    ResolveTypeBound resolver;
+    type->accept_vis (resolver);
+    return resolver.resolved_node;
+  };
+
+  void visit (AST::TraitBound &bound) override
+  {
+    resolved_node = ResolveType::go (&bound.get_type_path ());
+  }
+
+private:
+  ResolveTypeBound () : ResolverBase () {}
+};
+
+class ResolveGenericParam : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static NodeId go (AST::GenericParam *param, const CanonicalPath &prefix,
+		    const CanonicalPath &canonical_prefix)
+  {
+    ResolveGenericParam resolver (prefix, canonical_prefix);
+    param->accept_vis (resolver);
+    return resolver.resolved_node;
+  }
+
+  void visit (AST::ConstGenericParam &param) override
+  {
+    ResolveType::go (param.get_type ().get ());
+
+    if (param.has_default_value ())
+      ResolveExpr::go (param.get_default_value ().get_expression ().get (),
+		       prefix, canonical_prefix);
+
+    ok = true;
+  }
+
+  void visit (AST::TypeParam &param) override
+  {
+    // if it has a type lets resolve it
+    if (param.has_type ())
+      ResolveType::go (param.get_type ().get ());
+
+    if (param.has_type_param_bounds ())
+      {
+	for (auto &bound : param.get_type_param_bounds ())
+	  {
+	    ResolveTypeBound::go (bound.get ());
+	  }
+      }
+
+    auto seg = CanonicalPath::new_seg (param.get_node_id (),
+				       param.get_type_representation ());
+    resolver->get_type_scope ().insert (
+      seg, param.get_node_id (), param.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+	rust_error_at (param.get_locus (),
+		       "generic param redefined multiple times");
+	rust_error_at (locus, "was defined here");
+      });
+
+    mappings->insert_canonical_path (param.get_node_id (), seg);
+  }
+
+private:
+  ResolveGenericParam (const CanonicalPath &prefix,
+		       const CanonicalPath &canonical_prefix)
+    : ResolverBase (), ok (false), prefix (prefix),
+      canonical_prefix (canonical_prefix)
+  {}
+
+  bool ok;
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+class ResolveWhereClause : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void Resolve (AST::WhereClause &where_clause)
+  {
+    ResolveWhereClause r;
+    for (auto &clause : where_clause.get_items ())
+      clause->accept_vis (r);
+  }
+
+  void visit (AST::TypeBoundWhereClauseItem &item) override
+  {
+    ResolveType::go (item.get_type ().get ());
+    if (item.has_type_param_bounds ())
+      {
+	for (auto &bound : item.get_type_param_bounds ())
+	  {
+	    ResolveTypeBound::go (bound.get ());
+	  }
+      }
+  }
+
+private:
+  ResolveWhereClause () : ResolverBase () {}
+};
+
+class ResolveTypeToCanonicalPath : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static bool go (AST::Type *type, CanonicalPath &result);
+
+  void visit (AST::TypePath &path) override;
+
+  void visit (AST::ReferenceType &type) override;
+
+  void visit (AST::RawPointerType &type) override;
+
+  void visit (AST::SliceType &type) override;
+
+  void visit (AST::TraitObjectTypeOneBound &type) override;
+
+  void visit (AST::TraitObjectType &type) override;
+
+private:
+  ResolveTypeToCanonicalPath ();
+
+  CanonicalPath result;
+};
+
+class ResolveGenericArgs : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static void go (AST::GenericArgs &generic_args);
+  static void go (AST::GenericArgs &generic_args, const CanonicalPath &prefix,
+		  const CanonicalPath &canonical_prefix);
+
+private:
+  ResolveGenericArgs (const CanonicalPath &prefix,
+		      const CanonicalPath &canonical_prefix)
+    : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+  {}
+
+  bool is_type_name (const CanonicalPath &path);
+  bool is_const_value_name (const CanonicalPath &path);
+
+  /**
+   * Resolve a disambiguated generic arg
+   */
+  void disambiguate (AST::GenericArg &arg);
+
+  /**
+   * Resolve a disambiguated generic arg
+   */
+  void resolve_disambiguated_generic (AST::GenericArg &arg);
+
+  const CanonicalPath &prefix;
+  const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_TYPE_H
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
new file mode 100644
index 00000000000..93fa7c8761c
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -0,0 +1,115 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve.h"
+#include "rust-ast-full.h"
+#include "rust-tyty.h"
+#include "rust-ast-resolve-toplevel.h"
+#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-resolve-struct-expr-field.h"
+
+extern bool
+saw_errors (void);
+
+namespace Rust {
+namespace Resolver {
+
+// NameResolution
+
+NameResolution *
+NameResolution::get ()
+{
+  static NameResolution *instance;
+  if (instance == nullptr)
+    instance = new NameResolution ();
+
+  return instance;
+}
+
+NameResolution::NameResolution ()
+  : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ())
+{
+  // these are global
+  resolver->get_type_scope ().push (mappings->get_next_node_id ());
+  resolver->insert_builtin_types (resolver->get_type_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+}
+
+void
+NameResolution::Resolve (AST::Crate &crate)
+{
+  auto resolver = get ();
+  resolver->go (crate);
+}
+
+void
+NameResolution::go (AST::Crate &crate)
+{
+  // lookup current crate name
+  CrateNum cnum = mappings->get_current_crate ();
+  std::string crate_name;
+  bool ok = mappings->get_crate_name (cnum, crate_name);
+  rust_assert (ok);
+
+  // setup the ribs
+  NodeId scope_node_id = crate.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  // get the root segment
+  CanonicalPath crate_prefix
+    = CanonicalPath::new_seg (scope_node_id, crate_name);
+  crate_prefix.set_crate_num (cnum);
+
+  // setup a dummy crate node
+  resolver->get_name_scope ().insert (
+    CanonicalPath::new_seg (crate.get_node_id (), "__$$crate__"),
+    crate.get_node_id (), Location ());
+
+  // setup the root scope
+  resolver->push_new_module_scope (scope_node_id);
+
+  // first gather the top-level namespace names then we drill down so this
+  // allows for resolving forward declarations since an impl block might have
+  // a Self type Foo which is defined after the impl block for example.
+  for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+    ResolveTopLevel::go (it->get (), CanonicalPath::create_empty (),
+			 crate_prefix);
+
+  // FIXME remove this
+  if (saw_errors ())
+    {
+      resolver->pop_module_scope ();
+      return;
+    }
+
+  // next we can drill down into the items and their scopes
+  for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+    ResolveItem::go (it->get (), CanonicalPath::create_empty (), crate_prefix);
+
+  // done
+  resolver->pop_module_scope ();
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve.h b/gcc/rust/resolve/rust-ast-resolve.h
new file mode 100644
index 00000000000..a2e10d5c742
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-resolve.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_H
+#define RUST_AST_RESOLVE_H
+
+#include "rust-name-resolver.h"
+#include "rust-ast-full.h"
+#include "rust-hir-map.h"
+
+namespace Rust {
+namespace Resolver {
+
+class NameResolution
+{
+public:
+  static void Resolve (AST::Crate &crate);
+
+  static NameResolution *get ();
+
+  ~NameResolution () {}
+
+private:
+  void go (AST::Crate &crate);
+
+  NameResolution ();
+
+  Resolver *resolver;
+  Analysis::Mappings *mappings;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_H
diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h
new file mode 100644
index 00000000000..74551cb014d
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-verify-assignee.h
@@ -0,0 +1,84 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_VERIFY_ASSIGNEE
+#define RUST_AST_VERIFY_ASSIGNEE
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class VerifyAsignee : public ResolverBase
+{
+  using Rust::Resolver::ResolverBase::visit;
+
+public:
+  static bool go (AST::Expr *assignee, NodeId parent)
+  {
+    VerifyAsignee checker (parent);
+    assignee->accept_vis (checker);
+    if (!checker.ok)
+      rust_error_at (assignee->get_locus (),
+		     "invalid left-hand side of assignment");
+    return checker.ok;
+  }
+
+  void visit (AST::ArrayIndexExpr &expr) override
+  {
+    expr.get_array_expr ()->accept_vis (*this);
+  }
+
+  void visit (AST::FieldAccessExpr &expr) override
+  {
+    expr.get_receiver_expr ()->accept_vis (*this);
+  }
+
+  void visit (AST::TupleIndexExpr &expr) override
+  {
+    expr.get_tuple_expr ()->accept_vis (*this);
+  }
+
+  void visit (AST::IdentifierExpr &expr) override
+  {
+    if (!resolver->get_name_scope ().lookup (
+	  CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
+	  &resolved_node))
+      return;
+
+    ok = true;
+  }
+
+  void visit (AST::DereferenceExpr &expr) override
+  {
+    expr.get_dereferenced_expr ()->accept_vis (*this);
+  }
+
+  void visit (AST::PathInExpression &expr) override { ok = true; }
+
+private:
+  VerifyAsignee (NodeId parent) : ResolverBase (), ok (false) {}
+
+  bool ok;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_VERIFY_ASSIGNEE
diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc
new file mode 100644
index 00000000000..fb7087425c1
--- /dev/null
+++ b/gcc/rust/resolve/rust-name-resolver.cc
@@ -0,0 +1,503 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-name-resolver.h"
+#include "rust-ast-full.h"
+
+#define MKBUILTIN_TYPE(_X, _R, _TY)                                            \
+  do                                                                           \
+    {                                                                          \
+      AST::PathIdentSegment seg (_X, Linemap::predeclared_location ());        \
+      auto typePath = ::std::unique_ptr<AST::TypePathSegment> (                \
+	new AST::TypePathSegment (::std::move (seg), false,                    \
+				  Linemap::predeclared_location ()));          \
+      ::std::vector< ::std::unique_ptr<AST::TypePathSegment> > segs;           \
+      segs.push_back (::std::move (typePath));                                 \
+      auto builtin_type                                                        \
+	= new AST::TypePath (::std::move (segs),                               \
+			     Linemap::predeclared_location (), false);         \
+      _R.push_back (builtin_type);                                             \
+      tyctx->insert_builtin (_TY->get_ref (), builtin_type->get_node_id (),    \
+			     _TY);                                             \
+      mappings->insert_node_to_hir (builtin_type->get_node_id (),              \
+				    _TY->get_ref ());                          \
+      mappings->insert_canonical_path (                                        \
+	builtin_type->get_node_id (),                                          \
+	CanonicalPath::new_seg (builtin_type->get_node_id (), _X));            \
+    }                                                                          \
+  while (0)
+
+namespace Rust {
+namespace Resolver {
+
+Rib::Rib (CrateNum crateNum, NodeId node_id)
+  : crate_num (crateNum), node_id (node_id),
+    mappings (Analysis::Mappings::get ())
+{}
+
+void
+Rib::insert_name (
+  const CanonicalPath &path, NodeId id, Location locus, bool shadow,
+  std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb)
+{
+  auto it = path_mappings.find (path);
+  bool path_already_exists = it != path_mappings.end ();
+  if (path_already_exists && !shadow)
+    {
+      const auto &decl = decls_within_rib.find (it->second);
+      if (decl != decls_within_rib.end ())
+	dup_cb (path, it->second, decl->second);
+      else
+	dup_cb (path, it->second, locus);
+
+      return;
+    }
+
+  path_mappings[path] = id;
+  reverse_path_mappings.insert (std::pair<NodeId, CanonicalPath> (id, path));
+  decls_within_rib.insert (std::pair<NodeId, Location> (id, locus));
+  references[id] = {};
+}
+
+bool
+Rib::lookup_name (const CanonicalPath &ident, NodeId *id)
+{
+  auto it = path_mappings.find (ident);
+  if (it == path_mappings.end ())
+    return false;
+
+  *id = it->second;
+  return true;
+}
+
+void
+Rib::clear_name (const CanonicalPath &ident, NodeId id)
+{
+  auto ii = path_mappings.find (ident);
+  if (ii != path_mappings.end ())
+    path_mappings.erase (ii);
+
+  auto ij = reverse_path_mappings.find (id);
+  if (ij != reverse_path_mappings.end ())
+    reverse_path_mappings.erase (ij);
+
+  auto ik = decls_within_rib.find (id);
+  if (ik != decls_within_rib.end ())
+    decls_within_rib.erase (ik);
+}
+
+void
+Rib::append_reference_for_def (NodeId def, NodeId ref)
+{
+  references[def].insert (ref);
+}
+
+bool
+Rib::have_references_for_node (NodeId def) const
+{
+  auto it = references.find (def);
+  if (it == references.end ())
+    return false;
+
+  return !it->second.empty ();
+}
+
+bool
+Rib::decl_was_declared_here (NodeId def) const
+{
+  for (auto &it : decls_within_rib)
+    {
+      if (it.first == def)
+	return true;
+    }
+  return false;
+}
+
+void
+Rib::debug () const
+{
+  fprintf (stderr, "%s\n", debug_str ().c_str ());
+}
+
+std::string
+Rib::debug_str () const
+{
+  std::string buffer;
+  for (const auto &it : path_mappings)
+    {
+      buffer += it.first.get () + "=" + std::to_string (it.second);
+      buffer += ",";
+    }
+  return "{" + buffer + "}";
+}
+
+Scope::Scope (CrateNum crate_num) : crate_num (crate_num) {}
+
+void
+Scope::insert (
+  const CanonicalPath &ident, NodeId id, Location locus, bool shadow,
+  std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb)
+{
+  peek ()->insert_name (ident, id, locus, shadow, dup_cb);
+}
+
+void
+Scope::insert (const CanonicalPath &ident, NodeId id, Location locus)
+{
+  peek ()->insert_name (ident, id, locus, true,
+			[] (const CanonicalPath &, NodeId, Location) -> void {
+			});
+}
+
+bool
+Scope::lookup (const CanonicalPath &ident, NodeId *id)
+{
+  NodeId lookup = UNKNOWN_NODEID;
+  iterate ([&] (Rib *r) mutable -> bool {
+    if (r->lookup_name (ident, &lookup))
+      return false;
+    return true;
+  });
+
+  *id = lookup;
+  return lookup != UNKNOWN_NODEID;
+}
+
+void
+Scope::iterate (std::function<bool (Rib *)> cb)
+{
+  for (auto it = stack.rbegin (); it != stack.rend (); ++it)
+    {
+      if (!cb (*it))
+	return;
+    }
+}
+
+void
+Scope::iterate (std::function<bool (const Rib *)> cb) const
+{
+  for (auto it = stack.rbegin (); it != stack.rend (); ++it)
+    {
+      if (!cb (*it))
+	return;
+    }
+}
+
+Rib *
+Scope::peek ()
+{
+  return stack.back ();
+}
+
+void
+Scope::push (NodeId id)
+{
+  stack.push_back (new Rib (get_crate_num (), id));
+}
+
+Rib *
+Scope::pop ()
+{
+  Rib *r = peek ();
+  stack.pop_back ();
+  return r;
+}
+
+void
+Scope::append_reference_for_def (NodeId refId, NodeId defId)
+{
+  bool ok = false;
+  iterate ([&] (Rib *r) mutable -> bool {
+    if (r->decl_was_declared_here (defId))
+      {
+	ok = true;
+	r->append_reference_for_def (defId, refId);
+      }
+    return true;
+  });
+  rust_assert (ok);
+}
+
+bool
+Scope::decl_was_declared_here (NodeId def) const
+{
+  bool found = false;
+  iterate ([&] (const Rib *r) -> bool {
+    if (r->decl_was_declared_here (def))
+      {
+	found = true;
+	return false;
+      }
+    return true;
+  });
+  return found;
+}
+
+Resolver::Resolver ()
+  : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()),
+    name_scope (Scope (mappings->get_current_crate ())),
+    type_scope (Scope (mappings->get_current_crate ())),
+    label_scope (Scope (mappings->get_current_crate ())),
+    macro_scope (Scope (mappings->get_current_crate ())),
+    global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID)
+{
+  generate_builtins ();
+}
+
+Resolver *
+Resolver::get ()
+{
+  static Resolver *instance;
+  if (instance == nullptr)
+    instance = new Resolver ();
+
+  return instance;
+}
+
+void
+Resolver::push_new_name_rib (Rib *r)
+{
+  rust_assert (name_ribs.find (r->get_node_id ()) == name_ribs.end ());
+  name_ribs[r->get_node_id ()] = r;
+}
+
+void
+Resolver::push_new_type_rib (Rib *r)
+{
+  if (type_ribs.size () == 0)
+    global_type_node_id = r->get_node_id ();
+
+  rust_assert (type_ribs.find (r->get_node_id ()) == type_ribs.end ());
+  type_ribs[r->get_node_id ()] = r;
+}
+
+void
+Resolver::push_new_label_rib (Rib *r)
+{
+  rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ());
+  label_ribs[r->get_node_id ()] = r;
+}
+
+void
+Resolver::push_new_macro_rib (Rib *r)
+{
+  rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ());
+  macro_ribs[r->get_node_id ()] = r;
+}
+
+bool
+Resolver::find_name_rib (NodeId id, Rib **rib)
+{
+  auto it = name_ribs.find (id);
+  if (it == name_ribs.end ())
+    return false;
+
+  *rib = it->second;
+  return true;
+}
+
+bool
+Resolver::find_type_rib (NodeId id, Rib **rib)
+{
+  auto it = type_ribs.find (id);
+  if (it == type_ribs.end ())
+    return false;
+
+  *rib = it->second;
+  return true;
+}
+
+bool
+Resolver::find_macro_rib (NodeId id, Rib **rib)
+{
+  auto it = macro_ribs.find (id);
+  if (it == macro_ribs.end ())
+    return false;
+
+  *rib = it->second;
+  return true;
+}
+
+void
+Resolver::insert_builtin_types (Rib *r)
+{
+  auto builtins = get_builtin_types ();
+  for (auto &builtin : builtins)
+    {
+      CanonicalPath builtin_path
+	= CanonicalPath::new_seg (builtin->get_node_id (),
+				  builtin->as_string ());
+      r->insert_name (builtin_path, builtin->get_node_id (),
+		      Linemap::predeclared_location (), false,
+		      [] (const CanonicalPath &, NodeId, Location) -> void {});
+    }
+}
+
+std::vector<AST::Type *> &
+Resolver::get_builtin_types ()
+{
+  return builtins;
+}
+
+void
+Resolver::generate_builtins ()
+{
+  auto u8
+    = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U8);
+  auto u16
+    = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U16);
+  auto u32
+    = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U32);
+  auto u64
+    = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U64);
+  auto u128
+    = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U128);
+  auto i8 = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I8);
+  auto i16
+    = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I16);
+  auto i32
+    = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I32);
+  auto i64
+    = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I64);
+  auto i128
+    = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I128);
+  auto rbool = new TyTy::BoolType (mappings->get_next_hir_id ());
+  auto f32
+    = new TyTy::FloatType (mappings->get_next_hir_id (), TyTy::FloatType::F32);
+  auto f64
+    = new TyTy::FloatType (mappings->get_next_hir_id (), TyTy::FloatType::F64);
+  auto usize = new TyTy::USizeType (mappings->get_next_hir_id ());
+  auto isize = new TyTy::ISizeType (mappings->get_next_hir_id ());
+  auto char_tyty = new TyTy::CharType (mappings->get_next_hir_id ());
+  auto str = new TyTy::StrType (mappings->get_next_hir_id ());
+  auto never = new TyTy::NeverType (mappings->get_next_hir_id ());
+
+  MKBUILTIN_TYPE ("u8", builtins, u8);
+  MKBUILTIN_TYPE ("u16", builtins, u16);
+  MKBUILTIN_TYPE ("u32", builtins, u32);
+  MKBUILTIN_TYPE ("u64", builtins, u64);
+  MKBUILTIN_TYPE ("u128", builtins, u128);
+  MKBUILTIN_TYPE ("i8", builtins, i8);
+  MKBUILTIN_TYPE ("i16", builtins, i16);
+  MKBUILTIN_TYPE ("i32", builtins, i32);
+  MKBUILTIN_TYPE ("i64", builtins, i64);
+  MKBUILTIN_TYPE ("i128", builtins, i128);
+  MKBUILTIN_TYPE ("bool", builtins, rbool);
+  MKBUILTIN_TYPE ("f32", builtins, f32);
+  MKBUILTIN_TYPE ("f64", builtins, f64);
+  MKBUILTIN_TYPE ("usize", builtins, usize);
+  MKBUILTIN_TYPE ("isize", builtins, isize);
+  MKBUILTIN_TYPE ("char", builtins, char_tyty);
+  MKBUILTIN_TYPE ("str", builtins, str);
+  MKBUILTIN_TYPE ("!", builtins, never);
+
+  // unit type ()
+  TyTy::TupleType *unit_tyty
+    = TyTy::TupleType::get_unit_type (mappings->get_next_hir_id ());
+  std::vector<std::unique_ptr<AST::Type> > elems;
+  AST::TupleType *unit_type
+    = new AST::TupleType (std::move (elems), Linemap::predeclared_location ());
+  builtins.push_back (unit_type);
+  tyctx->insert_builtin (unit_tyty->get_ref (), unit_type->get_node_id (),
+			 unit_tyty);
+  set_unit_type_node_id (unit_type->get_node_id ());
+}
+
+void
+Resolver::insert_resolved_name (NodeId refId, NodeId defId)
+{
+  resolved_names[refId] = defId;
+  get_name_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_name (NodeId refId, NodeId *defId)
+{
+  auto it = resolved_names.find (refId);
+  if (it == resolved_names.end ())
+    return false;
+
+  *defId = it->second;
+  return true;
+}
+
+void
+Resolver::insert_resolved_type (NodeId refId, NodeId defId)
+{
+  // auto it = resolved_types.find (refId);
+  // rust_assert (it == resolved_types.end ());
+
+  resolved_types[refId] = defId;
+  get_type_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_type (NodeId refId, NodeId *defId)
+{
+  auto it = resolved_types.find (refId);
+  if (it == resolved_types.end ())
+    return false;
+
+  *defId = it->second;
+  return true;
+}
+
+void
+Resolver::insert_resolved_label (NodeId refId, NodeId defId)
+{
+  auto it = resolved_labels.find (refId);
+  rust_assert (it == resolved_labels.end ());
+
+  resolved_labels[refId] = defId;
+  get_label_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_label (NodeId refId, NodeId *defId)
+{
+  auto it = resolved_labels.find (refId);
+  if (it == resolved_labels.end ())
+    return false;
+
+  *defId = it->second;
+  return true;
+}
+
+void
+Resolver::insert_resolved_macro (NodeId refId, NodeId defId)
+{
+  auto it = resolved_macros.find (refId);
+  rust_assert (it == resolved_macros.end ());
+
+  resolved_labels[refId] = defId;
+  get_label_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId)
+{
+  auto it = resolved_macros.find (refId);
+  if (it == resolved_macros.end ())
+    return false;
+
+  *defId = it->second;
+  return true;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
new file mode 100644
index 00000000000..014628a87c9
--- /dev/null
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -0,0 +1,212 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_NAME_RESOLVER_H
+#define RUST_NAME_RESOLVER_H
+
+#include "rust-system.h"
+#include "rust-canonical-path.h"
+#include "rust-hir-map.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+class Rib
+{
+public:
+  // Rust uses local_def_ids assigned by def_collector on the AST
+  // lets use NodeId instead
+  Rib (CrateNum crateNum, NodeId node_id);
+
+  // this takes the relative paths of items within a compilation unit for lookup
+  void insert_name (
+    const CanonicalPath &path, NodeId id, Location locus, bool shadow,
+    std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb);
+
+  bool lookup_canonical_path (const NodeId &id, CanonicalPath *ident);
+  bool lookup_name (const CanonicalPath &ident, NodeId *id);
+  void clear_name (const CanonicalPath &ident, NodeId id);
+  void append_reference_for_def (NodeId def, NodeId ref);
+  bool have_references_for_node (NodeId def) const;
+  bool decl_was_declared_here (NodeId def) const;
+  void debug () const;
+  std::string debug_str () const;
+
+  CrateNum get_crate_num () const { return crate_num; }
+  NodeId get_node_id () const { return node_id; }
+  std::map<NodeId, Location> &get_declarations () { return decls_within_rib; }
+
+private:
+  CrateNum crate_num;
+  NodeId node_id;
+  std::map<CanonicalPath, NodeId> path_mappings;
+  std::map<NodeId, CanonicalPath> reverse_path_mappings;
+  std::map<NodeId, Location> decls_within_rib;
+  std::map<NodeId, std::set<NodeId>> references;
+  Analysis::Mappings *mappings;
+};
+
+class Scope
+{
+public:
+  Scope (CrateNum crate_num);
+
+  void
+  insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow,
+	  std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb);
+
+  void insert (const CanonicalPath &ident, NodeId id, Location locus);
+  bool lookup (const CanonicalPath &ident, NodeId *id);
+
+  void iterate (std::function<bool (Rib *)> cb);
+  void iterate (std::function<bool (const Rib *)> cb) const;
+
+  Rib *peek ();
+  void push (NodeId id);
+  Rib *pop ();
+
+  bool decl_was_declared_here (NodeId def) const;
+  void append_reference_for_def (NodeId refId, NodeId defId);
+
+  CrateNum get_crate_num () const { return crate_num; }
+
+private:
+  CrateNum crate_num;
+  std::vector<Rib *> stack;
+};
+
+class Resolver
+{
+public:
+  static Resolver *get ();
+  ~Resolver () {}
+
+  // these builtin types
+  void insert_builtin_types (Rib *r);
+
+  // these will be required for type resolution passes to
+  // map back to tyty nodes
+  std::vector<AST::Type *> &get_builtin_types ();
+
+  void push_new_name_rib (Rib *r);
+  void push_new_type_rib (Rib *r);
+  void push_new_label_rib (Rib *r);
+  void push_new_macro_rib (Rib *r);
+
+  bool find_name_rib (NodeId id, Rib **rib);
+  bool find_type_rib (NodeId id, Rib **rib);
+  bool find_label_rib (NodeId id, Rib **rib);
+  bool find_macro_rib (NodeId id, Rib **rib);
+
+  void insert_resolved_name (NodeId refId, NodeId defId);
+  bool lookup_resolved_name (NodeId refId, NodeId *defId);
+
+  void insert_resolved_type (NodeId refId, NodeId defId);
+  bool lookup_resolved_type (NodeId refId, NodeId *defId);
+
+  void insert_resolved_label (NodeId refId, NodeId defId);
+  bool lookup_resolved_label (NodeId refId, NodeId *defId);
+
+  void insert_resolved_macro (NodeId refId, NodeId defId);
+  bool lookup_resolved_macro (NodeId refId, NodeId *defId);
+
+  // proxy for scoping
+  Scope &get_name_scope () { return name_scope; }
+  Scope &get_type_scope () { return type_scope; }
+  Scope &get_label_scope () { return label_scope; }
+  Scope &get_macro_scope () { return macro_scope; }
+
+  NodeId get_global_type_node_id () { return global_type_node_id; }
+  void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; }
+  NodeId get_unit_type_node_id () { return unit_ty_node_id; }
+
+  void push_new_module_scope (NodeId module_id)
+  {
+    current_module_stack.push_back (module_id);
+  }
+
+  void pop_module_scope ()
+  {
+    rust_assert (!current_module_stack.empty ());
+    current_module_stack.pop_back ();
+  }
+
+  NodeId peek_current_module_scope () const
+  {
+    rust_assert (!current_module_stack.empty ());
+    return current_module_stack.back ();
+  }
+
+  NodeId peek_crate_module_scope () const
+  {
+    rust_assert (!current_module_stack.empty ());
+    return current_module_stack.front ();
+  }
+
+  NodeId peek_parent_module_scope () const
+  {
+    rust_assert (current_module_stack.size () > 1);
+    return current_module_stack.at (current_module_stack.size () - 2);
+  }
+
+private:
+  Resolver ();
+
+  void generate_builtins ();
+
+  Analysis::Mappings *mappings;
+  TypeCheckContext *tyctx;
+
+  std::vector<AST::Type *> builtins;
+
+  Scope name_scope;
+  Scope type_scope;
+  Scope label_scope;
+  Scope macro_scope;
+
+  NodeId global_type_node_id;
+  NodeId unit_ty_node_id;
+
+  // map a AST Node to a Rib
+  std::map<NodeId, Rib *> name_ribs;
+  std::map<NodeId, Rib *> type_ribs;
+  std::map<NodeId, Rib *> label_ribs;
+  std::map<NodeId, Rib *> macro_ribs;
+
+  // Rust uses DefIds to namespace these under a crate_num
+  // but then it uses the def_collector to assign local_defids
+  // to each ast node as well. not sure if this is going to fit
+  // with gcc very well to compile a full crate in one go but we will
+  // see.
+
+  // these are of the form ref->Def-NodeId
+  // we need two namespaces one for names and ones for types
+  std::map<NodeId, NodeId> resolved_names;
+  std::map<NodeId, NodeId> resolved_types;
+  std::map<NodeId, NodeId> resolved_labels;
+  std::map<NodeId, NodeId> resolved_macros;
+
+  // keep track of the current module scope ids
+  std::vector<NodeId> current_module_stack;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_NAME_RESOLVER_H
