diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index f73ada4c8ac..7dad27a5dcd 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -116,7 +116,6 @@ GRS_OBJS = \
     rust/rust-tyty-bounds.o \
     rust/rust-hir-type-check-util.o \
     rust/rust-hir-trait-resolve.o \
-    rust/rust-hir-type-check-toplevel.o \
     rust/rust-hir-type-check-item.o \
     rust/rust-hir-type-check-type.o \
     rust/rust-hir-type-check-struct.o \
@@ -126,6 +125,7 @@ GRS_OBJS = \
     rust/rust-hir-type-check-enumitem.o \
     rust/rust-hir-type-check-implitem.o \
     rust/rust-hir-dot-operator.o \
+    rust/rust-hir-path-probe.o \
     rust/rust-coercion.o \
     rust/rust-casts.o \
     rust/rust-hir-type-check-base.o \
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 985e61b83f0..ed2df11da45 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -25,8 +25,7 @@ namespace Resolver {
 
 MethodResolver::MethodResolver (bool autoderef_flag,
 				const HIR::PathIdentSegment &segment_name)
-  : AutoderefCycle (autoderef_flag), mappings (Analysis::Mappings::get ()),
-    context (TypeCheckContext::get ()), segment_name (segment_name),
+  : AutoderefCycle (autoderef_flag), segment_name (segment_name),
     try_result (MethodCandidate::get_error ())
 {}
 
@@ -80,8 +79,9 @@ MethodResolver::select (const TyTy::BaseType &receiver)
 	return true;
 
       TyTy::BaseType *ty = nullptr;
-      if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+      if (!query_type (func->get_mappings ().get_hirid (), &ty))
 	return true;
+      rust_assert (ty != nullptr);
       if (ty->get_kind () == TyTy::TypeKind::ERROR)
 	return true;
 
@@ -127,7 +127,7 @@ MethodResolver::select (const TyTy::BaseType &receiver)
 	  continue;
 
 	TyTy::BaseType *ty = nullptr;
-	if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+	if (!query_type (func->get_mappings ().get_hirid (), &ty))
 	  continue;
 	if (ty->get_kind () == TyTy::TypeKind::ERROR)
 	  continue;
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
index 8bb49f6da74..8341173a061 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.h
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -37,7 +37,7 @@ struct MethodCandidate
   bool is_error () const { return candidate.is_error (); }
 };
 
-class MethodResolver : protected AutoderefCycle
+class MethodResolver : private TypeCheckBase, protected AutoderefCycle
 {
 public:
   struct predicate_candidate
@@ -63,10 +63,6 @@ protected:
   bool select (const TyTy::BaseType &receiver) override;
 
 private:
-  // context info
-  Analysis::Mappings *mappings;
-  TypeCheckContext *context;
-
   // search
   const HIR::PathIdentSegment &segment_name;
   std::vector<MethodResolver::predicate_candidate> predicate_items;
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.cc b/gcc/rust/typecheck/rust-hir-path-probe.cc
new file mode 100644
index 00000000000..cb3270d3623
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-path-probe.cc
@@ -0,0 +1,46 @@
+// 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-hir-path-probe.h"
+#include "rust-hir-type-check-item.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item,
+					    HIR::ImplBlock *impl)
+{
+  current_impl = impl;
+  HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid ();
+  TyTy::BaseType *impl_block_ty = nullptr;
+  if (!query_type (impl_ty_id, &impl_block_ty))
+    return;
+
+  if (!receiver->can_eq (impl_block_ty, false))
+    {
+      if (!impl_block_ty->can_eq (receiver, false))
+	return;
+    }
+
+  // lets visit the impl_item
+  item->accept_vis (*this);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h
index 5e85f4e2a16..c957487dd2a 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe.h
+++ b/gcc/rust/typecheck/rust-hir-path-probe.h
@@ -195,7 +195,7 @@ public:
       {
 	HirId tyid = alias.get_mappings ().get_hirid ();
 	TyTy::BaseType *ty = nullptr;
-	bool ok = context->lookup_type (tyid, &ty);
+	bool ok = query_type (tyid, &ty);
 	rust_assert (ok);
 
 	PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias,
@@ -214,7 +214,7 @@ public:
       {
 	HirId tyid = constant.get_mappings ().get_hirid ();
 	TyTy::BaseType *ty = nullptr;
-	bool ok = context->lookup_type (tyid, &ty);
+	bool ok = query_type (tyid, &ty);
 	rust_assert (ok);
 
 	PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant,
@@ -233,7 +233,7 @@ public:
       {
 	HirId tyid = function.get_mappings ().get_hirid ();
 	TyTy::BaseType *ty = nullptr;
-	bool ok = context->lookup_type (tyid, &ty);
+	bool ok = query_type (tyid, &ty);
 	rust_assert (ok);
 
 	PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function,
@@ -272,23 +272,7 @@ protected:
   }
 
   void process_impl_item_candidate (HirId id, HIR::ImplItem *item,
-				    HIR::ImplBlock *impl)
-  {
-    current_impl = impl;
-    HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid ();
-    TyTy::BaseType *impl_block_ty = nullptr;
-    if (!context->lookup_type (impl_ty_id, &impl_block_ty))
-      return;
-
-    if (!receiver->can_eq (impl_block_ty, false))
-      {
-	if (!impl_block_ty->can_eq (receiver, false))
-	  return;
-      }
-
-    // lets visit the impl_item
-    item->accept_vis (*this);
-  }
+				    HIR::ImplBlock *impl);
 
   void
   process_associated_trait_for_candidates (const TraitReference *trait_ref,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index d5121e7a7bc..cf496d3eb19 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -17,8 +17,10 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-hir-type-check-base.h"
+#include "rust-hir-type-check-item.h"
 #include "rust-hir-type-check-type.h"
 #include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-implitem.h"
 #include "rust-coercion.h"
 #include "rust-casts.h"
 
@@ -37,6 +39,13 @@ TypeCheckBase::check_for_unconstrained (
   const TyTy::SubstitutionArgumentMappings &constraint_b,
   const TyTy::BaseType *reference)
 {
+  bool check_result = false;
+  bool check_completed
+    = context->have_checked_for_unconstrained (reference->get_ref (),
+					       &check_result);
+  if (check_completed)
+    return check_result;
+
   std::set<HirId> symbols_to_constrain;
   std::map<HirId, Location> symbol_to_location;
   for (const auto &p : params_to_constrain)
@@ -86,6 +95,10 @@ TypeCheckBase::check_for_unconstrained (
 	  unconstrained = true;
 	}
     }
+
+  context->insert_unconstrained_check_marker (reference->get_ref (),
+					      unconstrained);
+
   return unconstrained;
 }
 
@@ -479,5 +492,68 @@ TypeCheckBase::resolve_generic_params (
     }
 }
 
+bool
+TypeCheckBase::query_type (HirId reference, TyTy::BaseType **result)
+{
+  if (context->lookup_type (reference, result))
+    return true;
+
+  HIR::Item *item = mappings->lookup_hir_item (reference);
+  if (item != nullptr)
+    {
+      rust_debug_loc (item->get_locus (), "resolved item {%u} to", reference);
+      *result = TypeCheckItem::Resolve (*item);
+      return true;
+    }
+
+  HirId parent_impl_id = UNKNOWN_HIRID;
+  HIR::ImplItem *impl_item
+    = mappings->lookup_hir_implitem (reference, &parent_impl_id);
+  if (impl_item != nullptr)
+    {
+      HIR::ImplBlock *impl_block
+	= mappings->lookup_hir_impl_block (parent_impl_id);
+      rust_assert (impl_block != nullptr);
+
+      // found an impl item
+      rust_debug_loc (impl_item->get_locus (), "resolved impl-item {%u} to",
+		      reference);
+
+      *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item);
+      return true;
+    }
+
+  // is it an impl_type?
+  HIR::ImplBlock *impl_block_by_type = nullptr;
+  bool found_impl_block_type
+    = mappings->lookup_impl_block_type (reference, &impl_block_by_type);
+  if (found_impl_block_type)
+    {
+      *result = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type);
+      return true;
+    }
+
+  // is it an extern item?
+  HirId parent_extern_block_id = UNKNOWN_HIRID;
+  HIR::ExternalItem *extern_item
+    = mappings->lookup_hir_extern_item (reference, &parent_extern_block_id);
+  if (extern_item != nullptr)
+    {
+      HIR::ExternBlock *block
+	= mappings->lookup_hir_extern_block (parent_extern_block_id);
+      rust_assert (block != nullptr);
+
+      *result = TypeCheckTopLevelExternItem::Resolve (extern_item, *block);
+      return true;
+    }
+
+  // more?
+  Location possible_locus = mappings->lookup_location (reference);
+  rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
+		  reference);
+
+  return false;
+}
+
 } // namespace Resolver
 } // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h
index b8ff2cf6dc9..335014339f3 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -69,6 +69,8 @@ protected:
     const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
     std::vector<TyTy::SubstitutionParamMapping> &substitutions);
 
+  bool query_type (HirId reference, TyTy::BaseType **result);
+
   Analysis::Mappings *mappings;
   Resolver *resolver;
   TypeCheckContext *context;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index bea5eb8cb0b..2f22c82f063 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -188,6 +188,9 @@ TypeCheckExpr::visit (HIR::CallExpr &expr)
       return;
     }
 
