diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc
index 8574988fb0b..a1229adc06c 100644
--- a/gcc/rust/typecheck/rust-hir-trait-reference.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc
@@ -343,14 +343,26 @@ TraitReference::on_resolved ()
 }
 
 void
-TraitReference::clear_associated_types ()
+TraitReference::clear_associated_types () const
 {
-  for (auto &item : item_refs)
+  for (const auto &item : item_refs)
+    {
+      bool is_assoc_type = item.get_trait_item_type ()
+			   == TraitItemReference::TraitItemType::TYPE;
+      if (is_assoc_type)
+	item.associated_type_reset (false);
+    }
+}
+
+void
+TraitReference::clear_associated_type_projections () const
+{
+  for (const auto &item : item_refs)
     {
       bool is_assoc_type = item.get_trait_item_type ()
 			   == TraitItemReference::TraitItemType::TYPE;
       if (is_assoc_type)
-	item.associated_type_reset ();
+	item.associated_type_reset (true);
     }
 }
 
diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h
index f3703efcced..d20b2952e5b 100644
--- a/gcc/rust/typecheck/rust-hir-trait-reference.h
+++ b/gcc/rust/typecheck/rust-hir-trait-reference.h
@@ -106,7 +106,7 @@ public:
 
   void associated_type_set (TyTy::BaseType *ty) const;
 
-  void associated_type_reset () const;
+  void associated_type_reset (bool only_projections) const;
 
   bool is_object_safe () const;
 
@@ -212,7 +212,9 @@ public:
 
   void on_resolved ();
 
-  void clear_associated_types ();
+  void clear_associated_types () const;
+
+  void clear_associated_type_projections () const;
 
   bool is_equal (const TraitReference &other) const;
 
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index 6e23093eceb..2d7985703cf 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -161,6 +161,9 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference)
   TraitQueryGuard guard (trait_id);
   TyTy::BaseType *self = nullptr;
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
+
+  // FIXME
+  // this should use the resolve_generic_params like everywhere else
   for (auto &generic_param : trait_reference->get_generic_params ())
     {
       switch (generic_param.get ()->get_kind ())
@@ -182,7 +185,11 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference)
 
 	    if (typaram.get_type_representation ().compare ("Self") == 0)
 	      {
-		self = param_type;
+		rust_assert (param_type->get_kind () == TyTy::TypeKind::PARAM);
+		TyTy::ParamType *p
+		  = static_cast<TyTy::ParamType *> (param_type);
+		p->set_implicit_self_trait ();
+		self = p;
 	      }
 	  }
 	  break;
@@ -365,7 +372,7 @@ TraitItemReference::associated_type_set (TyTy::BaseType *ty) const
 }
 
 void
-TraitItemReference::associated_type_reset () const
+TraitItemReference::associated_type_reset (bool only_projections) const
 {
   rust_assert (get_trait_item_type () == TraitItemType::TYPE);
 
@@ -374,7 +381,21 @@ TraitItemReference::associated_type_reset () const
   TyTy::PlaceholderType *placeholder
     = static_cast<TyTy::PlaceholderType *> (item_ty);
 
-  placeholder->clear_associated_type ();
+  if (!only_projections)
+    {
+      placeholder->clear_associated_type ();
+    }
+  else
+    {
+      if (!placeholder->can_resolve ())
+	return;
+
+      const TyTy::BaseType *r = placeholder->resolve ();
+      if (r->get_kind () == TyTy::TypeKind::PROJECTION)
+	{
+	  placeholder->clear_associated_type ();
+	}
+    }
 }
 
 TyTy::BaseType *
diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h
index 4e8c58344de..628bba5da20 100644
--- a/gcc/rust/typecheck/rust-hir-type-bounds.h
+++ b/gcc/rust/typecheck/rust-hir-type-bounds.h
@@ -30,42 +30,18 @@ class TypeBoundsProbe : public TypeCheckBase
 {
 public:
   static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
-  Probe (const TyTy::BaseType *receiver)
-  {
-    TypeBoundsProbe probe (receiver);
-    probe.scan ();
-    return probe.trait_references;
-  }
+  Probe (const TyTy::BaseType *receiver);
 
   static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver,
-					   TraitReference *ref)
-  {
-    for (auto &bound : receiver->get_specified_bounds ())
-      {
-	const TraitReference *b = bound.get ();
-	if (b->is_equal (*ref))
-	  return true;
-      }
-
-    std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
-      = Probe (receiver);
-    for (auto &bound : bounds)
-      {
-	const TraitReference *b = bound.first;
-	if (b->is_equal (*ref))
-	  return true;
-      }
-
-    return false;
-  }
+					   TraitReference *ref);
 
 private:
   void scan ();