+  rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}",
+		  function_tyty->get_name ().c_str ());
+
   TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
   if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
     {
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index f1f56d28ae2..e29b8d776b2 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -32,12 +32,21 @@ TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem (
   : TypeCheckBase (), parent (parent)
 {}
 
-void
+TyTy::BaseType *
 TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item,
 				      const HIR::ExternBlock &parent)
 {
+  // is it already resolved?
+  auto context = TypeCheckContext::get ();
+  TyTy::BaseType *resolved = nullptr;
+  bool already_resolved
+    = context->lookup_type (item->get_mappings ().get_hirid (), &resolved);
+  if (already_resolved)
+    return resolved;
+
   TypeCheckTopLevelExternItem resolver (parent);
   item->accept_vis (resolver);
+  return resolver.resolved;
 }
 
 void
@@ -47,6 +56,7 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item)
     = TypeCheckType::Resolve (item.get_item_type ().get ());
 
   context->insert_type (item.get_mappings (), actual_type);
+  resolved = actual_type;
 }
 
 void
@@ -142,79 +152,40 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function)
 				  ret_type, std::move (substitutions));
 
   context->insert_type (function.get_mappings (), fnType);
+  resolved = fnType;
 }
 
-TypeCheckTopLevelImplItem::TypeCheckTopLevelImplItem (
-  TyTy::BaseType *self,
+TypeCheckImplItem::TypeCheckImplItem (
+  HIR::ImplBlock *parent, TyTy::BaseType *self,
   std::vector<TyTy::SubstitutionParamMapping> substitutions)
-  : TypeCheckBase (), self (self), substitutions (substitutions)
+  : TypeCheckBase (), parent (parent), self (self),
+    substitutions (substitutions)
 {}
 
-void
-TypeCheckTopLevelImplItem::Resolve (
-  HIR::ImplItem *item, TyTy::BaseType *self,
+TyTy::BaseType *
+TypeCheckImplItem::Resolve (
+  HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
   std::vector<TyTy::SubstitutionParamMapping> substitutions)
 {
-  TypeCheckTopLevelImplItem resolver (self, substitutions);
+  // is it already resolved?
+  auto context = TypeCheckContext::get ();
+  TyTy::BaseType *resolved = nullptr;
+  bool already_resolved
+    = context->lookup_type (item->get_impl_mappings ().get_hirid (), &resolved);
+  if (already_resolved)
+    return resolved;
+
+  // resolve
+  TypeCheckImplItem resolver (parent, self, substitutions);
   item->accept_vis (resolver);
+  return resolver.result;
 }
 
 void
-TypeCheckTopLevelImplItem::visit (HIR::TypeAlias &alias)
-{
-  TyTy::BaseType *actual_type
-    = TypeCheckType::Resolve (alias.get_type_aliased ().get ());
-
-  context->insert_type (alias.get_mappings (), actual_type);
-
-  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
-    }
-}
-
-void
-TypeCheckTopLevelImplItem::visit (HIR::ConstantItem &constant)
-{
-  TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
-  TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
-
-  TyTy::BaseType *unified = unify_site (
-    constant.get_mappings ().get_hirid (),
-    TyTy::TyWithLocation (type, constant.get_type ()->get_locus ()),
-    TyTy::TyWithLocation (expr_type, constant.get_expr ()->get_locus ()),
-    constant.get_locus ());
-  context->insert_type (constant.get_mappings (), unified);
-}
-
-void
-TypeCheckTopLevelImplItem::visit (HIR::Function &function)
+TypeCheckImplItem::visit (HIR::Function &function)
 {
   if (function.has_generics ())
-    {
-      for (auto &generic_param : function.get_generic_params ())
-	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		auto param_type
-		  = TypeResolveGenericParam::Resolve (generic_param.get ());
-		context->insert_type (generic_param->get_mappings (),
-				      param_type);
-
-		substitutions.push_back (TyTy::SubstitutionParamMapping (
-		  static_cast<HIR::TypeParam &> (*generic_param), param_type));
-	      }
-	      break;
-	    }
-	}
-    }
+    resolve_generic_params (function.get_generic_params (), substitutions);
 
   for (auto &where_clause_item : function.get_where_clause ().get_items ())
     {
@@ -328,41 +299,10 @@ TypeCheckTopLevelImplItem::visit (HIR::Function &function)
 				  std::move (substitutions));
 
   context->insert_type (function.get_mappings (), fnType);
-}
-
-TypeCheckImplItem::TypeCheckImplItem (HIR::ImplBlock *parent,
-				      TyTy::BaseType *self)
-  : TypeCheckBase (), parent (parent), self (self)
-{}
-
-void
-TypeCheckImplItem::Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
-			    TyTy::BaseType *self)
-{
-  TypeCheckImplItem resolver (parent, self);
-  item->accept_vis (resolver);
-}
-
-void
-TypeCheckImplItem::visit (HIR::Function &function)
-{
-  TyTy::BaseType *lookup;
-  if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
-    {
-      rust_error_at (function.get_locus (), "failed to lookup function type");
-      return;
-    }
-
-  if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
-    {
-      rust_error_at (function.get_locus (),
-		     "found invalid type for function [%s]",
-		     lookup->as_string ().c_str ());
-      return;
-    }
+  result = fnType;
 
   // need to get the return type from this
-  TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup);
+  TyTy::FnType *resolve_fn_type = fnType;
   auto expected_ret_tyty = resolve_fn_type->get_return_type ();
   context->push_return_type (TypeCheckContextItem (parent, &function),
 			     expected_ret_tyty);
@@ -383,20 +323,41 @@ TypeCheckImplItem::visit (HIR::Function &function)
 }
 
 void
-TypeCheckImplItem::visit (HIR::ConstantItem &const_item)
-{}
+TypeCheckImplItem::visit (HIR::ConstantItem &constant)
+{
+  TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
+  TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
+
+  TyTy::BaseType *unified = unify_site (
+    constant.get_mappings ().get_hirid (),
+    TyTy::TyWithLocation (type, constant.get_type ()->get_locus ()),
+    TyTy::TyWithLocation (expr_type, constant.get_expr ()->get_locus ()),
+    constant.get_locus ());
+  context->insert_type (constant.get_mappings (), unified);
+  result = unified;
+}
 
 void
-TypeCheckImplItem::visit (HIR::TypeAlias &type_alias)
-{}
+TypeCheckImplItem::visit (HIR::TypeAlias &alias)
+{
+  TyTy::BaseType *actual_type
+    = TypeCheckType::Resolve (alias.get_type_aliased ().get ());
+
+  context->insert_type (alias.get_mappings (), actual_type);
+  result = actual_type;
+  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+    }
+}
 
 TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
   HIR::ImplBlock *parent, TyTy::BaseType *self,
   TyTy::TypeBoundPredicate &trait_reference,
   std::vector<TyTy::SubstitutionParamMapping> substitutions)
-  : TypeCheckImplItem (parent, self), trait_reference (trait_reference),
+  : TypeCheckBase (), trait_reference (trait_reference),
     resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()),
-    substitutions (substitutions)
+    parent (parent), self (self), substitutions (substitutions)
 {
   rust_assert (is_trait_impl_block ());
 }
@@ -417,10 +378,8 @@ void
 TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant)
 {
   // normal resolution of the item
-  TypeCheckImplItem::visit (constant);
-  TyTy::BaseType *lookup;
-  if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
-    return;
+  TyTy::BaseType *lookup
+    = TypeCheckImplItem::Resolve (parent, &constant, self, substitutions);
 
   // map the impl item to the associated trait item
   const auto tref = trait_reference.get ();
@@ -468,10 +427,8 @@ void
 TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
 {
   // normal resolution of the item
-  TypeCheckImplItem::visit (type);
-  TyTy::BaseType *lookup;
-  if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
-    return;
+  TyTy::BaseType *lookup
+    = TypeCheckImplItem::Resolve (parent, &type, self, substitutions);
 
   // map the impl item to the associated trait item
   const auto tref = trait_reference.get ();
@@ -528,11 +485,9 @@ TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
 void
 TypeCheckImplItemWithTrait::visit (HIR::Function &function)
 {
-  // we get the error checking from the base method here
-  TypeCheckImplItem::visit (function);
-  TyTy::BaseType *lookup;
-  if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
-    return;
+  // normal resolution of the item
+  TyTy::BaseType *lookup
+    = TypeCheckImplItem::Resolve (parent, &function, self, substitutions);
 
   // map the impl item to the associated trait item
   const auto tref = trait_reference.get ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index 768588d2671..0e5f16d6762 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -28,7 +28,8 @@ class TypeCheckTopLevelExternItem : public TypeCheckBase,
 				    public HIR::HIRExternalItemVisitor
 {
 public:
-  static void Resolve (HIR::ExternalItem *item, const HIR::ExternBlock &parent);
+  static TyTy::BaseType *Resolve (HIR::ExternalItem *item,
+				  const HIR::ExternBlock &parent);
 
   void visit (HIR::ExternalStaticItem &item) override;
   void visit (HIR::ExternalFunctionItem &function) override;
@@ -37,47 +38,33 @@ private:
   TypeCheckTopLevelExternItem (const HIR::ExternBlock &parent);
 
   const HIR::ExternBlock &parent;
-};
-
-class TypeCheckTopLevelImplItem : public TypeCheckBase,
-				  public HIR::HIRImplVisitor
-{
-public:
-  static void
-  Resolve (HIR::ImplItem *item, TyTy::BaseType *self,
-	   std::vector<TyTy::SubstitutionParamMapping> substitutions);
-
-  void visit (HIR::TypeAlias &alias) override;
-  void visit (HIR::ConstantItem &constant) override;
-  void visit (HIR::Function &function) override;
-
-private:
-  TypeCheckTopLevelImplItem (
-    TyTy::BaseType *self,
-    std::vector<TyTy::SubstitutionParamMapping> substitutions);
-
-  TyTy::BaseType *self;
-  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+  TyTy::BaseType *resolved;
 };
 
 class TypeCheckImplItem : public TypeCheckBase, public HIR::HIRImplVisitor
 {
 public:
-  static void Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
-		       TyTy::BaseType *self);
+  static TyTy::BaseType *
+  Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
+	   std::vector<TyTy::SubstitutionParamMapping> substitutions);
 
   void visit (HIR::Function &function) override;
   void visit (HIR::ConstantItem &const_item) override;
   void visit (HIR::TypeAlias &type_alias) override;
 
 protected:
-  TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self);
+  TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self,
+		     std::vector<TyTy::SubstitutionParamMapping> substitutions);
 
   HIR::ImplBlock *parent;
   TyTy::BaseType *self;
+  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+
+  TyTy::BaseType *result;
 };
 
-class TypeCheckImplItemWithTrait : public TypeCheckImplItem
+class TypeCheckImplItemWithTrait : public TypeCheckBase,
+				   public HIR::HIRImplVisitor
 {
 public:
   static TyTy::TypeBoundPredicateItem
@@ -105,6 +92,9 @@ private:
 
   TyTy::TypeBoundPredicate &trait_reference;
   TyTy::TypeBoundPredicateItem resolved_trait_item;
+
+  HIR::ImplBlock *parent;
+  TyTy::BaseType *self;
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
 };
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 0aa26072efc..e39dd537d6e 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -16,59 +16,466 @@
 // along with GCC; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-#include "rust-hir-type-check-item.h"
 #include "rust-hir-full.h"
+#include "rust-hir-type-check-item.h"
+#include "rust-hir-type-check-enumitem.h"
 #include "rust-hir-type-check-implitem.h"
 #include "rust-hir-type-check-type.h"
 #include "rust-hir-type-check-stmt.h"
 #include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-pattern.h"
 #include "rust-hir-trait-resolve.h"
 
 namespace Rust {
 namespace Resolver {
 
-TypeCheckItem::TypeCheckItem () : TypeCheckBase () {}
+TypeCheckItem::TypeCheckItem () : TypeCheckBase (), infered (nullptr) {}
 
-void
+TyTy::BaseType *
 TypeCheckItem::Resolve (HIR::Item &item)
 {
+  // is it already resolved?
+  auto context = TypeCheckContext::get ();
+  TyTy::BaseType *resolved = nullptr;
+  bool already_resolved
+    = context->lookup_type (item.get_mappings ().get_hirid (), &resolved);
+  if (already_resolved)
+    return resolved;
+
   rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM);
   HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item);
 
   TypeCheckItem resolver;
   vis_item.accept_vis (resolver);
+  return resolver.infered;
+}
+
+TyTy::BaseType *
+TypeCheckItem::ResolveImplItem (HIR::ImplBlock &impl_block, HIR::ImplItem &item)
+{
+  TypeCheckItem resolver;
+  return resolver.resolve_impl_item (impl_block, item);
+}
+
+TyTy::BaseType *
+TypeCheckItem::ResolveImplBlockSelf (HIR::ImplBlock &impl_block)
+{
+  TypeCheckItem resolver;
+
+  bool failed_flag = false;
+  std::vector<TyTy::SubstitutionParamMapping> substitutions
+    = resolver.resolve_impl_block_substitutions (impl_block, failed_flag);
+  if (failed_flag)
+    {
+      return new TyTy::ErrorType (impl_block.get_mappings ().get_hirid ());
+    }
+
+  return resolver.resolve_impl_block_self (impl_block);
+}
+
+void
+TypeCheckItem::visit (HIR::TypeAlias &alias)
+{
+  TyTy::BaseType *actual_type
+    = TypeCheckType::Resolve (alias.get_type_aliased ().get ());
+
+  context->insert_type (alias.get_mappings (), actual_type);
+
+  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+    }
+  infered = actual_type;
+}
+
+void
+TypeCheckItem::visit (HIR::TupleStruct &struct_decl)
+{
+  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+  if (struct_decl.has_generics ())
+    resolve_generic_params (struct_decl.get_generic_params (), substitutions);
+
+  for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+    }
+
+  std::vector<TyTy::StructFieldType *> fields;
+  size_t idx = 0;
+  for (auto &field : struct_decl.get_fields ())
+    {
+      TyTy::BaseType *field_type
+	= TypeCheckType::Resolve (field.get_field_type ().get ());
+      TyTy::StructFieldType *ty_field
+	= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+				     std::to_string (idx), field_type,
+				     field.get_locus ());
+      fields.push_back (ty_field);
+      context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+      idx++;
+    }
+
+  // get the path
+  const CanonicalPath *canonical_path = nullptr;
+  bool ok = mappings->lookup_canonical_path (
+    struct_decl.get_mappings ().get_nodeid (), &canonical_path);
+  rust_assert (ok);
+  RustIdent ident{*canonical_path, struct_decl.get_locus ()};
+
+  // its a single variant ADT
+  std::vector<TyTy::VariantDef *> variants;
+  variants.push_back (new TyTy::VariantDef (
+    struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+    ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
+
+  // Process #[repr(X)] attribute, if any
+  const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
+  TyTy::ADTType::ReprOptions repr
+    = parse_repr_options (attrs, struct_decl.get_locus ());
+
+  TyTy::BaseType *type
+    = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
+			 mappings->get_next_hir_id (),
+			 struct_decl.get_identifier (), ident,
+			 TyTy::ADTType::ADTKind::TUPLE_STRUCT,
+			 std::move (variants), std::move (substitutions), repr);
+
+  context->insert_type (struct_decl.get_mappings (), type);
+  infered = type;
+}
+
+void
+TypeCheckItem::visit (HIR::StructStruct &struct_decl)
+{
+  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+  if (struct_decl.has_generics ())
+    resolve_generic_params (struct_decl.get_generic_params (), substitutions);
+
+  for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+    }
+
+  std::vector<TyTy::StructFieldType *> fields;
+  for (auto &field : struct_decl.get_fields ())
+    {
+      TyTy::BaseType *field_type
+	= TypeCheckType::Resolve (field.get_field_type ().get ());
+      TyTy::StructFieldType *ty_field
+	= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+				     field.get_field_name (), field_type,
+				     field.get_locus ());
+      fields.push_back (ty_field);
+      context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+    }
+
+  // get the path
+  const CanonicalPath *canonical_path = nullptr;
+  bool ok = mappings->lookup_canonical_path (
+    struct_decl.get_mappings ().get_nodeid (), &canonical_path);
+  rust_assert (ok);
+  RustIdent ident{*canonical_path, struct_decl.get_locus ()};
+
+  // its a single variant ADT
+  std::vector<TyTy::VariantDef *> variants;
+  variants.push_back (new TyTy::VariantDef (
+    struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+    ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
+
+  // Process #[repr(X)] attribute, if any
+  const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
+  TyTy::ADTType::ReprOptions repr
+    = parse_repr_options (attrs, struct_decl.get_locus ());
+
+  TyTy::BaseType *type
+    = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
+			 mappings->get_next_hir_id (),
+			 struct_decl.get_identifier (), ident,
+			 TyTy::ADTType::ADTKind::STRUCT_STRUCT,
+			 std::move (variants), std::move (substitutions), repr);
+
+  context->insert_type (struct_decl.get_mappings (), type);
+  infered = type;
+}
+
+void
+TypeCheckItem::visit (HIR::Enum &enum_decl)
+{
+  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+  if (enum_decl.has_generics ())
+    resolve_generic_params (enum_decl.get_generic_params (), substitutions);
+
+  std::vector<TyTy::VariantDef *> variants;
+  int64_t discriminant_value = 0;
+  for (auto &variant : enum_decl.get_variants ())
+    {
+      TyTy::VariantDef *field_type
+	= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
+
+      discriminant_value++;
+      variants.push_back (field_type);
+    }
+
+  // get the path
+  const CanonicalPath *canonical_path = nullptr;
+  bool ok
+    = mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
+				       &canonical_path);
+  rust_assert (ok);
+  RustIdent ident{*canonical_path, enum_decl.get_locus ()};
+
+  // multi variant ADT
+  TyTy::BaseType *type
+    = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
+			 mappings->get_next_hir_id (),
+			 enum_decl.get_identifier (), ident,
+			 TyTy::ADTType::ADTKind::ENUM, std::move (variants),
+			 std::move (substitutions));
+
+  context->insert_type (enum_decl.get_mappings (), type);
+  infered = type;
+}
+
+void
+TypeCheckItem::visit (HIR::Union &union_decl)
+{
+  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+  if (union_decl.has_generics ())
+    resolve_generic_params (union_decl.get_generic_params (), substitutions);
+
+  for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+    }
+
+  std::vector<TyTy::StructFieldType *> fields;
+  for (auto &variant : union_decl.get_variants ())
+    {
+      TyTy::BaseType *variant_type
+	= TypeCheckType::Resolve (variant.get_field_type ().get ());
+      TyTy::StructFieldType *ty_variant
+	= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+				     variant.get_field_name (), variant_type,
+				     variant.get_locus ());
+      fields.push_back (ty_variant);
+      context->insert_type (variant.get_mappings (),
+			    ty_variant->get_field_type ());
+    }
+
+  // get the path
+  const CanonicalPath *canonical_path = nullptr;
+  bool ok
+    = mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
+				       &canonical_path);
+  rust_assert (ok);
+  RustIdent ident{*canonical_path, union_decl.get_locus ()};
+
+  // there is only a single variant
+  std::vector<TyTy::VariantDef *> variants;
+  variants.push_back (new TyTy::VariantDef (
+    union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
+    ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
+
+  TyTy::BaseType *type
+    = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+			 mappings->get_next_hir_id (),
+			 union_decl.get_identifier (), ident,
+			 TyTy::ADTType::ADTKind::UNION, std::move (variants),
+			 std::move (substitutions));
+
+  context->insert_type (union_decl.get_mappings (), type);
+  infered = type;
+}
+
+void
+TypeCheckItem::visit (HIR::StaticItem &var)
+{
+  TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
+  TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ());
+
+  TyTy::BaseType *unified
+    = coercion_site (var.get_mappings ().get_hirid (),
+		     TyTy::TyWithLocation (type, var.get_type ()->get_locus ()),
+		     TyTy::TyWithLocation (expr_type,
+					   var.get_expr ()->get_locus ()),
+		     var.get_locus ());
+  context->insert_type (var.get_mappings (), unified);
+  infered = unified;
+}
+
+void
+TypeCheckItem::visit (HIR::ConstantItem &constant)
+{
+  TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
+  TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
+
+  TyTy::BaseType *unified = unify_site (
+    constant.get_mappings ().get_hirid (),
+    TyTy::TyWithLocation (type, constant.get_type ()->get_locus ()),
+    TyTy::TyWithLocation (expr_type, constant.get_expr ()->get_locus ()),
+    constant.get_locus ());
+  context->insert_type (constant.get_mappings (), unified);
+  infered = unified;
 }
 
 void
 TypeCheckItem::visit (HIR::ImplBlock &impl_block)