+  void assemble_sized_builtin ();
+  void assemble_builtin_candidate (Analysis::RustLangItem::ItemType item);
 
 private:
-  TypeBoundsProbe (const TyTy::BaseType *receiver)
-    : TypeCheckBase (), receiver (receiver)
-  {}
+  TypeBoundsProbe (const TyTy::BaseType *receiver);
 
   const TyTy::BaseType *receiver;
   std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> trait_references;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 46a14eb6e92..d4eea7ae954 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -1095,6 +1095,7 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
       return;
     }
 
+  fn->prepare_higher_ranked_bounds ();
   auto root = receiver_tyty->get_root ();
   if (root->get_kind () == TyTy::TypeKind::ADT)
     {
@@ -1659,6 +1660,11 @@ TypeCheckExpr::resolve_operator_overload (
   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
   rust_assert (fn->is_method ());
 
+  fn->prepare_higher_ranked_bounds ();
+  rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
+		  candidate.candidate.ty->get_ref (),
+		  candidate.candidate.ty->debug_str ().c_str ());
+
   auto root = lhs->get_root ();
   if (root->get_kind () == TyTy::TypeKind::ADT)
     {
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc
index b14e0c68e5a..76d2eeff8ef 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -23,6 +23,41 @@
 namespace Rust {
 namespace Resolver {
 
+TypeBoundsProbe::TypeBoundsProbe (const TyTy::BaseType *receiver)
+  : TypeCheckBase (), receiver (receiver)
+{}
+
+std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
+TypeBoundsProbe::Probe (const TyTy::BaseType *receiver)
+{
+  TypeBoundsProbe probe (receiver);
+  probe.scan ();
+  return probe.trait_references;
+}
+
+bool
+TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver,
+					      TraitReference *ref)
+{
+  for (auto &bound : receiver->get_specified_bounds ())
+    {
+      const TraitReference *b = bound.get ();
+      if (b->is_equal (*ref))
+	return true;
+    }
+
+  std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
+    = Probe (receiver);
+  for (auto &bound : bounds)
+    {
+      const TraitReference *b = bound.first;
+      if (b->is_equal (*ref))
+	return true;
+    }
+
+  return false;
+}
+
 void
 TypeBoundsProbe::scan ()
 {
@@ -57,6 +92,75 @@ TypeBoundsProbe::scan ()
       if (!trait_ref->is_error ())
 	trait_references.push_back ({trait_ref, path.second});
     }
+
+  // marker traits...
+  assemble_sized_builtin ();
+}
+
+void
+TypeBoundsProbe::assemble_sized_builtin ()
+{
+  const TyTy::BaseType *raw = receiver->destructure ();
+
+  // does this thing actually implement sized?
+  switch (raw->get_kind ())
+    {
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+      assemble_builtin_candidate (Analysis::RustLangItem::SIZED);
+      break;
+
+      // not-sure about this.... FIXME
+    case TyTy::INFER:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      break;
+    }
+}
+
+void
+TypeBoundsProbe::assemble_builtin_candidate (
+  Analysis::RustLangItem::ItemType lang_item)
+{
+  DefId id;
+  bool found_lang_item = mappings->lookup_lang_item (lang_item, &id);
+  if (!found_lang_item)
+    return;
+
+  HIR::Item *item = mappings->lookup_defid (id);
+  if (item == nullptr)
+    return;
+
+  rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
+  HIR::Trait *trait = static_cast<HIR::Trait *> (item);
+  const TyTy::BaseType *raw = receiver->destructure ();
+
+  // assemble the reference
+  TraitReference *trait_ref = TraitResolver::Resolve (*trait);
+  trait_references.push_back ({trait_ref, mappings->lookup_builtin_marker ()});
+
+  rust_debug ("Added builtin lang_item: %s for %s",
+	      Analysis::RustLangItem::ToString (lang_item).c_str (),
+	      raw->get_name ().c_str ());
 }
 
 TraitReference *
@@ -101,7 +205,8 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
 	  = static_cast<HIR::TypePathSegmentFunction *> (final_seg.get ());
 	auto &fn = final_function_seg->get_function_path ();
 
-	// we need to make implicit generic args which must be an implicit Tuple
+	// we need to make implicit generic args which must be an implicit
+	// Tuple
 	auto crate_num = mappings->get_current_crate ();
 	HirId implicit_args_id = mappings->get_next_hir_id ();
 	Analysis::NodeMapping mapping (crate_num,
@@ -514,8 +619,8 @@ TypeBoundPredicate::lookup_associated_type (const std::string &search)
 {
   TypeBoundPredicateItem item = lookup_associated_item (search);
 
-  // only need to check that it is infact an associated type because other wise
-  // if it was not found it will just be an error node anyway
+  // only need to check that it is infact an associated type because other
+  // wise if it was not found it will just be an error node anyway
   if (!item.is_error ())
     {
       const auto raw = item.get_raw_item ();
diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc
index e4fe30e00ea..d2f6cf607d1 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.cc
+++ b/gcc/rust/typecheck/rust-tyty-subst.cc
@@ -119,11 +119,6 @@ SubstitutionParamMapping::fill_param_ty (
     {
       type.inherit_bounds (*param);
     }
-  else
-    {
-      if (!param->bounds_compatible (type, locus, true))
-	return false;
-    }
 
   if (type.get_kind () == TypeKind::PARAM)
     {
@@ -133,8 +128,15 @@ SubstitutionParamMapping::fill_param_ty (
   else
     {
       // check the substitution is compatible with bounds
-      if (!param->bounds_compatible (type, locus, true))
-	return false;
+      rust_debug_loc (locus,
+		      "fill_param_ty bounds_compatible: param %s type %s",
+		      param->get_name ().c_str (), type.get_name ().c_str ());
+
+      if (!param->is_implicit_self_trait ())
+	{
+	  if (!param->bounds_compatible (type, locus, true))
+	    return false;
+	}
 
       // recursively pass this down to all HRTB's
       for (auto &bound : param->get_specified_bounds ())
@@ -870,10 +872,149 @@ SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref,
   return SubstitutionArgumentMappings (resolved_mappings, {}, locus);
 }
 
+Resolver::AssociatedImplTrait *
+SubstitutionRef::lookup_associated_impl (const SubstitutionParamMapping &subst,
+					 const TypeBoundPredicate &bound,
+					 const TyTy::BaseType *binding,
+					 bool *error_flag) const
+{
+  auto context = Resolver::TypeCheckContext::get ();
+  const Resolver::TraitReference *specified_bound_ref = bound.get ();
+
+  // setup any associated type mappings for the specified bonds and this
+  // type
+  auto candidates = Resolver::TypeBoundsProbe::Probe (binding);
+  std::vector<Resolver::AssociatedImplTrait *> associated_impl_traits;
+  for (auto &probed_bound : candidates)
+    {
+      const Resolver::TraitReference *bound_trait_ref = probed_bound.first;
+      const HIR::ImplBlock *associated_impl = probed_bound.second;
+
+      HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
+      Resolver::AssociatedImplTrait *associated = nullptr;
+      bool found_impl_trait
+	= context->lookup_associated_trait_impl (impl_block_id, &associated);
+      if (found_impl_trait)
+	{
+	  bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
+	  bool found_self = associated->get_self ()->can_eq (binding, false);
+	  if (found_trait && found_self)
+	    {
+	      associated_impl_traits.push_back (associated);
+	    }
+	}
+    }
+
+  if (associated_impl_traits.empty ())
+    return nullptr;
+
+  // This code is important when you look at slices for example when
+  // you have a slice such as:
+  //
+  // let slice = &array[1..3]
+  //
+  // the higher ranked bounds will end up having an Index trait
+  // implementation for Range<usize> so we need this code to resolve
+  // that we have an integer inference variable that needs to become
+  // a usize
+  //
+  // The other complicated issue is that we might have an intrinsic
+  // which requires the :Clone or Copy bound but the libcore adds
+  // implementations for all the integral types so when there are
+  // multiple candidates we need to resolve to the default
+  // implementation for that type otherwise its an error for
+  // ambiguous type bounds
+
+  // if we have a non-general inference variable we need to be
+  // careful about the selection here
+  bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
+  bool is_integer_infervar
+    = is_infer_var
+      && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
+	   == TyTy::InferType::InferTypeKind::INTEGRAL;
+  bool is_float_infervar
+    = is_infer_var
+      && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
+	   == TyTy::InferType::InferTypeKind::FLOAT;
+
+  Resolver::AssociatedImplTrait *associate_impl_trait = nullptr;
+  if (associated_impl_traits.size () == 1)
+    {
+      // just go for it
+      associate_impl_trait = associated_impl_traits.at (0);
+    }
+  else if (is_integer_infervar)
+    {
+      TyTy::BaseType *type = nullptr;
+      bool ok = context->lookup_builtin ("i32", &type);
+      rust_assert (ok);
+
+      for (auto &impl : associated_impl_traits)
+	{
+	  bool found = impl->get_self ()->is_equal (*type);
+	  if (found)
+	    {
+	      associate_impl_trait = impl;
+	      break;
+	    }
+	}
+    }
+  else if (is_float_infervar)
+    {
+      TyTy::BaseType *type = nullptr;
+      bool ok = context->lookup_builtin ("f64", &type);
+      rust_assert (ok);
+
+      for (auto &impl : associated_impl_traits)
+	{
+	  bool found = impl->get_self ()->is_equal (*type);
+	  if (found)
+	    {
+	      associate_impl_trait = impl;
+	      break;
+	    }
+	}
+    }
+
+  if (associate_impl_trait == nullptr)
+    {
+      // go for the first one? or error out?
+      auto &mappings = *Analysis::Mappings::get ();
+      const auto &type_param = subst.get_generic_param ();
+      const auto *trait_ref = bound.get ();
+
+      RichLocation r (type_param.get_locus ());
+      r.add_range (bound.get_locus ());
+      r.add_range (mappings.lookup_location (binding->get_ref ()));
+
+      rust_error_at (r, "ambiguous type bound for trait %s and type %s",
+		     trait_ref->get_name ().c_str (),
+		     binding->get_name ().c_str ());
+
+      *error_flag = true;
+      return nullptr;
+    }
+
+  return associate_impl_trait;
+}
+
+void
+SubstitutionRef::prepare_higher_ranked_bounds ()
+{
+  for (const auto &subst : get_substs ())
+    {
+      const TyTy::ParamType *pty = subst.get_param_ty ();
+      for (const auto &bound : pty->get_specified_bounds ())
+	{
+	  const auto ref = bound.get ();
+	  ref->clear_associated_type_projections ();
+	}
+    }
+}
+
 bool
 SubstitutionRef::monomorphize ()
 {
-  auto context = Resolver::TypeCheckContext::get ();
   for (const auto &subst : get_substs ())
     {
       const TyTy::ParamType *pty = subst.get_param_ty ();
@@ -887,136 +1028,16 @@ SubstitutionRef::monomorphize ()
 
       for (const auto &bound : pty->get_specified_bounds ())
 	{
-	  const Resolver::TraitReference *specified_bound_ref = bound.get ();
-
-	  // setup any associated type mappings for the specified bonds and this
-	  // type
-	  auto candidates = Resolver::TypeBoundsProbe::Probe (binding);
-	  std::vector<Resolver::AssociatedImplTrait *> associated_impl_traits;
-	  for (auto &probed_bound : candidates)
+	  bool error_flag = false;
+	  auto associated
+	    = lookup_associated_impl (subst, bound, binding, &error_flag);
+	  if (associated != nullptr)
 	    {
-	      const Resolver::TraitReference *bound_trait_ref
-		= probed_bound.first;
-	      const HIR::ImplBlock *associated_impl = probed_bound.second;
-
-	      HirId impl_block_id
-		= associated_impl->get_mappings ().get_hirid ();
-	      Resolver::AssociatedImplTrait *associated = nullptr;
-	      bool found_impl_trait
-		= context->lookup_associated_trait_impl (impl_block_id,
-							 &associated);
-	      if (found_impl_trait)
-		{
-		  bool found_trait
-		    = specified_bound_ref->is_equal (*bound_trait_ref);
-		  bool found_self
-		    = associated->get_self ()->can_eq (binding, false);
-		  if (found_trait && found_self)
-		    {
-		      associated_impl_traits.push_back (associated);
-		    }
-		}
+	      associated->setup_associated_types (binding, bound);
 	    }
 
-	  if (!associated_impl_traits.empty ())
-	    {
-	      // This code is important when you look at slices for example when
-	      // you have a slice such as:
-	      //
-	      // let slice = &array[1..3]
-	      //
-	      // the higher ranked bounds will end up having an Index trait
-	      // implementation for Range<usize> so we need this code to resolve
-	      // that we have an integer inference variable that needs to become
-	      // a usize
-	      //
-	      // The other complicated issue is that we might have an intrinsic
-	      // which requires the :Clone or Copy bound but the libcore adds
-	      // implementations for all the integral types so when there are
-	      // multiple candidates we need to resolve to the default
-	      // implementation for that type otherwise its an error for
-	      // ambiguous type bounds
-
-	      if (associated_impl_traits.size () == 1)
-		{
-		  Resolver::AssociatedImplTrait *associate_impl_trait
-		    = associated_impl_traits.at (0);
-		  associate_impl_trait->setup_associated_types (binding, bound);
-		}
-	      else
-		{
-		  // if we have a non-general inference variable we need to be
-		  // careful about the selection here
-		  bool is_infer_var
-		    = binding->get_kind () == TyTy::TypeKind::INFER;
-		  bool is_integer_infervar
-		    = is_infer_var
-		      && static_cast<const TyTy::InferType *> (binding)
-			     ->get_infer_kind ()
-			   == TyTy::InferType::InferTypeKind::INTEGRAL;
-		  bool is_float_infervar
-		    = is_infer_var
-		      && static_cast<const TyTy::InferType *> (binding)
-			     ->get_infer_kind ()
-			   == TyTy::InferType::InferTypeKind::FLOAT;
-
-		  Resolver::AssociatedImplTrait *associate_impl_trait = nullptr;
-		  if (is_integer_infervar)
-		    {
-		      TyTy::BaseType *type = nullptr;
-		      bool ok = context->lookup_builtin ("i32", &type);
-		      rust_assert (ok);
-
-		      for (auto &impl : associated_impl_traits)
-			{
-			  bool found = impl->get_self ()->is_equal (*type);
-			  if (found)
-			    {
-			      associate_impl_trait = impl;
-			      break;
-			    }
-			}
-		    }
-		  else if (is_float_infervar)
-		    {
-		      TyTy::BaseType *type = nullptr;
-		      bool ok = context->lookup_builtin ("f64", &type);
-		      rust_assert (ok);
-
-		      for (auto &impl : associated_impl_traits)
-			{
-			  bool found = impl->get_self ()->is_equal (*type);
-			  if (found)
-			    {
-			      associate_impl_trait = impl;
-			      break;
-			    }
-			}
-		    }
-
-		  if (associate_impl_trait == nullptr)
-		    {
-		      // go for the first one? or error out?
-		      auto &mappings = *Analysis::Mappings::get ();
-		      const auto &type_param = subst.get_generic_param ();
-		      const auto *trait_ref = bound.get ();
-
-		      RichLocation r (type_param.get_locus ());
-		      r.add_range (bound.get_locus ());
-		      r.add_range (
-			mappings.lookup_location (binding->get_ref ()));
-
-		      rust_error_at (
-			r, "ambiguous type bound for trait %s and type %s",
-			trait_ref->get_name ().c_str (),
-			binding->get_name ().c_str ());
-
-		      return false;
-		    }
-
-		  associate_impl_trait->setup_associated_types (binding, bound);
-		}
-	    }
+	  if (error_flag)
+	    return false;
 	}
     }
 
diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h
index fd5826102b3..365fdb6c042 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.h
+++ b/gcc/rust/typecheck/rust-tyty-subst.h
@@ -298,7 +298,13 @@ public:
   // TODO comment
   BaseType *infer_substitions (Location locus);
 
-  // TODO comment
+  // this clears any possible projections from higher ranked trait bounds which
+  // could be hanging around from a previous resolution
+  void prepare_higher_ranked_bounds ();
+
+  // FIXME
+  // this is bad name for this, i think it should be something like
+  // compute-higher-ranked-bounds
   bool monomorphize ();
 
   // TODO comment
@@ -308,6 +314,10 @@ public:
   SubstitutionArgumentMappings get_used_arguments () const;
 
 protected:
+  Resolver::AssociatedImplTrait *lookup_associated_impl (
+    const SubstitutionParamMapping &subst, const TypeBoundPredicate &bound,
+    const TyTy::BaseType *binding, bool *error_flag) const;
+
   std::vector<SubstitutionParamMapping> substitutions;
   SubstitutionArgumentMappings used_arguments;
 };
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index fe5aa2b059c..d0d36ac0a11 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -31,6 +31,7 @@
 #include "rust-hir-type-bounds.h"
 #include "rust-hir-trait-resolve.h"
 #include "rust-tyty-cmp.h"
+#include "rust-type-util.h"
 
 #include "options.h"
 
@@ -266,6 +267,7 @@ BaseType::get_locus () const
   return ident.locus;
 }
 
+// FIXME this is missing locus
 bool
 BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
 {
@@ -277,12 +279,67 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
 	return true;
     }
 
+  bool satisfied = false;
   auto probed = Resolver::TypeBoundsProbe::Probe (this);
   for (const auto &b : probed)
     {
       const Resolver::TraitReference *bound = b.first;
       if (bound->satisfies_bound (*query))
+	{
+	  satisfied = true;
+	  break;
+	}
+    }
+
+  if (!satisfied)
+    return false;
+
+  for (const auto &b : probed)
+    {
+      const Resolver::TraitReference *bound = b.first;
+      if (!bound->is_equal (*query))
+	continue;
+
+      // builtin ones have no impl-block this needs fixed and use a builtin node
+      // of somekind
+      if (b.second == nullptr)
 	return true;
+
+      // need to check that associated types can match as well
+      const HIR::ImplBlock &impl = *(b.second);
+      for (const auto &item : impl.get_impl_items ())
+	{
+	  TyTy::BaseType *impl_item_ty = nullptr;
+	  Analysis::NodeMapping i = item->get_impl_mappings ();
+	  bool query_ok = Resolver::query_type (i.get_hirid (), &impl_item_ty);
+	  if (!query_ok)
+	    return false;
+
+	  std::string item_name = item->get_impl_item_name ();
+	  TypeBoundPredicateItem lookup
+	    = predicate.lookup_associated_item (item_name);
+	  if (lookup.is_error ())
+	    return false;
+
+	  const auto *item_ref = lookup.get_raw_item ();
+	  TyTy::BaseType *bound_ty = item_ref->get_tyty ();
+
+	  // compare the types
+	  if (!bound_ty->can_eq (impl_item_ty, false))
+	    {
+	      RichLocation r (mappings->lookup_location (get_ref ()));
+	      r.add_range (predicate.get_locus ());
+	      r.add_range (mappings->lookup_location (i.get_hirid ()));
+
+	      rust_error_at (
+		r, "expected %<%s%> got %<%s%>",
+		bound_ty->destructure ()->get_name ().c_str (),
+		impl_item_ty->destructure ()->get_name ().c_str ());
+	      return false;
+	    }
+	}
+
+      return true;
     }
 
   return false;
@@ -2827,18 +2884,18 @@ ParamType::ParamType (std::string symbol, Location locus, HirId ref,
 	      {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
 	       locus},
 	      specified_bounds, refs),
-    symbol (symbol), param (param)
+    is_trait_self (false), symbol (symbol), param (param)
 {}
 
-ParamType::ParamType (std::string symbol, Location locus, HirId ref,
-		      HirId ty_ref, HIR::GenericParam &param,
+ParamType::ParamType (bool is_trait_self, std::string symbol, Location locus,
+		      HirId ref, HirId ty_ref, HIR::GenericParam &param,
 		      std::vector<TypeBoundPredicate> specified_bounds,
 		      std::set<HirId> refs)
   : BaseType (ref, ty_ref, TypeKind::PARAM,
 	      {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
 	       locus},
 	      specified_bounds, refs),
-    symbol (symbol), param (param)
+    is_trait_self (is_trait_self), symbol (symbol), param (param)
 {}
 
 HIR::GenericParam &
@@ -2906,8 +2963,9 @@ ParamType::can_eq (const BaseType *other, bool emit_errors) const
 BaseType *
 ParamType::clone () const
 {
-  return new ParamType (get_symbol (), ident.locus, get_ref (), get_ty_ref (),
-			param, get_specified_bounds (), get_combined_refs ());
+  return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (),
+			get_ty_ref (), param, get_specified_bounds (),
+			get_combined_refs ());
 }
 
 BaseType *
@@ -2997,6 +3055,18 @@ ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
   return p;
 }
 
+void
+ParamType::set_implicit_self_trait ()
+{
+  is_trait_self = true;
+}
+
+bool
+ParamType::is_implicit_self_trait () const
+{
+  return is_trait_self;
+}
+
 // StrType
 
 StrType::StrType (HirId ref, std::set<HirId> refs)
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index d2cf5b07fc1..64b9379a1c0 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -267,8 +267,8 @@ public:
 	     std::vector<TypeBoundPredicate> specified_bounds,
 	     std::set<HirId> refs = std::set<HirId> ());
 
-  ParamType (std::string symbol, Location locus, HirId ref, HirId ty_ref,
-	     HIR::GenericParam &param,
+  ParamType (bool is_trait_self, std::string symbol, Location locus, HirId ref,
+	     HirId ty_ref, HIR::GenericParam &param,
 	     std::vector<TypeBoundPredicate> specified_bounds,
 	     std::set<HirId> refs = std::set<HirId> ());
 
@@ -298,7 +298,11 @@ public:
 
   ParamType *handle_substitions (SubstitutionArgumentMappings &mappings);
 
+  void set_implicit_self_trait ();
+  bool is_implicit_self_trait () const;
+
 private:
+  bool is_trait_self;
   std::string symbol;
   HIR::GenericParam &param;
 };
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 1fc32038d19..a9687040144 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -96,9 +96,16 @@ static const HirId kDefaultCrateNumBegin = 0;
 Mappings::Mappings ()
   : crateNumItr (kDefaultCrateNumBegin), currentCrateNum (UNKNOWN_CREATENUM),
     hirIdIter (kDefaultHirIdBegin), nodeIdIter (kDefaultNodeIdBegin)
-{}
+{
+  Analysis::NodeMapping node (0, 0, 0, 0);
+  builtinMarker
+    = new HIR::ImplBlock (node, {}, {}, nullptr, nullptr, HIR::WhereClause ({}),
+			  Positive,
+			  HIR::Visibility (HIR::Visibility::VisType::PUBLIC),
+			  {}, {}, Location ());
+}
 
-Mappings::~Mappings () {}
+Mappings::~Mappings () { delete builtinMarker; }
 
 Mappings *
 Mappings::get ()
@@ -1035,5 +1042,11 @@ Mappings::lookup_ast_item (NodeId id, AST::Item **result)
   return true;
 }
 
+HIR::ImplBlock *
+Mappings::lookup_builtin_marker ()
+{
+  return builtinMarker;
+}
+
 } // namespace Analysis
 } // namespace Rust
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 13cae717031..9d6affa27e0 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -296,6 +296,8 @@ public:
   void insert_ast_item (AST::Item *item);
   bool lookup_ast_item (NodeId id, AST::Item **result);
 
+  HIR::ImplBlock *lookup_builtin_marker ();
+
 private:
   Mappings ();
 
@@ -304,6 +306,7 @@ private:
   HirId hirIdIter;
   NodeId nodeIdIter;
   std::map<CrateNum, LocalDefId> localIdIter;
+  HIR::ImplBlock *builtinMarker;
 
   std::map<NodeId, CrateNum> crate_node_to_crate_num;
   std::map<CrateNum, AST::Crate *> ast_crate_mappings;
diff --git a/gcc/testsuite/rust/compile/issue-1725-1.rs b/gcc/testsuite/rust/compile/issue-1725-1.rs
new file mode 100644
index 00000000000..1ace9fbbf30
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1725-1.rs
@@ -0,0 +1,19 @@
+mod core {
+    mod ops {
+        #[lang = "add"]
+        pub trait Add<Rhs = Self> {
+            type Output;
+
+            fn add(self, rhs: Rhs) -> Self::Output;
+        }
+    }
+}
+
+pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {
+    a + a
+}
+
+pub fn main() {
+    foo(123f32);
+    // { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/issue-1725-2.rs b/gcc/testsuite/rust/compile/issue-1725-2.rs
new file mode 100644
index 00000000000..8bfd0bbd924
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1725-2.rs
@@ -0,0 +1,28 @@
+mod core {
+    mod ops {
+        #[lang = "add"]
+        pub trait Add<Rhs = Self> {
+            type Output;
+
+            fn add(self, rhs: Rhs) -> Self::Output;
+        }
+    }
+}
+
+impl core::ops::Add for f32 {
+    type Output = f32;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        self + rhs
+    }
+}
+
+pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {
+    a + a
+}
+
+pub fn main() {
+    foo(123f32);
+    // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 }
+    // { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-2 }
+}