+{
+  bool failed_flag = false;
+  std::vector<TyTy::SubstitutionParamMapping> substitutions
+    = resolve_impl_block_substitutions (impl_block, failed_flag);
+  if (failed_flag)
+    {
+      infered = new TyTy::ErrorType (impl_block.get_mappings ().get_hirid ());
+      return;
+    }
+
+  TyTy::BaseType *self = resolve_impl_block_self (impl_block);
+
+  // resolve each impl_item
+  for (auto &impl_item : impl_block.get_impl_items ())
+    {
+      TypeCheckImplItem::Resolve (&impl_block, impl_item.get (), self,
+				  substitutions);
+    }
+
+  // validate the impl items
+  validate_trait_impl_block (impl_block, self, substitutions);
+}
+
+TyTy::BaseType *
+TypeCheckItem::resolve_impl_item (HIR::ImplBlock &impl_block,
+				  HIR::ImplItem &item)
+{
+  bool failed_flag = false;
+  std::vector<TyTy::SubstitutionParamMapping> substitutions
+    = resolve_impl_block_substitutions (impl_block, failed_flag);
+  if (failed_flag)
+    {
+      return new TyTy::ErrorType (impl_block.get_mappings ().get_hirid ());
+    }
+
+  TyTy::BaseType *self = resolve_impl_block_self (impl_block);
+
+  return TypeCheckImplItem::Resolve (&impl_block, &item, self, substitutions);
+}
+
+void
+TypeCheckItem::visit (HIR::Function &function)
 {
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
-  if (impl_block.has_generics ())
+  if (function.has_generics ())
+    resolve_generic_params (function.get_generic_params (), substitutions);
+
+  for (auto &where_clause_item : function.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+    }
+
+  TyTy::BaseType *ret_type = nullptr;
+  if (!function.has_function_return_type ())
+    ret_type
+      = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
+  else
     {
-      for (auto &generic_param : impl_block.get_generic_params ())
+      auto resolved
+	= TypeCheckType::Resolve (function.get_return_type ().get ());
+      if (resolved->get_kind () == TyTy::TypeKind::ERROR)
 	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		TyTy::BaseType *l = nullptr;
-		bool ok = context->lookup_type (
-		  generic_param->get_mappings ().get_hirid (), &l);
-		if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
-		  {
-		    substitutions.push_back (TyTy::SubstitutionParamMapping (
-		      static_cast<HIR::TypeParam &> (*generic_param),
-		      static_cast<TyTy::ParamType *> (l)));
-		  }
-	      }
-	      break;
-	    }
+	  rust_error_at (function.get_locus (),
+			 "failed to resolve return type");
+	  return;
 	}
+
+      ret_type = resolved->clone ();
+      ret_type->set_ref (
+	function.get_return_type ()->get_mappings ().get_hirid ());
+    }
+
+  std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *>> params;
+  for (auto &param : function.get_function_params ())
+    {
+      // get the name as well required for later on
+      auto param_tyty = TypeCheckType::Resolve (param.get_type ());
+      params.push_back (
+	std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
+						     param_tyty));
+
+      context->insert_type (param.get_mappings (), param_tyty);
+      TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
+    }
+
+  const CanonicalPath *canonical_path = nullptr;
+  bool ok
+    = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
+				       &canonical_path);
+  rust_assert (ok);
+
+  RustIdent ident{*canonical_path, function.get_locus ()};
+  auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
+				  function.get_mappings ().get_defid (),
+				  function.get_function_name (), ident,
+				  TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
+				  std::move (params), ret_type,
+				  std::move (substitutions));
+
+  context->insert_type (function.get_mappings (), fnType);
+
+  // need to get the return type from this
+  TyTy::FnType *resolved_fn_type = fnType;
+  auto expected_ret_tyty = resolved_fn_type->get_return_type ();
+  context->push_return_type (TypeCheckContextItem (&function),
+			     expected_ret_tyty);
+
+  auto block_expr_ty
+    = TypeCheckExpr::Resolve (function.get_definition ().get ());
+
+  Location fn_return_locus = function.has_function_return_type ()
+			       ? function.get_return_type ()->get_locus ()
+			       : function.get_locus ();
+  coercion_site (function.get_definition ()->get_mappings ().get_hirid (),
+		 TyTy::TyWithLocation (expected_ret_tyty, fn_return_locus),
+		 TyTy::TyWithLocation (block_expr_ty),
+		 function.get_definition ()->get_locus ());
+
+  context->pop_return_type ();
+
+  infered = fnType;
+}
+
+void
+TypeCheckItem::visit (HIR::Module &module)
+{
+  for (auto &item : module.get_items ())
+    TypeCheckItem::Resolve (*item.get ());
+}
+
+void
+TypeCheckItem::visit (HIR::Trait &trait)
+{
+  TraitResolver::Resolve (trait);
+}
+
+void
+TypeCheckItem::visit (HIR::ExternBlock &extern_block)
+{
+  for (auto &item : extern_block.get_extern_items ())
+    {
+      TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
+    }
+}
+
+std::vector<TyTy::SubstitutionParamMapping>
+TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block,
+						 bool &failure_flag)
+{
+  std::vector<TyTy::SubstitutionParamMapping> substitutions;
+  if (impl_block.has_generics ())
+    resolve_generic_params (impl_block.get_generic_params (), substitutions);
+
+  for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
+    {
+      ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
     }
 
   auto specified_bound = TyTy::TypeBoundPredicate::error ();
@@ -84,14 +491,7 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
       specified_bound = get_predicate_from_bound (*ref.get ());
     }
 
-  TyTy::BaseType *self = nullptr;
-  if (!context->lookup_type (
-	impl_block.get_type ()->get_mappings ().get_hirid (), &self))
-    {
-      rust_error_at (impl_block.get_locus (),
-		     "failed to resolve Self for ImplBlock");
-      return;
-    }
+  TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ().get ());
 
   // inherit the bounds
   if (!specified_bound.is_error ())
@@ -103,20 +503,35 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
   const TyTy::SubstitutionArgumentMappings impl_constraints
     = GetUsedSubstArgs::From (self);
 
-  bool impl_block_has_unconstrained_typarams
-    = check_for_unconstrained (substitutions, trait_constraints,
-			       impl_constraints, self);
-  if (impl_block_has_unconstrained_typarams)
-    return;
+  failure_flag = check_for_unconstrained (substitutions, trait_constraints,
+					  impl_constraints, self);
+
+  return substitutions;
+}
+
+void
+TypeCheckItem::validate_trait_impl_block (
+  HIR::ImplBlock &impl_block, TyTy::BaseType *self,
+  std::vector<TyTy::SubstitutionParamMapping> &substitutions)
+{
+  auto specified_bound = TyTy::TypeBoundPredicate::error ();
+  TraitReference *trait_reference = &TraitReference::error_node ();
+  if (impl_block.has_trait_ref ())
+    {
+      std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref ();
+      trait_reference = TraitResolver::Resolve (*ref.get ());
+      rust_assert (!trait_reference->is_error ());
+
+      // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
+      // for example
+      specified_bound = get_predicate_from_bound (*ref.get ());
+    }
 
-  // validate the impl items
   bool is_trait_impl_block = !trait_reference->is_error ();
   std::vector<const TraitItemReference *> trait_item_refs;
   for (auto &impl_item : impl_block.get_impl_items ())
     {
-      if (!is_trait_impl_block)
-	TypeCheckImplItem::Resolve (&impl_block, impl_item.get (), self);
-      else
+      if (!specified_bound.is_error ())
 	{
 	  auto trait_item_ref
 	    = TypeCheckImplItemWithTrait::Resolve (&impl_block,
@@ -128,7 +543,7 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
     }
 
   bool impl_block_missing_trait_items
-    = is_trait_impl_block
+    = !specified_bound.is_error ()
       && trait_reference->size () != trait_item_refs.size ();
   if (impl_block_missing_trait_items)
     {
@@ -187,55 +602,10 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
     }
 }
 
-void
-TypeCheckItem::visit (HIR::Function &function)
+TyTy::BaseType *
+TypeCheckItem::resolve_impl_block_self (HIR::ImplBlock &impl_block)
 {
-  TyTy::BaseType *lookup;
-  if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
-    {
-      rust_error_at (function.get_locus (), "failed to lookup function type");
-      return;
-    }
-
-  if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
-    {
-      rust_error_at (function.get_locus (),
-		     "found invalid type for function [%s]",
-		     lookup->as_string ().c_str ());
-      return;
-    }
-
-  // need to get the return type from this
-  TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (lookup);
-  auto expected_ret_tyty = resolved_fn_type->get_return_type ();
-  context->push_return_type (TypeCheckContextItem (&function),
-			     expected_ret_tyty);
-
-  auto block_expr_ty
-    = TypeCheckExpr::Resolve (function.get_definition ().get ());
-
-  Location fn_return_locus = function.has_function_return_type ()
-			       ? function.get_return_type ()->get_locus ()
-			       : function.get_locus ();
-  coercion_site (function.get_definition ()->get_mappings ().get_hirid (),
-		 TyTy::TyWithLocation (expected_ret_tyty, fn_return_locus),
-		 TyTy::TyWithLocation (block_expr_ty),
-		 function.get_definition ()->get_locus ());
-
-  context->pop_return_type ();
-}
-
-void
-TypeCheckItem::visit (HIR::Module &module)
-{
-  for (auto &item : module.get_items ())
-    TypeCheckItem::Resolve (*item.get ());
-}
-
-void
-TypeCheckItem::visit (HIR::Trait &trait)
-{
-  TraitResolver::Resolve (trait);
+  return TypeCheckType::Resolve (impl_block.get_type ().get ());
 }
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h
index 18fffa18459..10085c90629 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.h
@@ -27,29 +27,48 @@ namespace Resolver {
 class TypeCheckItem : private TypeCheckBase, private HIR::HIRVisItemVisitor
 {
 public:
-  static void Resolve (HIR::Item &item);
+  static TyTy::BaseType *Resolve (HIR::Item &item);
+
+  static TyTy::BaseType *ResolveImplItem (HIR::ImplBlock &impl_block,
+					  HIR::ImplItem &item);
+
+  static TyTy::BaseType *ResolveImplBlockSelf (HIR::ImplBlock &impl_block);
 
-  void visit (HIR::ImplBlock &impl_block) override;
-  void visit (HIR::Function &function) override;
   void visit (HIR::Module &module) override;
-  void visit (HIR::Trait &trait) override;
-
-  // FIXME - get rid of toplevel pass
-  void visit (HIR::TypeAlias &alias) override{};
-  void visit (HIR::TupleStruct &struct_decl) override{};
-  void visit (HIR::StructStruct &struct_decl) override{};
-  void visit (HIR::Enum &enum_decl) override{};
-  void visit (HIR::Union &union_decl) override{};
-  void visit (HIR::StaticItem &var) override{};
-  void visit (HIR::ConstantItem &constant) override{};
-  void visit (HIR::ExternBlock &extern_block) override{};
+  void visit (HIR::Function &function) override;
+  void visit (HIR::TypeAlias &alias) override;
+  void visit (HIR::TupleStruct &struct_decl) override;
+  void visit (HIR::StructStruct &struct_decl) override;
+  void visit (HIR::Enum &enum_decl) override;
+  void visit (HIR::Union &union_decl) override;
+  void visit (HIR::StaticItem &var) override;
+  void visit (HIR::ConstantItem &constant) override;
+  void visit (HIR::ImplBlock &impl_block) override;
+  void visit (HIR::ExternBlock &extern_block) override;
+  void visit (HIR::Trait &trait_block) override;
 
   // nothing to do
   void visit (HIR::ExternCrate &crate) override {}
   void visit (HIR::UseDeclaration &use_decl) override {}
 
+protected:
+  std::vector<TyTy::SubstitutionParamMapping>
+  resolve_impl_block_substitutions (HIR::ImplBlock &impl_block,
+				    bool &failure_flag);
+
+  void validate_trait_impl_block (
+    HIR::ImplBlock &impl_block, TyTy::BaseType *self,
+    std::vector<TyTy::SubstitutionParamMapping> &substitutions);
+
+  TyTy::BaseType *resolve_impl_item (HIR::ImplBlock &impl_block,
+				     HIR::ImplItem &item);
+
+  TyTy::BaseType *resolve_impl_block_self (HIR::ImplBlock &impl_block);
+
 private:
   TypeCheckItem ();
+
+  TyTy::BaseType *infered;
 };
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc
index bf1de21ee4f..f404ea64bcc 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-path.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -235,7 +235,7 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
 	}
 
       TyTy::BaseType *lookup = nullptr;
-      if (!context->lookup_type (ref, &lookup))
+      if (!query_type (ref, &lookup))
 	{
 	  if (is_root)
 	    {
@@ -383,7 +383,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
 	  HirId impl_ty_id
 	    = associated_impl_block->get_type ()->get_mappings ().get_hirid ();
 	  TyTy::BaseType *impl_block_ty = nullptr;
-	  bool ok = context->lookup_type (impl_ty_id, &impl_block_ty);
+	  bool ok = query_type (impl_ty_id, &impl_block_ty);
 	  rust_assert (ok);
 
 	  if (impl_block_ty->needs_generic_substitutions ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc
index a55cf22ba23..437782e8102 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc
@@ -22,6 +22,7 @@
 #include "rust-hir-type-check-expr.h"
 #include "rust-hir-type-check-enumitem.h"
 #include "rust-hir-type-check-implitem.h"
+#include "rust-hir-type-check-item.h"
 #include "rust-hir-type-check-pattern.h"
 
 namespace Rust {
@@ -139,378 +140,74 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt)
 }
 
 void
-TypeCheckStmt::visit (HIR::TupleStruct &struct_decl)
+TypeCheckStmt::visit (HIR::TypePath &path)
 {
-  std::vector<TyTy::SubstitutionParamMapping> substitutions;
-  if (struct_decl.has_generics ())
-    {
-      for (auto &generic_param : struct_decl.get_generic_params ())
-	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		auto param_type
-		  = TypeResolveGenericParam::Resolve (generic_param.get ());
-		context->insert_type (generic_param->get_mappings (),
-				      param_type);
-
-		substitutions.push_back (TyTy::SubstitutionParamMapping (
-		  static_cast<HIR::TypeParam &> (*generic_param), param_type));
-	      }
-	      break;
-	    }
-	}
-    }
-
-  std::vector<TyTy::StructFieldType *> fields;
-  size_t idx = 0;
-  for (auto &field : struct_decl.get_fields ())
-    {
-      TyTy::BaseType *field_type
-	= TypeCheckType::Resolve (field.get_field_type ().get ());
-      TyTy::StructFieldType *ty_field
-	= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
-				     std::to_string (idx), field_type,
-				     field.get_locus ());
-      fields.push_back (ty_field);
-      context->insert_type (field.get_mappings (), ty_field->get_field_type ());
-      idx++;
-    }
-
-  // get the path
-  const CanonicalPath *canonical_path = nullptr;
-  bool ok = mappings->lookup_canonical_path (
-    struct_decl.get_mappings ().get_nodeid (), &canonical_path);
-  rust_assert (ok);
-  RustIdent ident{*canonical_path, struct_decl.get_locus ()};
-
-  // there is only a single variant
-  std::vector<TyTy::VariantDef *> variants;
-  variants.push_back (new TyTy::VariantDef (
-    struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
-    ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
-
-  // Process #[repr(...)] attribute, if any
-  const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
-  TyTy::ADTType::ReprOptions repr
-    = parse_repr_options (attrs, struct_decl.get_locus ());
-
-  TyTy::BaseType *type
-    = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
-			 mappings->get_next_hir_id (),
-			 struct_decl.get_identifier (), ident,
-			 TyTy::ADTType::ADTKind::TUPLE_STRUCT,
-			 std::move (variants), std::move (substitutions), repr);
+  infered = TypeCheckType::Resolve (&path);
+}
+void
+TypeCheckStmt::visit (HIR::QualifiedPathInType &path)
+{
+  infered = TypeCheckType::Resolve (&path);
+}
 
-  context->insert_type (struct_decl.get_mappings (), type);
-  infered = type;
+void
+TypeCheckStmt::visit (HIR::TupleStruct &struct_decl)
+{
+  infered = TypeCheckItem::Resolve (struct_decl);
 }
 
 void
 TypeCheckStmt::visit (HIR::Enum &enum_decl)
 {
-  std::vector<TyTy::SubstitutionParamMapping> substitutions;
-  if (enum_decl.has_generics ())
-    {
-      for (auto &generic_param : enum_decl.get_generic_params ())
-	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		auto param_type
-		  = TypeResolveGenericParam::Resolve (generic_param.get ());
-		context->insert_type (generic_param->get_mappings (),
-				      param_type);
-
-		substitutions.push_back (TyTy::SubstitutionParamMapping (
-		  static_cast<HIR::TypeParam &> (*generic_param), param_type));
-	      }
-	      break;
-	    }
-	}
-    }
-
-  std::vector<TyTy::VariantDef *> variants;
-  int64_t discriminant_value = 0;
-  for (auto &variant : enum_decl.get_variants ())
-    {
-      TyTy::VariantDef *field_type
-	= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
-
-      discriminant_value++;
-      variants.push_back (field_type);
-    }
-
-  // get the path
-  const CanonicalPath *canonical_path = nullptr;
-  bool ok
-    = mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
-				       &canonical_path);
-  rust_assert (ok);
-  RustIdent ident{*canonical_path, enum_decl.get_locus ()};
-
-  TyTy::BaseType *type
-    = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
-			 mappings->get_next_hir_id (),
-			 enum_decl.get_identifier (), ident,
-			 TyTy::ADTType::ADTKind::ENUM, std::move (variants),
-			 std::move (substitutions));
-
-  context->insert_type (enum_decl.get_mappings (), type);
-  infered = type;
+  infered = TypeCheckItem::Resolve (enum_decl);
 }
 
 void
 TypeCheckStmt::visit (HIR::StructStruct &struct_decl)
 {
-  std::vector<TyTy::SubstitutionParamMapping> substitutions;
-  if (struct_decl.has_generics ())
-    {
-      for (auto &generic_param : struct_decl.get_generic_params ())
-	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		auto param_type
-		  = TypeResolveGenericParam::Resolve (generic_param.get ());
-		context->insert_type (generic_param->get_mappings (),
-				      param_type);
-
-		substitutions.push_back (TyTy::SubstitutionParamMapping (
-		  static_cast<HIR::TypeParam &> (*generic_param), param_type));
-	      }
-	      break;
-	    }
-	}
-    }
-
-  std::vector<TyTy::StructFieldType *> fields;
-  for (auto &field : struct_decl.get_fields ())
-    {
-      TyTy::BaseType *field_type
-	= TypeCheckType::Resolve (field.get_field_type ().get ());
-      TyTy::StructFieldType *ty_field
-	= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
-				     field.get_field_name (), field_type,
-				     field.get_locus ());
-      fields.push_back (ty_field);
-      context->insert_type (field.get_mappings (), ty_field->get_field_type ());
-    }
-
-  // get the path
-  const CanonicalPath *canonical_path = nullptr;
-  bool ok = mappings->lookup_canonical_path (
-    struct_decl.get_mappings ().get_nodeid (), &canonical_path);
-  rust_assert (ok);
-  RustIdent ident{*canonical_path, struct_decl.get_locus ()};
-
-  // there is only a single variant
-  std::vector<TyTy::VariantDef *> variants;
-  variants.push_back (new TyTy::VariantDef (
-    struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
-    ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
-
-  // Process #[repr(...)] attribute, if any
-  const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
-  TyTy::ADTType::ReprOptions repr
-    = parse_repr_options (attrs, struct_decl.get_locus ());
-
-  TyTy::BaseType *type
-    = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
-			 mappings->get_next_hir_id (),
-			 struct_decl.get_identifier (), ident,
-			 TyTy::ADTType::ADTKind::STRUCT_STRUCT,
-			 std::move (variants), std::move (substitutions), repr);
-
-  context->insert_type (struct_decl.get_mappings (), type);
-  infered = type;
+  infered = TypeCheckItem::Resolve (struct_decl);
 }
 
 void
 TypeCheckStmt::visit (HIR::Union &union_decl)
 {
-  std::vector<TyTy::SubstitutionParamMapping> substitutions;
-  if (union_decl.has_generics ())
-    {
-      for (auto &generic_param : union_decl.get_generic_params ())
-	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		auto param_type
-		  = TypeResolveGenericParam::Resolve (generic_param.get ());
-		context->insert_type (generic_param->get_mappings (),
-				      param_type);
-
-		substitutions.push_back (TyTy::SubstitutionParamMapping (
-		  static_cast<HIR::TypeParam &> (*generic_param), param_type));
-	      }
-	      break;
-	    }
-	}
-    }
-
-  std::vector<TyTy::StructFieldType *> fields;
-  for (auto &variant : union_decl.get_variants ())
-    {
-      TyTy::BaseType *variant_type
-	= TypeCheckType::Resolve (variant.get_field_type ().get ());
-      TyTy::StructFieldType *ty_variant
-	= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
-				     variant.get_field_name (), variant_type,
-				     variant.get_locus ());
-      fields.push_back (ty_variant);
-      context->insert_type (variant.get_mappings (),
-			    ty_variant->get_field_type ());
-    }
-
-  // get the path
-  const CanonicalPath *canonical_path = nullptr;
-  bool ok
-    = mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
-				       &canonical_path);
-  rust_assert (ok);
-  RustIdent ident{*canonical_path, union_decl.get_locus ()};
-
-  // there is only a single variant
-  std::vector<TyTy::VariantDef *> variants;
-  variants.push_back (new TyTy::VariantDef (
-    union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
-    ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
-
-  TyTy::BaseType *type
-    = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
-			 mappings->get_next_hir_id (),
-			 union_decl.get_identifier (), ident,
-			 TyTy::ADTType::ADTKind::UNION, std::move (variants),
-			 std::move (substitutions));
-
-  context->insert_type (union_decl.get_mappings (), type);
-  infered = type;
+  infered = TypeCheckItem::Resolve (union_decl);
 }
 
 void
 TypeCheckStmt::visit (HIR::Function &function)
 {
-  std::vector<TyTy::SubstitutionParamMapping> substitutions;
-  if (function.has_generics ())
-    {
-      for (auto &generic_param : function.get_generic_params ())
-	{
-	  switch (generic_param.get ()->get_kind ())
-	    {
-	    case HIR::GenericParam::GenericKind::LIFETIME:
-	    case HIR::GenericParam::GenericKind::CONST:
-	      // FIXME: Skipping Lifetime and Const completely until better
-	      // handling.
-	      break;
-
-	      case HIR::GenericParam::GenericKind::TYPE: {
-		auto param_type
-		  = TypeResolveGenericParam::Resolve (generic_param.get ());
-		context->insert_type (generic_param->get_mappings (),
-				      param_type);
-
-		substitutions.push_back (TyTy::SubstitutionParamMapping (
-		  static_cast<HIR::TypeParam &> (*generic_param), param_type));
-	      }
-	      break;
-	    }
-	}
-    }
-
-  TyTy::BaseType *ret_type = nullptr;
-  if (!function.has_function_return_type ())
-    ret_type
-      = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
-  else
-    {
-      auto resolved
-	= TypeCheckType::Resolve (function.get_return_type ().get ());
-      if (resolved == nullptr)
-	{
-	  rust_error_at (function.get_locus (),
-			 "failed to resolve return type");
-	  return;
-	}
-
-      ret_type = resolved->clone ();
-      ret_type->set_ref (
-	function.get_return_type ()->get_mappings ().get_hirid ());
-    }
-
-  std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
-  for (auto &param : function.get_function_params ())
-    {
-      // get the name as well required for later on
-      auto param_tyty = TypeCheckType::Resolve (param.get_type ());
-      params.push_back (
-	std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
-						     param_tyty));
-
-      context->insert_type (param.get_mappings (), param_tyty);
-      TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
-    }
-
-  // get the path
-  const CanonicalPath *canonical_path = nullptr;
-  bool ok
-    = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
-				       &canonical_path);
-  rust_assert (ok);
-
-  RustIdent ident{*canonical_path, function.get_locus ()};
-  auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
-				  function.get_mappings ().get_defid (),
-				  function.get_function_name (), ident,
-				  TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
-				  std::move (params), ret_type,
-				  std::move (substitutions));
-  context->insert_type (function.get_mappings (), fnType);
+  infered = TypeCheckItem::Resolve (function);
+}
 
-  TyTy::FnType *resolved_fn_type = fnType;
-  auto expected_ret_tyty = resolved_fn_type->get_return_type ();
-  context->push_return_type (TypeCheckContextItem (&function),
-			     expected_ret_tyty);
+void
+TypeCheckStmt::visit (HIR::Module &module)
+{
+  infered = TypeCheckItem::Resolve (module);
+}
 
-  auto block_expr_ty
-    = TypeCheckExpr::Resolve (function.get_definition ().get ());
+void
+TypeCheckStmt::visit (HIR::TypeAlias &type_alias)
+{
+  infered = TypeCheckItem::Resolve (type_alias);
+}
 
-  context->pop_return_type ();
+void
+TypeCheckStmt::visit (HIR::StaticItem &static_item)
+{
+  infered = TypeCheckItem::Resolve (static_item);
+}
 
-  Location fn_return_locus = function.has_function_return_type ()
-			       ? function.get_return_type ()->get_locus ()
-			       : function.get_locus ();
-  coercion_site (function.get_definition ()->get_mappings ().get_hirid (),
-		 TyTy::TyWithLocation (expected_ret_tyty, fn_return_locus),
-		 TyTy::TyWithLocation (block_expr_ty),
-		 function.get_definition ()->get_locus ());
+void
+TypeCheckStmt::visit (HIR::Trait &trait)
+{
+  infered = TypeCheckItem::Resolve (trait);
+}
 
-  infered = fnType;
+void
+TypeCheckStmt::visit (HIR::ImplBlock &impl)
+{
+  infered = TypeCheckItem::Resolve (impl);
 }
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
index d7edfad7302..04878b8c531 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -40,50 +40,32 @@ public:
   void visit (HIR::StructStruct &struct_decl) override;
   void visit (HIR::Union &union_decl) override;
   void visit (HIR::Function &function) override;
+  void visit (HIR::Module &module) override;
+  void visit (HIR::TypeAlias &type_alias) override;
+  void visit (HIR::StaticItem &static_item) override;
+  void visit (HIR::Trait &trait) override;
+  void visit (HIR::ImplBlock &impl) override;
+  void visit (HIR::TypePath &path) override;
+  void visit (HIR::QualifiedPathInType &path) override;
 
-  void visit (HIR::EnumItemTuple &) override
-  { /* TODO? */
-  }
-  void visit (HIR::EnumItemStruct &) override
-  { /* TODO? */
-  }
-  void visit (HIR::EnumItem &item) override
-  { /* TODO? */
-  }
-  void visit (HIR::EnumItemDiscriminant &) override
-  { /* TODO? */
-  }
+  // FIXME
+  // this seems like it should not be part of this visitor
   void visit (HIR::TypePathSegmentFunction &segment) override
-  { /* TODO? */
-  }
-  void visit (HIR::TypePath &path) override
-  { /* TODO? */
-  }
-  void visit (HIR::QualifiedPathInType &path) override
-  { /* TODO? */
-  }
-  void visit (HIR::Module &module) override
-  { /* TODO? */
-  }
-  void visit (HIR::ExternCrate &crate) override
-  { /* TODO? */
-  }
-  void visit (HIR::UseDeclaration &use_decl) override
-  { /* TODO? */
-  }
-  void visit (HIR::TypeAlias &type_alias) override
-  { /* TODO? */
-  }
-  void visit (HIR::StaticItem &static_item) override
-  { /* TODO? */
-  }
-  void visit (HIR::Trait &trait) override
-  { /* TODO? */
-  }
-  void visit (HIR::ImplBlock &impl) override
-  { /* TODO? */
+  {
+    gcc_unreachable ();
   }
 
+  // nothing to do for these
+  void visit (HIR::ExternCrate &crate) override {}
+  void visit (HIR::UseDeclaration &use_decl) override {}
+
+  // nothing to do for these as they are taken care of by the
+  // hir-type-check-enumitem.h
+  void visit (HIR::EnumItemTuple &) override {}
+  void visit (HIR::EnumItemStruct &) override {}
+  void visit (HIR::EnumItem &) override {}
+  void visit (HIR::EnumItemDiscriminant &) override {}
+
 private:
   TypeCheckStmt () : TypeCheckBase (), infered (nullptr) {}
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index 06dc8e042d9..5a6d00a0e9d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -48,6 +48,14 @@ TypeCheckResolveGenericArguments::visit (HIR::TypePathSegmentGeneric &generic)
 TyTy::BaseType *
 TypeCheckType::Resolve (HIR::Type *type)
 {
+  // is it already resolved?
+  auto context = TypeCheckContext::get ();
+  TyTy::BaseType *resolved = nullptr;
+  bool already_resolved
+    = context->lookup_type (type->get_mappings ().get_hirid (), &resolved);
+  if (already_resolved)
+    return resolved;
+
   TypeCheckType resolver (type->get_mappings ().get_hirid ());
   type->accept_vis (resolver);
   rust_assert (resolver.translated != nullptr);
@@ -103,77 +111,29 @@ TypeCheckType::visit (HIR::TupleType &tuple)
 void
 TypeCheckType::visit (HIR::TypePath &path)
 {
-  // lookup the Node this resolves to
-  NodeId ref;
-  auto nid = path.get_mappings ().get_nodeid ();
-  bool is_fully_resolved = resolver->lookup_resolved_type (nid, &ref);
-
-  TyTy::BaseType *lookup = nullptr;
-  if (!is_fully_resolved)
-    {
-      // this can happen so we need to look up the root then resolve the
-      // remaining segments if possible
-      size_t offset = 0;
-      NodeId resolved_node_id = UNKNOWN_NODEID;
-      TyTy::BaseType *root
-	= resolve_root_path (path, &offset, &resolved_node_id);
-
-      rust_assert (root != nullptr);
-      if (root->get_kind () == TyTy::TypeKind::ERROR)
-	return;
-
-      translated
-	= resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (),
-			    path.get_segments (), offset, root,
-			    path.get_mappings (), path.get_locus ());
-      return;
-    }
-
-  HirId hir_lookup;
-  if (!context->lookup_type_by_node_id (ref, &hir_lookup))
-    {
-      rust_error_at (path.get_locus (), "failed to lookup HIR %d for node '%s'",
-		     ref, path.as_string ().c_str ());
-      return;
-    }
-
-  if (!context->lookup_type (hir_lookup, &lookup))
-    {
-      rust_error_at (path.get_locus (), "failed to lookup HIR TyTy");
-      return;
-    }
+  // this can happen so we need to look up the root then resolve the
+  // remaining segments if possible
+  size_t offset = 0;
+  NodeId resolved_node_id = UNKNOWN_NODEID;
+  TyTy::BaseType *root = resolve_root_path (path, &offset, &resolved_node_id);
+  if (root->get_kind () == TyTy::TypeKind::ERROR)
+    return;
 
-  TyTy::BaseType *path_type = lookup->clone ();
+  TyTy::BaseType *path_type = root->clone ();
   path_type->set_ref (path.get_mappings ().get_hirid ());
+  context->insert_implicit_type (path.get_mappings ().get_hirid (), path_type);
 
-  HIR::TypePathSegment *final_seg = path.get_final_segment ().get ();
-  HIR::GenericArgs args = TypeCheckResolveGenericArguments::resolve (final_seg);
-
-  bool is_big_self = final_seg->is_ident_only ()
-		     && (final_seg->as_string ().compare ("Self") == 0);
-
-  if (path_type->needs_generic_substitutions ())
-    {
-      if (is_big_self)
-	{
-	  translated = path_type;
-	  return;
-	}
-
-      translated = SubstMapper::Resolve (path_type, path.get_locus (), &args);
-    }
-  else if (!args.is_empty ())
-    {
-      rust_error_at (path.get_locus (),
-		     "TypePath %s declares generic arguments but "
-		     "the type %s does not have any",
-		     path.as_string ().c_str (),
-		     path_type->as_string ().c_str ());
-    }
-  else
+  bool fully_resolved = offset >= path.get_segments ().size ();
+  if (fully_resolved)
     {
       translated = path_type;
+      return;
     }
+
+  translated
+    = resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (),
+			path.get_segments (), offset, path_type,
+			path.get_mappings (), path.get_locus ());
 }
 
 void
@@ -389,7 +349,7 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
 	}
 
       TyTy::BaseType *lookup = nullptr;
-      if (!context->lookup_type (ref, &lookup))
+      if (!query_type (ref, &lookup))
 	{
 	  if (is_root)
 	    {
@@ -428,14 +388,22 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
 
 	  if (!lookup->can_substitute ())
 	    {
-	      rust_error_at (seg->get_locus (),
-			     "substitutions not supported for %s",
+	      rust_error_at (path.get_locus (),
+			     "TypePath %s declares generic arguments but the "
+			     "type %s does not have any",
+			     path.as_string ().c_str (),
 			     lookup->as_string ().c_str ());
 	      return new TyTy::ErrorType (lookup->get_ref ());
 	    }
 	  lookup = SubstMapper::Resolve (lookup, path.get_locus (),
 					 &generic_segment->get_generic_args ());
 	}
+      else if (lookup->needs_generic_substitutions ())
+	{
+	  HIR::GenericArgs empty
+	    = HIR::GenericArgs::create_empty (path.get_locus ());
+	  lookup = SubstMapper::Resolve (lookup, path.get_locus (), &empty);
+	}
 
       *root_resolved_node_id = ref_node_id;
       *offset = *offset + 1;
@@ -531,7 +499,7 @@ TypeCheckType::resolve_segments (
   context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
   if (tyseg->needs_generic_substitutions ())
     {
-      Location locus = segments.back ()->get_locus ();
+      // Location locus = segments.back ()->get_locus ();
       if (!prev_segment->needs_generic_substitutions ())
 	{
 	  auto used_args_in_prev_segment
@@ -540,10 +508,6 @@ TypeCheckType::resolve_segments (
 	    tyseg
 	      = SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment);
 	}
-      else
-	{
-	  tyseg = SubstMapper::InferSubst (tyseg, locus);
-	}
 
       if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
 	return new TyTy::ErrorType (expr_id);
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index f2445cd3ba2..d73e31efab8 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -18,7 +18,6 @@
 
 #include "rust-hir-type-check.h"
 #include "rust-hir-full.h"
-#include "rust-hir-type-check-toplevel.h"
 #include "rust-hir-type-check-item.h"
 #include "rust-hir-type-check-expr.h"
 #include "rust-hir-type-check-pattern.h"
@@ -35,7 +34,7 @@ void
 TypeResolution::Resolve (HIR::Crate &crate)
 {
   for (auto it = crate.items.begin (); it != crate.items.end (); it++)
-    TypeCheckTopLevel::Resolve (*it->get ());
+    TypeCheckItem::Resolve (*it->get ());
 
   if (saw_errors ())
     return;
@@ -44,12 +43,6 @@ TypeResolution::Resolve (HIR::Crate &crate)
   if (saw_errors ())
     return;
 
-  for (auto it = crate.items.begin (); it != crate.items.end (); it++)
-    TypeCheckItem::Resolve (*it->get ());
-
-  if (saw_errors ())
-    return;
-
   auto mappings = Analysis::Mappings::get ();
   auto context = TypeCheckContext::get ();
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 5a6c0426fd6..3e9c9c4d21a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -337,6 +337,41 @@ public:
     return true;
   }
 
+  void insert_unconstrained_check_marker (HirId id, bool status)
+  {
+    unconstrained[id] = status;
+  }
+
+  bool have_checked_for_unconstrained (HirId id, bool *result)
+  {
+    auto it = unconstrained.find (id);
+    bool found = it != unconstrained.end ();
+    if (!found)
+      return false;
+
+    *result = it->second;
+    return true;
+  }
+
+  void insert_resolved_predicate (HirId id, TyTy::TypeBoundPredicate predicate)
+  {
+    auto it = predicates.find (id);
+    rust_assert (it == predicates.end ());
+
+    predicates.insert ({id, predicate});
+  }
+
+  bool lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result)
+  {
+    auto it = predicates.find (id);
+    bool found = it != predicates.end ();
+    if (!found)
+      return false;
+
+    *result = it->second;
+    return true;
+  }
+
 private:
   TypeCheckContext ();
 
@@ -365,6 +400,12 @@ private:
 
   // variants
   std::map<HirId, HirId> variants;
+
+  // unconstrained type-params check
+  std::map<HirId, bool> unconstrained;
+
+  // predicates
+  std::map<HirId, TyTy::TypeBoundPredicate> predicates;
 };
 
 class TypeResolution
diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h
index 14b4e060d21..995d9c88ec4 100644
--- a/gcc/rust/typecheck/rust-substitution-mapper.h
+++ b/gcc/rust/typecheck/rust-substitution-mapper.h
@@ -102,7 +102,7 @@ public:
     if (!have_generic_args ())
       {
 	TyTy::BaseType *substs = type.infer_substitions (locus);
-	rust_assert (substs->get_kind () == TyTy::TypeKind::ADT);
+	rust_assert (substs->get_kind () == TyTy::TypeKind::PROJECTION);
 	concrete = static_cast<TyTy::ProjectionType *> (substs);
       }
     else
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 69376aaa373..5b5ff751e2b 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -18,6 +18,7 @@
 
 #include "rust-hir-type-bounds.h"
 #include "rust-hir-trait-resolve.h"
+#include "rust-hir-type-check-item.h"
 
 namespace Rust {
 namespace Resolver {
@@ -33,11 +34,8 @@ TypeBoundsProbe::scan ()
       if (!impl->has_trait_ref ())
 	return true;
 
-      TyTy::BaseType *impl_type = nullptr;
-      bool ok
-	= context->lookup_type (impl->get_type ()->get_mappings ().get_hirid (),
-				&impl_type);
-      if (!ok)
+      TyTy::BaseType *impl_type = TypeCheckItem::ResolveImplBlockSelf (*impl);
+      if (impl_type->get_kind () == TyTy::TypeKind::ERROR)
 	return true;
 
       if (!receiver->can_eq (impl_type, false))
@@ -69,6 +67,13 @@ TypeCheckBase::resolve_trait_path (HIR::TypePath &path)
 TyTy::TypeBoundPredicate
 TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
 {
+  TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error ();
+  bool already_resolved
+    = context->lookup_predicate (type_path.get_mappings ().get_hirid (),
+				 &lookup);
+  if (already_resolved)
+    return lookup;
+
   TraitReference *trait = resolve_trait_path (type_path);
   if (trait->is_error ())
     return TyTy::TypeBoundPredicate::error ();
@@ -94,6 +99,8 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
       predicate.apply_generic_arguments (&args);
     }
 
+  context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
+				      predicate);
   return predicate;
 }
 
@@ -470,6 +477,13 @@ TypeBoundsMappings::raw_bounds_as_name () const
 void
 TypeBoundsMappings::add_bound (TypeBoundPredicate predicate)
 {
+  for (auto &bound : specified_bounds)
+    {
+      bool same_trait_ref_p = bound.get_id () == predicate.get_id ();
+      if (same_trait_ref_p)
+	return;
+    }
+
   specified_bounds.push_back (predicate);
 }
 
diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h
index 2813bf42c1c..d47cbb4369a 100644
--- a/gcc/rust/typecheck/rust-tyty-cmp.h
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -1358,6 +1358,8 @@ public:
   // generic arguments
   void visit (const ParamType &) override { ok = true; }
 
+  void visit (const TupleType &) override { ok = true; }
+
   void visit (const InferType &) override { ok = true; }
 
   void visit (const FnType &) override { ok = true; }
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 3e29bd2a92c..64fe0f6cfb0 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -208,9 +208,6 @@ void
 BaseType::inherit_bounds (
   const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
 {
-  // FIXME
-  // 1. This needs to union the bounds
-  // 2. Do some checking for trait polarity to ensure compatibility
   for (auto &bound : specified_bounds)
     {
       add_bound (bound);
@@ -754,6 +751,40 @@ SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args)
   return SubstitutionArgumentMappings (mappings, args.get_locus ());
 }
 
+BaseType *
+SubstitutionRef::infer_substitions (Location locus)
+{
+  std::vector<SubstitutionArg> args;
+  std::map<std::string, BaseType *> argument_mappings;
+  for (auto &p : get_substs ())
+    {
+      if (p.needs_substitution ())
+	{
+	  const std::string &symbol = p.get_param_ty ()->get_symbol ();
+	  auto it = argument_mappings.find (symbol);
+	  bool have_mapping = it != argument_mappings.end ();
+
+	  if (have_mapping)
+	    {
+	      args.push_back (SubstitutionArg (&p, it->second));
+	    }
+	  else
+	    {
+	      TyVar infer_var = TyVar::get_implicit_infer_var (locus);
+	      args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
+	      argument_mappings[symbol] = infer_var.get_tyty ();
+	    }
+	}
+      else
+	{
+	  args.push_back (SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
+	}
+    }
+
+  SubstitutionArgumentMappings infer_arguments (std::move (args), locus);
+  return handle_substitions (std::move (infer_arguments));
+}
+
 SubstitutionArgumentMappings
 SubstitutionRef::adjust_mappings_for_this (
   SubstitutionArgumentMappings &mappings)
@@ -2479,7 +2510,13 @@ ParamType::resolve () const
 	break;
 
       TyVar v (rr->get_ty_ref ());
-      r = v.get_tyty ();
+      BaseType *n = v.get_tyty ();
+
+      // fix infinite loop
+      if (r == n)
+	break;
+
+      r = n;
     }
 
   if (r->get_kind () == TypeKind::PARAM && (r->get_ref () == r->get_ty_ref ()))
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 43460d2dd2f..e3cf4d667c7 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -960,37 +960,7 @@ public:
   solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to);
 
   // TODO comment
-  BaseType *infer_substitions (Location locus)
-  {
-    std::vector<SubstitutionArg> args;
-    std::map<std::string, BaseType *> argument_mappings;
-    for (auto &p : get_substs ())
-      {
-	if (p.needs_substitution ())
-	  {
-	    const std::string &symbol = p.get_param_ty ()->get_symbol ();
-	    auto it = argument_mappings.find (symbol);
-	    if (it == argument_mappings.end ())
-	      {
-		TyVar infer_var = TyVar::get_implicit_infer_var (locus);
-		args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
-		argument_mappings[symbol] = infer_var.get_tyty ();
-	      }
-	    else
-	      {
-		args.push_back (SubstitutionArg (&p, it->second));
-	      }
-	  }
-	else
-	  {
-	    args.push_back (
-	      SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
-	  }
-      }
-
-    SubstitutionArgumentMappings infer_arguments (std::move (args), locus);
-    return handle_substitions (std::move (infer_arguments));
-  }
+  BaseType *infer_substitions (Location locus);
 
   // TODO comment
   bool monomorphize ();
@@ -1059,6 +1029,8 @@ public:
 
   bool contains_associated_types () const;
 
+  DefId get_id () const { return reference; }
+
 private:
   DefId reference;
   Location locus;
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 103d6869b81..80434489fcd 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -419,7 +419,9 @@ Mappings::insert_hir_impl_block (HIR::ImplBlock *item)
   auto id = item->get_mappings ().get_hirid ();
   rust_assert (lookup_hir_impl_block (id) == nullptr);
 
+  HirId impl_type_id = item->get_type ()->get_mappings ().get_hirid ();
   hirImplBlockMappings[id] = item;
+  hirImplBlockTypeMappings[impl_type_id] = item;
   insert_node_to_hir (item->get_mappings ().get_nodeid (), id);
 }
 
@@ -433,6 +435,17 @@ Mappings::lookup_hir_impl_block (HirId id)
   return it->second;
 }
 
+bool
+Mappings::lookup_impl_block_type (HirId id, HIR::ImplBlock **impl_block)
+{
+  auto it = hirImplBlockTypeMappings.find (id);
+  if (it == hirImplBlockTypeMappings.end ())
+    return false;
+
+  *impl_block = it->second;
+  return true;
+}
+
 void
 Mappings::insert_module (HIR::Module *module)
 {
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index fadbdde21b5..474bd5fa229 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -123,6 +123,7 @@ public:
 
   void insert_hir_impl_block (HIR::ImplBlock *item);
   HIR::ImplBlock *lookup_hir_impl_block (HirId id);
+  bool lookup_impl_block_type (HirId id, HIR::ImplBlock **impl_block);
 
   void insert_module (HIR::Module *module);
   HIR::Module *lookup_module (HirId id);
@@ -314,6 +315,7 @@ private:
   std::map<HirId, HIR::SelfParam *> hirSelfParamMappings;
   std::map<HirId, HIR::ImplBlock *> hirImplItemsToImplMappings;
   std::map<HirId, HIR::ImplBlock *> hirImplBlockMappings;
+  std::map<HirId, HIR::ImplBlock *> hirImplBlockTypeMappings;
   std::map<HirId, HIR::TraitItem *> hirTraitItemMappings;
   std::map<HirId, HIR::ExternBlock *> hirExternBlockMappings;
   std::map<HirId, std::pair<HIR::ExternalItem *, HirId>> hirExternItemMappings;
diff --git a/gcc/testsuite/rust/compile/const_generics_5.rs b/gcc/testsuite/rust/compile/const_generics_5.rs
index 5344e31a140..46cf6c93968 100644
--- a/gcc/testsuite/rust/compile/const_generics_5.rs
+++ b/gcc/testsuite/rust/compile/const_generics_5.rs
@@ -1,12 +1,15 @@
+// bogus errors but shows the type checking system needs to support const
+// generics with defaults
+
 struct Foo<const N: usize = { 14 }>;
 
 const M: usize = 15;
-type N = Foo<3>;
+type N = Foo<3>; // { dg-error "TypePath Foo<> declares generic arguments but the type Foo{Foo {}} does not have any" }
 
 fn main() {
-    let _: Foo<15> = Foo;
-    let _: Foo<{ M }> = Foo;
-    let _: Foo<M> = Foo;
-    // bogus error, but it means the above const generic gets disambiguated properly
+    let _: Foo<15> = Foo; // { dg-error "TypePath Foo<> declares generic arguments but the type Foo{Foo {}} does not have any" }
+    let _: Foo<{ M }> = Foo; // { dg-error "TypePath Foo<> declares generic arguments but the type Foo{Foo {}} does not have any" }
+    let _: Foo<M> = Foo; // { dg-error "TypePath Foo<> declares generic arguments but the type Foo{Foo {}} does not have any" }
+
     let _: Foo<N> = Foo; // { dg-error "TypePath Foo<N> declares generic arguments but the type Foo{Foo {}} does not have any" }
 }
diff --git a/gcc/testsuite/rust/compile/unconstrained_type_param.rs b/gcc/testsuite/rust/compile/unconstrained_type_param.rs
index c4aaa10146f..7fe74c2c798 100644
--- a/gcc/testsuite/rust/compile/unconstrained_type_param.rs
+++ b/gcc/testsuite/rust/compile/unconstrained_type_param.rs
@@ -9,4 +9,6 @@ impl<X, Y> Foo<X> {
 
 fn main() {
     let a = Foo::test();
+    // { dg-error "Failed to resolve expression of function call" "" { target *-*-* } .-1 }
+    // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 }
 }
