public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] MethodResolution should respect the autoderef cycle
@ 2022-06-08 12:00 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:00 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ee794effe3b55d2aa8acc108fb36bd8d05672dfa

commit ee794effe3b55d2aa8acc108fb36bd8d05672dfa
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Fri Jan 21 20:01:03 2022 +0000

    MethodResolution should respect the autoderef cycle
    
    Autoderef includes calling into the deref operator overloads so for
    example.
    
    ```rust
    pub trait Deref {
        type Target;
    
        fn deref(&self) -> &Self::Target;
    }
    
    impl<T> Deref for &T {
        type Target = T;
    
        fn deref(&self) -> &T {
            *self
        }
    }
    
    struct Bar(i32);
    impl Bar {
        fn foobar(self) -> i32 {
            self.0
        }
    }
    
    struct Foo<T>(T);
    impl<T> Deref for Foo<T> {
        type Target = T;
    
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    
    fn main() {
        let bar = Bar(123);
        let foo: Foo<&Bar> = Foo(&bar);
        let foobar: i32 = foo.foobar();
    }
    
    ```
    
    So you can see here we have a nested structure of Foo<&Bar> and Foo is a
    generic structure, and we have a method call of foo.foobar(). This is an
    interesting case of method resolution showing how rust allows for multiple
    dereference to find the apropriate method of foobar.
    
    So in this method call expression foo is of type Foo<&Bar> the generic
    structure is a covariant Reference Type (&) of the structure Bar. The
    method foobar has a receiver type of a simple Bar being passed by value.
    
    So in order for this function to be called the method resolution system
    has an algorithm of:
    
    - reciever = Foo<&Bar>
    - Find all methods named foobar
    - try and match the receiver (self) with this reciever
    - so that means we have Foo<&Bar> vs Bar which does not match
    - Go back to the start and try by taking an immutable refernece
    - &Foo<&Bar> does not match Bar
    - Go back to the start and try by taking a mutable reference
    - &mut Foo<&Bar> does not match Bar
    - Try and dereference the original receiver Foo<&Bar>
    - Do we have the deref lang item defined
    - if yes resolve the method by the same mechanism for Foo<&Bar> for deref
    - Get the result type of this function which is &&Bar do the dereference
    - Now we have &Bar and a new adjustment for the original receiver
    - Try and match &Bar to the foobar method reciever of Bar
    - Try taking an immutable reference &&Bar
    - Try taking a mutable reference &mut &Bar
    - Try and deref &Bar we have the generic implementation of deref for &T
    - Call this derefernece like before to get down to Bar
    - Now try Bar on the foobar reciever Bar and it matches
    
    We have now resolved the method with two dereference adjustments so the
    function call becomes:
    
    ```
    void main ()
    {
      i32 D.110;
      const struct  bar;
      const struct  foo;
      const i32 foobar;
      try
        {
          bar.0 = 123;
          foo.0 = &bar;
          RUSTTMP.3 = <Foo as Deref>::deref<&Bar> (&foo);
          RUSTTMP.5 = <&T as Deref>::deref<Bar> (RUSTTMP.3);
          foobar = Bar::foobar (*RUSTTMP.5);
        }
      finally
        {
          bar = {CLOBBER};
          foo = {CLOBBER};
        }
    }
    ```
    
    Obviously GCC will optimize this with -O2 so that it does not require
    function calls but the gimple will show us what is actually going on. As
    far as I am aware rustc pre-optimizes this regardless of optimizations
    being turned on or not, these lang item functions are easily inlineable
    so it makes more sense to me to let GCC's middle-end take care of this for
    us.
    
    This is a big patch and very difficult to split up as it reimplements our
    method resolution system.
    
    Fixes #884

Diff:
---
 gcc/rust/Make-lang.in                              |   1 +
 gcc/rust/backend/rust-compile-base.h               |  11 +
 gcc/rust/backend/rust-compile-expr.cc              | 249 ++++++---------
 gcc/rust/backend/rust-compile-implitem.h           |  16 +-
 gcc/rust/backend/rust-compile-item.h               |   3 +-
 gcc/rust/backend/rust-compile-resolve-path.cc      |  22 +-
 gcc/rust/backend/rust-compile-resolve-path.h       |   5 -
 gcc/rust/backend/rust-compile-var-decl.h           |   1 +
 gcc/rust/backend/rust-compile.cc                   |   5 +-
 gcc/rust/typecheck/rust-autoderef.cc               | 242 ++++++++++++++
 gcc/rust/typecheck/rust-autoderef.h                |  98 +++---
 gcc/rust/typecheck/rust-hir-dot-operator.h         | 349 +++++++++++++++------
 .../typecheck/rust-hir-inherent-impl-overlap.h     |   2 +-
 gcc/rust/typecheck/rust-hir-path-probe.h           |  18 +-
 gcc/rust/typecheck/rust-hir-trait-ref.h            |  26 +-
 gcc/rust/typecheck/rust-hir-type-check-expr.h      | 152 +++------
 gcc/rust/typecheck/rust-hir-type-check-implitem.h  |  59 ++--
 gcc/rust/typecheck/rust-hir-type-check-item.h      |  10 +-
 gcc/rust/typecheck/rust-hir-type-check.h           |   2 +-
 gcc/rust/typecheck/rust-tyty-bounds.cc             |   2 +-
 gcc/rust/typecheck/rust-tyty-cmp.h                 | 145 ++++-----
 gcc/rust/typecheck/rust-tyty-rules.h               |   3 -
 gcc/rust/typecheck/rust-tyty.cc                    | 123 +++-----
 gcc/rust/typecheck/rust-tyty.h                     |  72 ++---
 gcc/testsuite/rust/execute/torture/method2.rs      |  76 +++++
 25 files changed, 1002 insertions(+), 690 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index dcb2d2cafce..f7f248968d6 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -89,6 +89,7 @@ GRS_OBJS = \
     rust/rust-hir-type-check-struct.o \
     rust/rust-hir-address-taken.o \
     rust/rust-hir-type-check-pattern.o \
+    rust/rust-autoderef.o \
     rust/rust-substitution-mapper.o \
     rust/rust-lint-marklive.o \
     rust/rust-hir-type-check-path.o \
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
index e96317605df..902bedce6c4 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -60,6 +60,17 @@ protected:
 
   bool verify_array_capacities (tree ltype, tree rtype, Location ltype_locus,
 				Location rtype_locus);
+
+  tree query_compile (HirId ref, TyTy::BaseType *lookup,
+		      const HIR::PathIdentSegment &final_segment,
+		      const Analysis::NodeMapping &mappings,
+		      Location expr_locus, bool is_qualified_path);
+
+  tree resolve_adjustements (std::vector<Resolver::Adjustment> &adjustments,
+			     tree expression, Location locus);
+
+  tree resolve_deref_adjustment (Resolver::Adjustment &adjustment,
+				 tree expression, Location locus);
 };
 
 } // namespace Compile
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 33237e5f5a9..c58d29d0b6f 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -23,7 +23,6 @@
 #include "rust-hir-trait-resolve.h"
 #include "rust-hir-path-probe.h"
 #include "rust-hir-type-bounds.h"
-#include "rust-hir-dot-operator.h"
 #include "rust-compile-pattern.h"
 #include "rust-constexpr.h"
 
@@ -574,25 +573,9 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
     expr.get_mappings ().get_hirid (), &adjustments);
   rust_assert (ok);
 
-  for (auto &adjustment : *adjustments)
-    {
-      switch (adjustment.get_type ())
-	{
-	case Resolver::Adjustment::AdjustmentType::IMM_REF:
-	case Resolver::Adjustment::AdjustmentType::MUT_REF:
-	  self = ctx->get_backend ()->address_expression (
-	    self, expr.get_receiver ()->get_locus ());
-	  break;
-
-	case Resolver::Adjustment::AdjustmentType::DEREF_REF:
-	  tree expected_type
-	    = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
-	  self = ctx->get_backend ()->indirect_expression (
-	    expected_type, self, true, /* known_valid*/
-	    expr.get_receiver ()->get_locus ());
-	  break;
-	}
-    }
+  // apply adjustments for the fn call
+  self = resolve_adjustements (*adjustments, self,
+			       expr.get_receiver ()->get_locus ());
 
   std::vector<tree> args;
   args.push_back (self); // adjusted self
@@ -737,11 +720,10 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref,
   if (resolved_item != nullptr)
     {
       if (!fntype->has_subsititions_defined ())
-	return CompileInherentImplItem::Compile (receiver, resolved_item, ctx,
-						 true);
+	return CompileInherentImplItem::Compile (resolved_item, ctx, true);
 
-      return CompileInherentImplItem::Compile (receiver, resolved_item, ctx,
-					       true, fntype);
+      return CompileInherentImplItem::Compile (resolved_item, ctx, true,
+					       fntype);
     }
 
   // it might be resolved to a trait item
@@ -785,24 +767,20 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref,
     }
   else
     {
-      std::vector<Resolver::Adjustment> adjustments;
-      Resolver::PathProbeCandidate *candidate
-	= Resolver::MethodResolution::Select (candidates, root, adjustments);
-
       // FIXME this will be a case to return error_mark_node, there is
       // an error scenario where a Trait Foo has a method Bar, but this
       // receiver does not implement this trait or has an incompatible
       // implementation and we should just return error_mark_node
-      rust_assert (candidate != nullptr);
-      rust_assert (candidate->is_impl_candidate ());
 
-      HIR::ImplItem *impl_item = candidate->item.impl.impl_item;
+      rust_assert (candidates.size () == 1);
+      auto &candidate = candidates.at (0);
+      rust_assert (candidate.is_impl_candidate ());
+
+      HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
       if (!fntype->has_subsititions_defined ())
-	return CompileInherentImplItem::Compile (receiver, impl_item, ctx,
-						 true);
+	return CompileInherentImplItem::Compile (impl_item, ctx, true);
 
-      return CompileInherentImplItem::Compile (receiver, impl_item, ctx, true,
-					       fntype);
+      return CompileInherentImplItem::Compile (impl_item, ctx, true, fntype);
     }
 }
 
@@ -868,29 +846,8 @@ CompileExpr::resolve_operator_overload (
     expr.get_mappings ().get_hirid (), &adjustments);
   rust_assert (ok);
 
-  // FIXME refactor this out
-  tree self = lhs;
-  for (auto &adjustment : *adjustments)
-    {
-      switch (adjustment.get_type ())
-	{
-	case Resolver::Adjustment::AdjustmentType::IMM_REF:
-	case Resolver::Adjustment::AdjustmentType::MUT_REF:
-	  self
-	    = ctx->get_backend ()->address_expression (self,
-						       lhs_expr->get_locus ());
-	  break;
-
-	case Resolver::Adjustment::AdjustmentType::DEREF_REF:
-	  tree expected_type
-	    = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
-	  self
-	    = ctx->get_backend ()->indirect_expression (expected_type, self,
-							true, /* known_valid*/
-							lhs_expr->get_locus ());
-	  break;
-	}
-    }
+  // apply adjustments for the fn call
+  tree self = resolve_adjustements (*adjustments, lhs, lhs_expr->get_locus ());
 
   std::vector<tree> args;
   args.push_back (self); // adjusted self
@@ -1221,106 +1178,82 @@ CompileExpr::array_copied_expr (Location expr_locus,
 							    expr_locus);
 }
 
-// tree
-// CompileExpr::array_copied_expr (Location expr_locus, tree array_type,
-// 				HIR::ArrayElemsCopied &elems)
-// {
-//   // create tmp for the result
-//   fncontext fnctx = ctx->peek_fn ();
-//   Location start_location = expr_locus;
-//   Location end_location = expr_locus;
-//   tree fndecl = fnctx.fndecl;
-//   tree enclosing_scope = ctx->peek_enclosing_scope ();
-
-//   bool is_address_taken = false;
-//   tree result_var_stmt = nullptr;
-//   Bvariable *result
-//     = ctx->get_backend ()->temporary_variable (fnctx.fndecl,
-//     enclosing_scope,
-// 					       array_type, NULL,
-// 					       is_address_taken, expr_locus,
-// 					       &result_var_stmt);
-//   ctx->add_statement (result_var_stmt);
-
-//   // get the compiled value
-//   tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (),
-//   ctx);
-
-//   // lets assign each index in the array
-//   TyTy::BaseType *capacity_tyty = nullptr;
-//   HirId capacity_ty_id
-//     = elems.get_num_copies_expr ()->get_mappings ().get_hirid ();
-//   bool ok = ctx->get_tyctx ()->lookup_type (capacity_ty_id,
-//   &capacity_tyty); rust_assert (ok); tree capacity_type =
-//   TyTyResolveCompile::compile (ctx, capacity_tyty); tree capacity_expr =
-//   CompileExpr::Compile (elems.get_num_copies_expr (), ctx);
-
-//   // create a loop for this with assignments to array_index exprs
-//   tree index_type = capacity_type;
-//   Bvariable *idx
-//     = ctx->get_backend ()->temporary_variable (fnctx.fndecl,
-//     enclosing_scope,
-// 					       index_type, NULL,
-// 					       is_address_taken, expr_locus,
-// 					       &result_var_stmt);
-//   ctx->add_statement (result_var_stmt);
-
-//   // set index to zero
-//   tree index_lvalue = error_mark_node;
-//   tree zero = build_int_cst (index_type, 0);
-//   tree index_assignment
-//     = ctx->get_backend ()->assignment_statement (fnctx.fndecl,
-//     index_lvalue,
-// 						 zero, expr_locus);
-//   ctx->add_statement (index_assignment);
-
-//   // BEGIN loop block
-//   tree loop_body = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
-// 					       start_location, end_location);
-//   ctx->push_block (loop_body);
-
-//   // loop predicate
-//   tree loop_predicate
-//     = fold_build2_loc (expr_locus.gcc_location (), GE_EXPR,
-//     boolean_type_node,
-// 		       ctx->get_backend ()->var_expression (idx, expr_locus),
-// 		       capacity_expr);
-//   tree exit_expr = fold_build1_loc (expr_locus.gcc_location (), EXIT_EXPR,
-// 				    void_type_node, loop_predicate);
-//   tree break_stmt
-//     = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr);
-//   ctx->add_statement (break_stmt);
-
-//   // increment index
-//   tree increment
-//     = fold_build2_loc (expr_locus.gcc_location (), POSTINCREMENT_EXPR,
-// 		       index_type,
-// 		       ctx->get_backend ()->var_expression (idx, expr_locus),
-// 		       build_int_cst (index_type, 1));
-
-//   // create index_assess
-//   tree index_access = ctx->get_backend ()->array_index_expression (
-//     ctx->get_backend ()->var_expression (result, expr_locus), increment,
-//     expr_locus);
-
-//   // create assignment to index_access
-//   tree array_assignment
-//     = ctx->get_backend ()->assignment_statement (fnctx.fndecl,
-//     index_access,
-// 						 translated_expr, expr_locus);
-//   ctx->add_statement (array_assignment);
-
-//   // END loop block
-//   ctx->pop_block ();
-
-//   tree loop_expr = ctx->get_backend ()->loop_expression (loop_body,
-//   expr_locus); tree loop_stmt
-//     = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr);
-//   ctx->add_statement (loop_stmt);
-
-//   // result is the tmp
-//   return ctx->get_backend ()->var_expression (result, expr_locus);
-// }
+tree
+HIRCompileBase::resolve_adjustements (
+  std::vector<Resolver::Adjustment> &adjustments, tree expression,
+  Location locus)
+{
+  tree e = expression;
+  for (auto &adjustment : adjustments)
+    {
+      switch (adjustment.get_type ())
+	{
+	case Resolver::Adjustment::AdjustmentType::ERROR:
+	  return error_mark_node;
+
+	case Resolver::Adjustment::AdjustmentType::IMM_REF:
+	case Resolver::Adjustment::AdjustmentType::MUT_REF:
+	  e = ctx->get_backend ()->address_expression (e, locus);
+	  break;
+
+	case Resolver::Adjustment::AdjustmentType::DEREF_REF:
+	  e = resolve_deref_adjustment (adjustment, e, locus);
+	  break;
+	}
+    }
+
+  return e;
+}
+
+tree
+HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
+					  tree expression, Location locus)
+{
+  rust_assert (adjustment.is_deref_adjustment ());
+
+  tree expected_type
+    = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
+  if (!adjustment.has_operator_overload ())
+    {
+      return ctx->get_backend ()->indirect_expression (expected_type,
+						       expression,
+						       true, /* known_valid*/
+						       locus);
+    }
+
+  TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
+  HIR::ImplItem *resolved_item = adjustment.get_deref_hir_item ();
+
+  tree fn_address = error_mark_node;
+  if (!lookup->has_subsititions_defined ())
+    fn_address = CompileInherentImplItem::Compile (resolved_item, ctx, true,
+						   nullptr, true, locus);
+  else
+    fn_address = CompileInherentImplItem::Compile (resolved_item, ctx, true,
+						   lookup, true, locus);
+
+  // does it need a reference to call
+  tree adjusted_argument = expression;
+  bool needs_borrow = adjustment.get_deref_adjustment_type ()
+		      != Resolver::Adjustment::AdjustmentType::ERROR;
+  if (needs_borrow)
+    {
+      adjusted_argument
+	= ctx->get_backend ()->address_expression (expression, locus);
+    }
+
+  // make the call
+  auto fncontext = ctx->peek_fn ();
+  tree deref_call
+    = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address,
+					    {adjusted_argument}, nullptr,
+					    locus);
+
+  // do the indirect expression
+  return ctx->get_backend ()->indirect_expression (expected_type, deref_call,
+						   true, /* known_valid*/
+						   locus);
+}
 
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h
index 7bef6ae9e02..82b7c6dbffa 100644
--- a/gcc/rust/backend/rust-compile-implitem.h
+++ b/gcc/rust/backend/rust-compile-implitem.h
@@ -34,14 +34,12 @@ class CompileInherentImplItem : public HIRCompileBase
   using Rust::Compile::HIRCompileBase::visit;
 
 public:
-  static tree Compile (const TyTy::BaseType *self, HIR::ImplItem *item,
-		       Context *ctx, bool compile_fns,
+  static tree Compile (HIR::ImplItem *item, Context *ctx, bool compile_fns,
 		       TyTy::BaseType *concrete = nullptr,
 		       bool is_query_mode = false,
 		       Location ref_locus = Location ())
   {
-    CompileInherentImplItem compiler (self, ctx, compile_fns, concrete,
-				      ref_locus);
+    CompileInherentImplItem compiler (ctx, compile_fns, concrete, ref_locus);
     item->accept_vis (compiler);
 
     if (is_query_mode
@@ -307,15 +305,13 @@ public:
   }
 
 private:
-  CompileInherentImplItem (const TyTy::BaseType *self, Context *ctx,
-			   bool compile_fns, TyTy::BaseType *concrete,
-			   Location ref_locus)
-    : HIRCompileBase (ctx), self (self), compile_fns (compile_fns),
-      concrete (concrete), reference (ctx->get_backend ()->error_expression ()),
+  CompileInherentImplItem (Context *ctx, bool compile_fns,
+			   TyTy::BaseType *concrete, Location ref_locus)
+    : HIRCompileBase (ctx), compile_fns (compile_fns), concrete (concrete),
+      reference (ctx->get_backend ()->error_expression ()),
       ref_locus (ref_locus)
   {}
 
-  const TyTy::BaseType *self;
   bool compile_fns;
   TyTy::BaseType *concrete;
   tree reference;
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h
index c35efccf79a..b3c5ba8eb16 100644
--- a/gcc/rust/backend/rust-compile-item.h
+++ b/gcc/rust/backend/rust-compile-item.h
@@ -395,8 +395,7 @@ public:
       }
 
     for (auto &impl_item : impl_block.get_impl_items ())
-      CompileInherentImplItem::Compile (self_lookup, impl_item.get (), ctx,
-					compile_fns);
+      CompileInherentImplItem::Compile (impl_item.get (), ctx, compile_fns);
   }
 
   void visit (HIR::ExternBlock &extern_block) override
diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc
index c1d0778ff5e..5c727d6df2d 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.cc
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -152,10 +152,10 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
   // let the query system figure it out
   return query_compile (ref, lookup, final_segment, mappings, expr_locus,
 			is_qualified_path);
-} // namespace Compile
+}
 
 tree
-ResolvePathRef::query_compile (HirId ref, TyTy::BaseType *lookup,
+HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
 			       const HIR::PathIdentSegment &final_segment,
 			       const Analysis::NodeMapping &mappings,
 			       Location expr_locus, bool is_qualified_path)
@@ -194,13 +194,11 @@ ResolvePathRef::query_compile (HirId ref, TyTy::BaseType *lookup,
 	  rust_assert (ok);
 
 	  if (!lookup->has_subsititions_defined ())
-	    return CompileInherentImplItem::Compile (self, resolved_item, ctx,
-						     true, nullptr, true,
-						     expr_locus);
+	    return CompileInherentImplItem::Compile (resolved_item, ctx, true,
+						     nullptr, true, expr_locus);
 	  else
-	    return CompileInherentImplItem::Compile (self, resolved_item, ctx,
-						     true, lookup, true,
-						     expr_locus);
+	    return CompileInherentImplItem::Compile (resolved_item, ctx, true,
+						     lookup, true, expr_locus);
 	}
       else
 	{
@@ -278,12 +276,12 @@ ResolvePathRef::query_compile (HirId ref, TyTy::BaseType *lookup,
 	      rust_assert (ok);
 
 	      if (!lookup->has_subsititions_defined ())
-		return CompileInherentImplItem::Compile (self, impl_item, ctx,
-							 true, nullptr, true,
+		return CompileInherentImplItem::Compile (impl_item, ctx, true,
+							 nullptr, true,
 							 expr_locus);
 	      else
-		return CompileInherentImplItem::Compile (self, impl_item, ctx,
-							 true, lookup, true,
+		return CompileInherentImplItem::Compile (impl_item, ctx, true,
+							 lookup, true,
 							 expr_locus);
 
 	      lookup->set_ty_ref (impl_item->get_impl_mappings ().get_hirid ());
diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h
index 56f82d1e6bc..97a79e27d49 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.h
+++ b/gcc/rust/backend/rust-compile-resolve-path.h
@@ -57,11 +57,6 @@ private:
 		const Analysis::NodeMapping &mappings, Location locus,
 		bool is_qualified_path);
 
-  tree query_compile (HirId ref, TyTy::BaseType *lookup,
-		      const HIR::PathIdentSegment &final_segment,
-		      const Analysis::NodeMapping &mappings,
-		      Location expr_locus, bool is_qualified_path);
-
   tree resolved;
 };
 
diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h
index 4b52dcd4346..51affe04c4c 100644
--- a/gcc/rust/backend/rust-compile-var-decl.h
+++ b/gcc/rust/backend/rust-compile-var-decl.h
@@ -49,6 +49,7 @@ public:
 
     address_taken_context->lookup_addess_taken (
       stmt.get_mappings ().get_hirid (), &address_taken);
+
     translated_type = TyTyResolveCompile::compile (ctx, resolved_type);
     stmt.get_pattern ()->accept_vis (*this);
   }
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index a97ad4d2d90..b17c4384bb6 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -528,9 +528,8 @@ HIRCompileBase::compute_address_for_trait_item (
 	  lookup_fntype = lookup_fntype->handle_substitions (mappings);
 	}
 
-      return CompileInherentImplItem::Compile (root, associated_function, ctx,
-					       true, lookup_fntype, true,
-					       locus);
+      return CompileInherentImplItem::Compile (associated_function, ctx, true,
+					       lookup_fntype, true, locus);
     }
 
   // we can only compile trait-items with a body
diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc
new file mode 100644
index 00000000000..44f09061bba
--- /dev/null
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -0,0 +1,242 @@
+// Copyright (C) 2020-2021 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-autoderef.h"
+#include "rust-hir-path-probe.h"
+#include "rust-hir-dot-operator.h"
+
+namespace Rust {
+namespace Resolver {
+
+static bool
+resolve_operator_overload_fn (
+  Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
+  TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
+  Adjustment::AdjustmentType *requires_ref_adjustment);
+
+bool
+Adjuster::needs_address (const std::vector<Adjustment> &adjustments)
+{
+  for (auto &adjustment : adjustments)
+    {
+      switch (adjustment.get_type ())
+	{
+	case Adjustment::AdjustmentType::IMM_REF:
+	case Adjustment::AdjustmentType::MUT_REF:
+	case Adjustment::AdjustmentType::DEREF_REF:
+	  return true;
+
+	default:
+	  break;
+	}
+    }
+
+  return false;
+}
+
+TyTy::BaseType *
+Adjuster::adjust_type (const std::vector<Adjustment> &adjustments)
+{
+  if (adjustments.size () == 0)
+    return base->clone ();
+
+  return adjustments.back ().get_expected ()->clone ();
+}
+
+Adjustment
+Adjuster::try_deref_type (const TyTy::BaseType *ty)
+{
+  // probe for the lang-item
+  TyTy::BaseType *resolved_base = ty->clone ();
+
+  HIR::ImplItem *impl_item = nullptr;
+  TyTy::FnType *fn = nullptr;
+  Adjustment::AdjustmentType requires_ref_adjustment
+    = Adjustment::AdjustmentType::ERROR;
+  bool operator_overloaded
+    = resolve_operator_overload_fn (Analysis::RustLangItem::ItemType::DEREF, ty,
+				    &fn, &impl_item, &requires_ref_adjustment);
+  if (operator_overloaded)
+    {
+      resolved_base = fn->get_return_type ()->clone ();
+    }
+
+  bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF;
+  if (!is_valid_type)
+    return Adjustment::get_error ();
+
+  TyTy::ReferenceType *ref_base
+    = static_cast<TyTy::ReferenceType *> (resolved_base);
+
+  auto infered = ref_base->get_base ()->clone ();
+
+  return Adjustment::get_op_overload_deref_adjustment (infered, fn, impl_item,
+						       requires_ref_adjustment);
+}
+
+static bool
+resolve_operator_overload_fn (
+  Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
+  TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
+  Adjustment::AdjustmentType *requires_ref_adjustment)
+{
+  auto context = TypeCheckContext::get ();
+  auto mappings = Analysis::Mappings::get ();
+
+  // look up lang item for arithmetic type
+  std::string associated_item_name
+    = Analysis::RustLangItem::ToString (lang_item_type);
+  DefId respective_lang_item_id = UNKNOWN_DEFID;
+  bool lang_item_defined
+    = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+  if (!lang_item_defined)
+    return false;
+
+  auto segment = HIR::PathIdentSegment (associated_item_name);
+  auto candidate
+    = MethodResolver::Probe (ty, HIR::PathIdentSegment (associated_item_name),
+			     true);
+
+  bool have_implementation_for_lang_item = !candidate.is_error ();
+  if (!have_implementation_for_lang_item)
+    return false;
+
+  // Get the adjusted self
+  Adjuster adj (ty);
+  TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
+
+  // is this the case we are recursive
+  // handle the case where we are within the impl block for this
+  // lang_item otherwise we end up with a recursive operator overload
+  // such as the i32 operator overload trait
+  TypeCheckContextItem &fn_context = context->peek_context ();
+  if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
+    {
+      auto &impl_item = fn_context.get_impl_item ();
+      HIR::ImplBlock *parent = impl_item.first;
+      HIR::Function *fn = impl_item.second;
+
+      if (parent->has_trait_ref ()
+	  && fn->get_function_name ().compare (associated_item_name) == 0)
+	{
+	  TraitReference *trait_reference
+	    = TraitResolver::Lookup (*parent->get_trait_ref ().get ());
+	  if (!trait_reference->is_error ())
+	    {
+	      TyTy::BaseType *lookup = nullptr;
+	      bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
+					      &lookup);
+	      rust_assert (ok);
+	      rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+
+	      TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
+	      rust_assert (fntype->is_method ());
+
+	      bool is_lang_item_impl
+		= trait_reference->get_mappings ().get_defid ()
+		  == respective_lang_item_id;
+	      bool self_is_lang_item_self
+		= fntype->get_self_type ()->is_equal (*adjusted_self);
+	      bool recursive_operator_overload
+		= is_lang_item_impl && self_is_lang_item_self;
+
+	      if (recursive_operator_overload)
+		return false;
+	    }
+	}
+    }
+
+  TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
+
+  // rust only support impl item deref operator overloading ie you must have an
+  // impl block for it
+  rust_assert (candidate.candidate.type
+	       == PathProbeCandidate::CandidateType::IMPL_FUNC);
+  *impl_item = candidate.candidate.item.impl.impl_item;
+
+  rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+  TyTy::BaseType *lookup = lookup_tyty;
+  TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+  rust_assert (fn->is_method ());
+
+  if (fn->needs_substitution ())
+    {
+      if (ty->get_kind () == TyTy::TypeKind::ADT)
+	{
+	  const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (ty);
+
+	  auto s = fn->get_self_type ()->get_root ();
+	  rust_assert (s->can_eq (adt, false));
+	  rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
+	  const TyTy::ADTType *self_adt
+	    = static_cast<const TyTy::ADTType *> (s);
+
+	  // we need to grab the Self substitutions as the inherit type
+	  // parameters for this
+	  if (self_adt->needs_substitution ())
+	    {
+	      rust_assert (adt->was_substituted ());
+
+	      TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
+		= GetUsedSubstArgs::From (adt);
+
+	      TyTy::SubstitutionArgumentMappings inherit_type_args
+		= self_adt->solve_mappings_from_receiver_for_self (
+		  used_args_in_prev_segment);
+
+	      // there may or may not be inherited type arguments
+	      if (!inherit_type_args.is_error ())
+		{
+		  // need to apply the inherited type arguments to the
+		  // function
+		  lookup = fn->handle_substitions (inherit_type_args);
+		}
+	    }
+	}
+      else
+	{
+	  rust_assert (candidate.adjustments.size () < 2);
+
+	  // lets infer the params for this we could probably fix this up by
+	  // actually just performing a substitution of a single param but this
+	  // seems more generic i think.
+	  //
+	  // this is the case where we had say Foo<&Bar>> and we have derefed to
+	  // the &Bar and we are trying to match a method self of Bar which
+	  // requires another deref which is matched to the deref trait impl of
+	  // &&T so this requires another reference and deref call
+
+	  lookup = fn->infer_substitions (Location ());
+	  rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+	  fn = static_cast<TyTy::FnType *> (lookup);
+	  fn->get_self_type ()->unify (adjusted_self);
+	  lookup = fn;
+	}
+    }
+
+  if (candidate.adjustments.size () > 0)
+    *requires_ref_adjustment = candidate.adjustments.at (0).get_type ();
+
+  *resolved_fn = static_cast<TyTy::FnType *> (lookup);
+
+  return true;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h
index ef3827d0995..762b3e8673b 100644
--- a/gcc/rust/typecheck/rust-autoderef.h
+++ b/gcc/rust/typecheck/rust-autoderef.h
@@ -29,15 +29,26 @@ class Adjustment
 public:
   enum AdjustmentType
   {
+    ERROR,
+
     IMM_REF,
     MUT_REF,
     DEREF_REF
   };
 
+  // ctor for all adjustments except derefs
   Adjustment (AdjustmentType type, const TyTy::BaseType *expected)
-    : type (type), expected (expected)
+    : Adjustment (type, expected, nullptr, nullptr, AdjustmentType::ERROR)
   {}
 
+  static Adjustment get_op_overload_deref_adjustment (
+    const TyTy::BaseType *expected, TyTy::FnType *fn, HIR::ImplItem *deref_item,
+    Adjustment::AdjustmentType requires_ref_adjustment)
+  {
+    return Adjustment (Adjustment::DEREF_REF, expected, fn, deref_item,
+		       requires_ref_adjustment);
+  }
+
   AdjustmentType get_type () const { return type; }
 
   const TyTy::BaseType *get_expected () const { return expected; }
@@ -52,6 +63,8 @@ public:
   {
     switch (type)
       {
+      case AdjustmentType::ERROR:
+	return "ERROR";
       case AdjustmentType::IMM_REF:
 	return "IMM_REF";
       case AdjustmentType::MUT_REF:
@@ -63,9 +76,41 @@ public:
     return "";
   }
 
+  static Adjustment get_error () { return Adjustment{ERROR, nullptr}; }
+
+  bool is_error () const { return type == ERROR; }
+
+  bool is_deref_adjustment () const { return type == DEREF_REF; }
+
+  bool has_operator_overload () const { return deref_operator_fn != nullptr; }
+
+  TyTy::FnType *get_deref_operator_fn () const { return deref_operator_fn; }
+
+  AdjustmentType get_deref_adjustment_type () const
+  {
+    return requires_ref_adjustment;
+  }
+
+  HIR::ImplItem *get_deref_hir_item () const { return deref_item; }
+
 private:
+  Adjustment (AdjustmentType type, const TyTy::BaseType *expected,
+	      TyTy::FnType *deref_operator_fn, HIR::ImplItem *deref_item,
+	      Adjustment::AdjustmentType requires_ref_adjustment)
+    : type (type), expected (expected), deref_operator_fn (deref_operator_fn),
+      deref_item (deref_item), requires_ref_adjustment (requires_ref_adjustment)
+  {}
+
   AdjustmentType type;
   const TyTy::BaseType *expected;
+
+  // - only used for deref operator_overloads
+  //
+  // the fn that we are calling
+  TyTy::FnType *deref_operator_fn;
+  HIR::ImplItem *deref_item;
+  // operator overloads can requre a reference
+  Adjustment::AdjustmentType requires_ref_adjustment;
 };
 
 class Adjuster
@@ -73,56 +118,11 @@ class Adjuster
 public:
   Adjuster (const TyTy::BaseType *ty) : base (ty) {}
 
-  static bool needs_address (const std::vector<Adjustment> &adjustments)
-  {
-    for (auto &adjustment : adjustments)
-      {
-	switch (adjustment.get_type ())
-	  {
-	  case Adjustment::AdjustmentType::IMM_REF:
-	  case Adjustment::AdjustmentType::MUT_REF:
-	    return true;
-
-	  default:
-	    break;
-	  }
-      }
+  TyTy::BaseType *adjust_type (const std::vector<Adjustment> &adjustments);
 
-    return false;
-  }
+  static bool needs_address (const std::vector<Adjustment> &adjustments);
 
-  TyTy::BaseType *adjust_type (const std::vector<Adjustment> &adjustments)
-  {
-    TyTy::BaseType *ty = base->clone ();
-    for (auto &adjustment : adjustments)
-      {
-	switch (adjustment.get_type ())
-	  {
-	  case Adjustment::AdjustmentType::IMM_REF:
-	    ty = new TyTy::ReferenceType (ty->get_ref (),
-					  TyTy::TyVar (ty->get_ref ()),
-					  Mutability::Imm);
-	    break;
-
-	  case Adjustment::AdjustmentType::MUT_REF:
-	    ty = new TyTy::ReferenceType (ty->get_ref (),
-					  TyTy::TyVar (ty->get_ref ()),
-					  Mutability::Mut);
-	    break;
-
-	  case Adjustment::AdjustmentType::DEREF_REF:
-	    // FIXME this really needs to support deref lang-item operator
-	    // overloads
-	    rust_assert (ty->get_kind () == TyTy::TypeKind::REF);
-	    const TyTy::ReferenceType *rr
-	      = static_cast<const TyTy::ReferenceType *> (ty);
-	    ty = rr->get_base ();
-
-	    break;
-	  }
-      }
-    return ty;
-  }
+  static Adjustment try_deref_type (const TyTy::BaseType *ty);
 
 private:
   const TyTy::BaseType *base;
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
index 067ae2c0d9e..660590277ac 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.h
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -20,161 +20,310 @@
 #define RUST_HIR_DOT_OPERATOR
 
 #include "rust-hir-path-probe.h"
+#include "rust-hir-trait-resolve.h"
 
 namespace Rust {
 namespace Resolver {
 
-// lookup if method exists for current type
-// if exists: done
-// if not: check again for auto-ref and auto-mut-ref
-// deref and start again with 1.*/
+struct MethodCandidate
+{
+  PathProbeCandidate candidate;
+  std::vector<Adjustment> adjustments;
+
+  static MethodCandidate get_error ()
+  {
+    return {PathProbeCandidate::get_error (), {}};
+  }
 
-// https://doc.rust-lang.org/nightly/nomicon/dot-operator.html
+  bool is_error () const { return candidate.is_error (); }
+};
 
-class MethodResolution
+class MethodResolver : public TypeCheckBase
 {
+protected:
+  using Rust::Resolver::TypeCheckBase::visit;
+
 public:
-  static PathProbeCandidate *
-  Select (std::vector<PathProbeCandidate> &candidates,
-	  const TyTy::BaseType *receiver, std::vector<Adjustment> &adjustments)
+  static MethodCandidate Probe (const TyTy::BaseType *receiver,
+				const HIR::PathIdentSegment &segment_name,
+				bool autoderef_flag = false)
   {
     const TyTy::BaseType *r = receiver;
+    std::vector<Adjustment> adjustments;
     while (true)
       {
-	PathProbeCandidate *c = nullptr;
+	PathProbeCandidate c = PathProbeCandidate::get_error ();
+	const std::vector<TyTy::TypeBoundPredicate> &specified_bounds
+	  = r->get_specified_bounds ();
 
 	// 1. try raw
-	c = Try (candidates, r);
-	if (c != nullptr)
-	  return c;
+	MethodResolver raw (*r, segment_name, specified_bounds);
+	c = raw.select ();
+	if (!c.is_error ())
+	  return MethodCandidate{c, adjustments};
 
 	// 2. try ref
 	TyTy::ReferenceType *r1
 	  = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
 				     Mutability::Imm);
-	c = Try (candidates, r1);
-	if (c != nullptr)
+	MethodResolver imm_ref (*r1, segment_name, specified_bounds);
+	c = imm_ref.select ();
+	if (!c.is_error ())
 	  {
 	    adjustments.push_back (
 	      Adjustment (Adjustment::AdjustmentType::IMM_REF, r1));
-	    return c;
+	    return MethodCandidate{c, adjustments};
 	  }
 
 	// 3. try mut ref
 	TyTy::ReferenceType *r2
 	  = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
 				     Mutability::Mut);
-	c = Try (candidates, r2);
-	if (c != nullptr)
+	MethodResolver mut_ref (*r2, segment_name, specified_bounds);
+	c = mut_ref.select ();
+	if (!c.is_error ())
 	  {
 	    adjustments.push_back (
 	      Adjustment (Adjustment::AdjustmentType::MUT_REF, r2));
-	    return c;
+	    return MethodCandidate{c, adjustments};
 	  }
 
 	// 4. deref to to 1, if cannot deref then quit
-	bool can_deref = r->get_kind () == TyTy::TypeKind::REF;
-	if (!can_deref)
-	  return nullptr;
-
-	// FIXME this needs to use deref trait and fall back to unsized to
-	// remove array syntax
-
-	const TyTy::ReferenceType *rr
-	  = static_cast<const TyTy::ReferenceType *> (r);
-	r = rr->get_base ();
-	adjustments.push_back (
-	  Adjustment (Adjustment::AdjustmentType::DEREF_REF, r));
+	if (autoderef_flag)
+	  {
+	    return MethodCandidate::get_error ();
+	  }
+	else
+	  {
+	    Adjustment deref = Adjuster::try_deref_type (r);
+	    if (deref.is_error ())
+	      return MethodCandidate::get_error ();
+
+	    r = deref.get_expected ();
+	    adjustments.push_back (deref);
+	  }
       }
-    return nullptr;
+    return MethodCandidate::get_error ();
   }
 
-private:
-  static PathProbeCandidate *Try (std::vector<PathProbeCandidate> &candidates,
-				  const TyTy::BaseType *receiver)
+protected:
+  PathProbeCandidate select ()
   {
-    TypeCheckContext *context = TypeCheckContext::get ();
+    struct impl_item_candidate
+    {
+      HIR::Function *item;
+      HIR::ImplBlock *impl_block;
+      TyTy::FnType *ty;
+    };
+
+    // assemble inherent impl items
+    std::vector<impl_item_candidate> inherent_impl_fns;
+    mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item,
+				       HIR::ImplBlock *impl) mutable -> bool {
+      bool is_trait_impl = impl->has_trait_ref ();
+      if (is_trait_impl)
+	return true;
+
+      bool is_fn
+	= item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION;
+      if (!is_fn)
+	return true;
+
+      HIR::Function *func = static_cast<HIR::Function *> (item);
+      if (!func->is_method ())
+	return true;
+
+      bool name_matches
+	= func->get_function_name ().compare (segment_name.as_string ()) == 0;
+      if (!name_matches)
+	return true;
+
+      TyTy::BaseType *ty = nullptr;
+      if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+	return true;
+      if (ty->get_kind () == TyTy::TypeKind::ERROR)
+	return true;
+
+      rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+      TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+      inherent_impl_fns.push_back ({func, impl, fnty});
+
+      return true;
+    });
+
+    struct trait_item_candidate
+    {
+      const HIR::TraitItemFunc *item;
+      const HIR::Trait *trait;
+      TyTy::FnType *ty;
+      const TraitReference *reference;
+      const TraitItemReference *item_ref;
+    };
+
+    std::vector<trait_item_candidate> trait_fns;
+    mappings->iterate_impl_blocks ([&] (HirId id,
+					HIR::ImplBlock *impl) mutable -> bool {
+      bool is_trait_impl = impl->has_trait_ref ();
+      if (!is_trait_impl)
+	return true;
+
+      // look for impl implementation else lookup the associated trait item
+      for (auto &impl_item : impl->get_impl_items ())
+	{
+	  bool is_fn = impl_item->get_impl_item_type ()
+		       == HIR::ImplItem::ImplItemType::FUNCTION;
+	  if (!is_fn)
+	    continue;
+
+	  HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
+	  if (!func->is_method ())
+	    continue;
+
+	  bool name_matches
+	    = func->get_function_name ().compare (segment_name.as_string ())
+	      == 0;
+	  if (!name_matches)
+	    continue;
 
-    // probe impls
-    for (auto &c : candidates)
+	  TyTy::BaseType *ty = nullptr;
+	  if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+	    continue;
+	  if (ty->get_kind () == TyTy::TypeKind::ERROR)
+	    continue;
+
+	  rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+	  TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+	  inherent_impl_fns.push_back ({func, impl, fnty});
+	  return true;
+	}
+
+      TraitReference *trait_ref
+	= TraitResolver::Resolve (*impl->get_trait_ref ().get ());
+      rust_assert (!trait_ref->is_error ());
+
+      auto item_ref
+	= trait_ref->lookup_trait_item (segment_name.as_string (),
+					TraitItemReference::TraitItemType::FN);
+      if (item_ref->is_error ())
+	return true;
+
+      const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
+      HIR::TraitItem *item = item_ref->get_hir_trait_item ();
+      rust_assert (item->get_item_kind ()
+		   == HIR::TraitItem::TraitItemKind::FUNC);
+      HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
+
+      TyTy::BaseType *ty = item_ref->get_tyty ();
+      rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+      TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+      trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref};
+      trait_fns.push_back (candidate);
+
+      return true;
+    });
+
+    // lookup specified bounds for an associated item
+    struct precdicate_candidate
+    {
+      TyTy::TypeBoundPredicateItem lookup;
+      TyTy::FnType *fntype;
+    };
+
+    std::vector<precdicate_candidate> predicate_items;
+    for (auto &bound : specified_bounds)
       {
-	bool is_func = c.type == PathProbeCandidate::CandidateType::IMPL_FUNC;
-	HIR::ImplBlock *block = c.item.impl.parent;
-	if (is_func && !block->has_trait_ref ())
+	TyTy::TypeBoundPredicateItem lookup
+	  = bound.lookup_associated_item (segment_name.as_string ());
+	if (lookup.is_error ())
+	  continue;
+
+	bool is_fn = lookup.get_raw_item ()->get_trait_item_type ()
+		     == TraitItemReference::TraitItemType::FN;
+	if (!is_fn)
+	  continue;
+
+	TyTy::BaseType *ty = lookup.get_raw_item ()->get_tyty ();
+	rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+	TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+	precdicate_candidate candidate{lookup, fnty};
+	predicate_items.push_back (candidate);
+      }
+
+    for (auto impl_item : inherent_impl_fns)
+      {
+	TyTy::FnType *fn = impl_item.ty;
+	rust_assert (fn->is_method ());
+
+	TyTy::BaseType *fn_self = fn->get_self_type ();
+	if (fn_self->can_eq (&receiver, false))
 	  {
-	    HIR::Function *func
-	      = static_cast<HIR::Function *> (c.item.impl.impl_item);
-
-	    TyTy::BaseType *lookup = nullptr;
-	    bool ok = context->lookup_type (func->get_mappings ().get_hirid (),
-					    &lookup);
-	    rust_assert (ok);
-	    rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
-
-	    TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
-	    if (fn->is_method ())
-	      {
-		TyTy::BaseType *fn_self = fn->get_self_type ();
-		if (fn_self->can_eq (receiver, false, true))
-		  {
-		    return &c;
-		  }
-	      }
+	    PathProbeCandidate::ImplItemCandidate c{impl_item.item,
+						    impl_item.impl_block};
+	    return PathProbeCandidate (
+	      PathProbeCandidate::CandidateType::IMPL_FUNC, fn,
+	      impl_item.item->get_locus (), c);
 	  }
       }
 
-    // probe trait impls
-    for (auto &c : candidates)
+    for (auto trait_item : trait_fns)
       {
-	bool is_func = c.type == PathProbeCandidate::CandidateType::IMPL_FUNC;
-	HIR::ImplBlock *block = c.item.impl.parent;
-	if (is_func && block->has_trait_ref ())
+	TyTy::FnType *fn = trait_item.ty;
+	rust_assert (fn->is_method ());
+
+	TyTy::BaseType *fn_self = fn->get_self_type ();
+	if (fn_self->can_eq (&receiver, false))
 	  {
-	    HIR::Function *func
-	      = static_cast<HIR::Function *> (c.item.impl.impl_item);
-
-	    TyTy::BaseType *lookup = nullptr;
-	    bool ok = context->lookup_type (func->get_mappings ().get_hirid (),
-					    &lookup);
-	    rust_assert (ok);
-	    rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
-
-	    TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
-	    if (fn->is_method ())
-	      {
-		TyTy::BaseType *fn_self = fn->get_self_type ();
-		if (fn_self->can_eq (receiver, false, true))
-		  {
-		    return &c;
-		  }
-	      }
+	    PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
+						     trait_item.item_ref,
+						     nullptr};
+	    return PathProbeCandidate (
+	      PathProbeCandidate::CandidateType::TRAIT_FUNC, fn,
+	      trait_item.item->get_locus (), c);
 	  }
       }
 
-    // probe trait bounds
-    for (auto &c : candidates)
+    for (auto predicate : predicate_items)
       {
-	bool is_func = c.type == PathProbeCandidate::CandidateType::TRAIT_FUNC;
-	if (is_func)
+	TyTy::FnType *fn = predicate.fntype;
+	rust_assert (fn->is_method ());
+
+	TyTy::BaseType *fn_self = fn->get_self_type ();
+	if (fn_self->can_eq (&receiver, false))
 	  {
-	    const TraitItemReference *item_ref = c.item.trait.item_ref;
-	    TyTy::BaseType *lookup = item_ref->get_tyty ();
-	    rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
-
-	    TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
-	    if (fn->is_method ())
-	      {
-		TyTy::BaseType *fn_self = fn->get_self_type ();
-		if (fn_self->can_eq (receiver, false, true))
-		  {
-		    return &c;
-		  }
-	      }
+	    const TraitReference *trait_ref
+	      = predicate.lookup.get_parent ()->get ();
+	    const TraitItemReference *trait_item
+	      = predicate.lookup.get_raw_item ();
+
+	    TyTy::BaseType *subst = predicate.lookup.get_tyty_for_receiver (
+	      receiver.get_root (),
+	      predicate.lookup.get_parent ()->get_generic_args ());
+
+	    PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
+						     nullptr};
+	    return PathProbeCandidate (
+	      PathProbeCandidate::CandidateType::TRAIT_FUNC, subst,
+	      trait_item->get_locus (), c);
 	  }
       }
 
-    return nullptr;
+    return PathProbeCandidate::get_error ();
   }
+
+  MethodResolver (const TyTy::BaseType &receiver,
+		  const HIR::PathIdentSegment &segment_name,
+		  const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
+    : receiver (receiver), segment_name (segment_name),
+      specified_bounds (specified_bounds)
+  {}
+
+  const TyTy::BaseType &receiver;
+  const HIR::PathIdentSegment &segment_name;
+  const std::vector<TyTy::TypeBoundPredicate> &specified_bounds;
 };
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
index 318b34b6747..2738f9583d3 100644
--- a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
+++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
@@ -122,7 +122,7 @@ public:
 	    if (query == candidate)
 	      continue;
 
-	    if (query->can_eq (candidate, false, false))
+	    if (query->can_eq (candidate, false))
 	      possible_collision (it->second, iy->second);
 	  }
       }
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h
index 0c618d32e01..ae88787efb2 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe.h
+++ b/gcc/rust/typecheck/rust-hir-path-probe.h
@@ -32,6 +32,8 @@ struct PathProbeCandidate
 {
   enum CandidateType
   {
+    ERROR,
+
     ENUM_VARIANT,
 
     IMPL_CONST,
@@ -108,6 +110,19 @@ struct PathProbeCandidate
     return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
 	   || type == TRAIT_FUNC;
   }
+
+  bool is_full_trait_item_candidate () const
+  {
+    return is_trait_candidate () && item.trait.impl == nullptr;
+  }
+
+  static PathProbeCandidate get_error ()
+  {
+    return PathProbeCandidate (ERROR, nullptr, Location (),
+			       ImplItemCandidate{nullptr, nullptr});
+  }
+
+  bool is_error () const { return type == ERROR; }
 };
 
 class PathProbeType : public TypeCheckBase
@@ -268,7 +283,7 @@ protected:
     bool ok = context->lookup_type (impl_ty_id, &impl_block_ty);
     rust_assert (ok);
 
-    if (!receiver->can_eq (impl_block_ty, false, false))
+    if (!receiver->can_eq (impl_block_ty, false))
       return;
 
     // lets visit the impl_item
@@ -462,6 +477,7 @@ public:
       {
 	switch (c.type)
 	  {
+	  case PathProbeCandidate::CandidateType::ERROR:
 	  case PathProbeCandidate::CandidateType::ENUM_VARIANT:
 	    gcc_unreachable ();
 	    break;
diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h
index 31ebf8b5323..3573c99b775 100644
--- a/gcc/rust/typecheck/rust-hir-trait-ref.h
+++ b/gcc/rust/typecheck/rust-hir-trait-ref.h
@@ -234,6 +234,8 @@ public:
 	   + "]";
   }
 
+  const HIR::Trait *get_hir_trait_ref () const { return hir_trait_ref; }
+
   const Analysis::NodeMapping &get_mappings () const
   {
     return hir_trait_ref->get_mappings ();
@@ -258,6 +260,24 @@ public:
     return false;
   }
 
+  bool lookup_trait_item_by_type (const std::string &ident,
+				  TraitItemReference::TraitItemType type,
+				  TraitItemReference **ref)
+  {
+    for (auto &item : item_refs)
+      {
+	if (item.get_trait_item_type () != type)
+	  continue;
+
+	if (ident.compare (item.get_identifier ()) == 0)
+	  {
+	    *ref = &item;
+	    return true;
+	  }
+      }
+    return false;
+  }
+
   bool lookup_hir_trait_item (const HIR::TraitItem &item,
 			      const TraitItemReference **ref) const
   {
@@ -278,7 +298,7 @@ public:
     return false;
   }
 
-  const TraitItemReference &
+  const TraitItemReference *
   lookup_trait_item (const std::string &ident,
 		     TraitItemReference::TraitItemType type) const
   {
@@ -288,9 +308,9 @@ public:
 	  continue;
 
 	if (ident.compare (item.get_identifier ()) == 0)
-	  return item;
+	  return &item;
       }
-    return TraitItemReference::error_node ();
+    return &TraitItemReference::error_node ();
   }
 
   size_t size () const { return item_refs.size (); }
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 0ac924fa26e..fd89953d592 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -251,53 +251,10 @@ public:
 
     context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
 
-    // in order to probe of the correct type paths we need the root type, which
-    // strips any references
-    const TyTy::BaseType *root = receiver_tyty->get_root ();
-
-    // https://doc.rust-lang.org/reference/expressions/method-call-expr.html
-    // method resolution is complex in rust once we start handling generics and
-    // traits. For now we only support looking up the valid name in impl blocks
-    // which is simple. There will need to be adjustments to ensure we can turn
-    // the receiver into borrowed references etc
-
-    bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
-    bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
-
-    bool receiver_is_generic = receiver_is_type_param || receiver_is_dyn;
-    bool probe_bounds = true;
-    bool probe_impls = !receiver_is_generic;
-    bool ignore_mandatory_trait_items = !receiver_is_generic;
-
-    auto probe_type = probe_impls ? receiver_tyty : root;
-    auto candidates
-      = PathProbeType::Probe (probe_type,
-			      expr.get_method_name ().get_segment (),
-			      probe_impls, probe_bounds,
-			      ignore_mandatory_trait_items);
-    if (candidates.empty ())
-      {
-	if (probe_impls)
-	  {
-	    candidates
-	      = PathProbeType::Probe (root,
-				      expr.get_method_name ().get_segment (),
-				      probe_impls, probe_bounds,
-				      ignore_mandatory_trait_items);
-	  }
-
-	if (candidates.empty ())
-	  {
-	    rust_error_at (expr.get_locus (),
-			   "failed to resolve the PathExprSegment to any item");
-	    return;
-	  }
-      }
-
-    std::vector<Adjustment> adjustments;
-    PathProbeCandidate *resolved_candidate
-      = MethodResolution::Select (candidates, receiver_tyty, adjustments);
-    if (resolved_candidate == nullptr)
+    auto candidate
+      = MethodResolver::Probe (receiver_tyty,
+			       expr.get_method_name ().get_segment ());
+    if (candidate.is_error ())
       {
 	rust_error_at (
 	  expr.get_method_name ().get_locus (),
@@ -308,28 +265,29 @@ public:
 
     // Get the adjusted self
     Adjuster adj (receiver_tyty);
-    TyTy::BaseType *adjusted_self = adj.adjust_type (adjustments);
+    TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
 
     // mark the required tree addressable
-    if (Adjuster::needs_address (adjustments))
+    if (Adjuster::needs_address (candidate.adjustments))
       AddressTakenResolver::SetAddressTaken (*expr.get_receiver ().get ());
 
     // store the adjustments for code-generation to know what to do
     context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
-					std::move (adjustments));
+					std::move (candidate.adjustments));
 
-    TyTy::BaseType *lookup_tyty = resolved_candidate->ty;
+    PathProbeCandidate &resolved_candidate = candidate.candidate;
+    TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
     NodeId resolved_node_id
-      = resolved_candidate->is_impl_candidate ()
-	  ? resolved_candidate->item.impl.impl_item->get_impl_mappings ()
+      = resolved_candidate.is_impl_candidate ()
+	  ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
 	      .get_nodeid ()
-	  : resolved_candidate->item.trait.item_ref->get_mappings ()
+	  : resolved_candidate.item.trait.item_ref->get_mappings ()
 	      .get_nodeid ();
 
     if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
       {
 	RichLocation r (expr.get_method_name ().get_locus ());
-	r.add_range (resolved_candidate->locus);
+	r.add_range (resolved_candidate.locus);
 	rust_error_at (r, "associated impl item is not a method");
 	return;
       }
@@ -339,11 +297,13 @@ public:
     if (!fn->is_method ())
       {
 	RichLocation r (expr.get_method_name ().get_locus ());
-	r.add_range (resolved_candidate->locus);
+	r.add_range (resolved_candidate.locus);
 	rust_error_at (r, "associated function is not a method");
 	return;
       }
 
+    auto root = receiver_tyty->get_root ();
+    bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
     if (root->get_kind () == TyTy::TypeKind::ADT)
       {
 	const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root);
@@ -369,7 +329,7 @@ public:
 	    // always be at the end of the list
 
 	    auto s = fn->get_self_type ()->get_root ();
-	    rust_assert (s->can_eq (adt, false, false));
+	    rust_assert (s->can_eq (adt, false));
 	    rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
 	    const TyTy::ADTType *self_adt
 	      = static_cast<const TyTy::ADTType *> (s);
@@ -419,6 +379,8 @@ public:
 	  }
       }
 
+    // ADT expected but got PARAM
+
     TyTy::BaseType *function_ret_tyty
       = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, adjusted_self,
 					   context);
@@ -1320,10 +1282,6 @@ protected:
 			     HIR::OperatorExpr &expr, TyTy::BaseType *lhs,
 			     TyTy::BaseType *rhs)
   {
-    // in order to probe of the correct type paths we need the root type, which
-    // strips any references
-    const TyTy::BaseType *root = lhs->get_root ();
-
     // look up lang item for arithmetic type
     std::string associated_item_name
       = Analysis::RustLangItem::ToString (lang_item_type);
@@ -1335,48 +1293,18 @@ protected:
     if (!lang_item_defined)
       return false;
 
-    bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
-    bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
-    bool receiver_is_generic = receiver_is_type_param || receiver_is_dyn;
-    bool probe_bounds = true;
-    bool probe_impls = !receiver_is_generic;
-    bool ignore_mandatory_trait_items = !receiver_is_generic;
-
-    auto probe_type = probe_impls ? lhs : root;
-    auto candidates
-      = PathProbeType::Probe (probe_type,
-			      HIR::PathIdentSegment (associated_item_name),
-			      probe_impls, probe_bounds,
-			      ignore_mandatory_trait_items);
-    if (candidates.empty ())
-      {
-	if (probe_impls)
-	  {
-	    candidates = PathProbeType::Probe (
-	      root, HIR::PathIdentSegment (associated_item_name), probe_impls,
-	      probe_bounds, ignore_mandatory_trait_items);
-	  }
+    auto segment = HIR::PathIdentSegment (associated_item_name);
+    auto candidate
+      = MethodResolver::Probe (lhs,
+			       HIR::PathIdentSegment (associated_item_name));
 
-	if (candidates.empty ())
-	  return false;
-      }
-
-    // autoderef to find the relevant method
-    std::vector<Adjustment> adjustments;
-    PathProbeCandidate *resolved_candidate
-      = MethodResolution::Select (candidates, lhs, adjustments);
-    if (resolved_candidate == nullptr)
-      return false;
-
-    bool have_implementation_for_lang_item = resolved_candidate != nullptr;
+    bool have_implementation_for_lang_item = !candidate.is_error ();
     if (!have_implementation_for_lang_item)
       return false;
 
-    // mark the required tree addressable
+    // Get the adjusted self
     Adjuster adj (lhs);
-    TyTy::BaseType *receiver_adjusted_self_ty = adj.adjust_type (adjustments);
-    if (Adjuster::needs_address (adjustments))
-      AddressTakenResolver::SetAddressTaken (*expr.get_expr ().get ());
+    TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
 
     // is this the case we are recursive
     // handle the case where we are within the impl block for this lang_item
@@ -1410,8 +1338,7 @@ protected:
 		  = trait_reference->get_mappings ().get_defid ()
 		    == respective_lang_item_id;
 		bool self_is_lang_item_self
-		  = fntype->get_self_type ()->is_equal (
-		    *receiver_adjusted_self_ty);
+		  = fntype->get_self_type ()->is_equal (*adjusted_self);
 		bool recursive_operator_overload
 		  = is_lang_item_impl && self_is_lang_item_self;
 
@@ -1421,19 +1348,24 @@ protected:
 	  }
       }
 
-    // now its just like a method-call-expr
-    context->insert_receiver (expr.get_mappings ().get_hirid (), lhs);
+    // mark the required tree addressable
+    if (Adjuster::needs_address (candidate.adjustments))
+      AddressTakenResolver::SetAddressTaken (*expr.get_expr ().get ());
 
     // store the adjustments for code-generation to know what to do
     context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
-					std::move (adjustments));
+					std::move (candidate.adjustments));
 
-    TyTy::BaseType *lookup_tyty = resolved_candidate->ty;
+    // now its just like a method-call-expr
+    context->insert_receiver (expr.get_mappings ().get_hirid (), lhs);
+
+    PathProbeCandidate &resolved_candidate = candidate.candidate;
+    TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
     NodeId resolved_node_id
-      = resolved_candidate->is_impl_candidate ()
-	  ? resolved_candidate->item.impl.impl_item->get_impl_mappings ()
+      = resolved_candidate.is_impl_candidate ()
+	  ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
 	      .get_nodeid ()
-	  : resolved_candidate->item.trait.item_ref->get_mappings ()
+	  : resolved_candidate.item.trait.item_ref->get_mappings ()
 	      .get_nodeid ();
 
     rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
@@ -1441,6 +1373,8 @@ protected:
     TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
     rust_assert (fn->is_method ());
 
+    auto root = lhs->get_root ();
+    bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
     if (root->get_kind () == TyTy::TypeKind::ADT)
       {
 	const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root);
@@ -1466,7 +1400,7 @@ protected:
 	    // always be at the end of the list
 
 	    auto s = fn->get_self_type ()->get_root ();
-	    rust_assert (s->can_eq (adt, false, false));
+	    rust_assert (s->can_eq (adt, false));
 	    rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
 	    const TyTy::ADTType *self_adt
 	      = static_cast<const TyTy::ADTType *> (s);
@@ -1508,7 +1442,7 @@ protected:
     TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
     rust_assert (type->num_params () > 0);
     auto fnparam = type->param_at (0);
-    fnparam.second->unify (receiver_adjusted_self_ty); // typecheck the self
+    fnparam.second->unify (adjusted_self); // typecheck the self
     if (rhs == nullptr)
       {
 	rust_assert (type->num_params () == 1);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index 25b592c50e7..94d8534fd06 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -370,7 +370,7 @@ class TypeCheckImplItemWithTrait : public TypeCheckImplItem
   using Rust::Resolver::TypeCheckBase::visit;
 
 public:
-  static const TraitItemReference &
+  static const TraitItemReference *
   Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
 	   TraitReference &trait_reference,
 	   std::vector<TyTy::SubstitutionParamMapping> substitutions)
@@ -383,11 +383,14 @@ public:
 
   void visit (HIR::ConstantItem &constant) override
   {
-    resolved_trait_item = trait_reference.lookup_trait_item (
-      constant.get_identifier (), TraitItemReference::TraitItemType::CONST);
+    // resolved_trait_item = trait_reference.lookup_trait_item (
+    //   constant.get_identifier (), TraitItemReference::TraitItemType::CONST);
+    trait_reference.lookup_trait_item_by_type (
+      constant.get_identifier (), TraitItemReference::TraitItemType::CONST,
+      &resolved_trait_item);
 
     // unknown trait item
-    if (resolved_trait_item.is_error ())
+    if (resolved_trait_item->is_error ())
       {
 	RichLocation r (constant.get_locus ());
 	r.add_range (trait_reference.get_locus ());
@@ -401,14 +404,14 @@ public:
     TyTy::BaseType *lookup;
     if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
       return;
-    if (resolved_trait_item.is_error ())
+    if (resolved_trait_item->is_error ())
       return;
 
     // check the types are compatible
-    if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true, false))
+    if (!resolved_trait_item->get_tyty ()->can_eq (lookup, true))
       {
 	RichLocation r (constant.get_locus ());
-	r.add_range (resolved_trait_item.get_locus ());
+	r.add_range (resolved_trait_item->get_locus ());
 
 	rust_error_at (
 	  r, "constant %<%s%> has an incompatible type for trait %<%s%>",
@@ -419,11 +422,14 @@ public:
 
   void visit (HIR::TypeAlias &type) override
   {
-    resolved_trait_item = trait_reference.lookup_trait_item (
-      type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE);
+    // resolved_trait_item = trait_reference.lookup_trait_item (
+    //   type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE);
+    trait_reference.lookup_trait_item_by_type (
+      type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE,
+      &resolved_trait_item);
 
     // unknown trait item
-    if (resolved_trait_item.is_error ())
+    if (resolved_trait_item->is_error ())
       {
 	RichLocation r (type.get_locus ());
 	r.add_range (trait_reference.get_locus ());
@@ -437,14 +443,14 @@ public:
     TyTy::BaseType *lookup;
     if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
       return;
-    if (resolved_trait_item.is_error ())
+    if (resolved_trait_item->is_error ())
       return;
 
     // check the types are compatible
-    if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true, false))
+    if (!resolved_trait_item->get_tyty ()->can_eq (lookup, true))
       {
 	RichLocation r (type.get_locus ());
-	r.add_range (resolved_trait_item.get_locus ());
+	r.add_range (resolved_trait_item->get_locus ());
 
 	rust_error_at (
 	  r, "type alias %<%s%> has an incompatible type for trait %<%s%>",
@@ -456,19 +462,22 @@ public:
     // generic substitutions to the type itself
     TyTy::ProjectionType *projection = new TyTy::ProjectionType (
       type.get_mappings ().get_hirid (), lookup, &trait_reference,
-      resolved_trait_item.get_mappings ().get_defid (), substitutions);
+      resolved_trait_item->get_mappings ().get_defid (), substitutions);
 
     context->insert_type (type.get_mappings (), projection);
-    resolved_trait_item.associated_type_set (projection);
+    resolved_trait_item->associated_type_set (projection);
   }
 
   void visit (HIR::Function &function) override
   {
-    resolved_trait_item = trait_reference.lookup_trait_item (
-      function.get_function_name (), TraitItemReference::TraitItemType::FN);
+    // resolved_trait_item = trait_reference.lookup_trait_item (
+    //   function.get_function_name (), TraitItemReference::TraitItemType::FN);
+    trait_reference.lookup_trait_item_by_type (
+      function.get_function_name (), TraitItemReference::TraitItemType::FN,
+      &resolved_trait_item);
 
     // unknown trait item
-    if (resolved_trait_item.is_error ())
+    if (resolved_trait_item->is_error ())
       {
 	RichLocation r (function.get_locus ());
 	r.add_range (trait_reference.get_locus ());
@@ -482,16 +491,16 @@ public:
     TyTy::BaseType *lookup;
     if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
       return;
-    if (resolved_trait_item.is_error ())
+    if (resolved_trait_item->is_error ())
       return;
 
     rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
-    rust_assert (resolved_trait_item.get_tyty ()->get_kind ()
+    rust_assert (resolved_trait_item->get_tyty ()->get_kind ()
 		 == TyTy::TypeKind::FNDEF);
 
     TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
     TyTy::FnType *trait_item_fntype
-      = static_cast<TyTy::FnType *> (resolved_trait_item.get_tyty ());
+      = static_cast<TyTy::FnType *> (resolved_trait_item->get_tyty ());
 
     // sets substitute self into the trait_item_ref->tyty
     TyTy::SubstitutionParamMapping *self_mapping = nullptr;
@@ -515,10 +524,10 @@ public:
       = trait_item_fntype->handle_substitions (implicit_self_substs);
 
     // check the types are compatible
-    if (!trait_item_fntype->can_eq (fntype, true, false))
+    if (!trait_item_fntype->can_eq (fntype, true))
       {
 	RichLocation r (function.get_locus ());
-	r.add_range (resolved_trait_item.get_locus ());
+	r.add_range (resolved_trait_item->get_locus ());
 
 	rust_error_at (
 	  r, "method %<%s%> has an incompatible type for trait %<%s%>",
@@ -533,7 +542,7 @@ private:
     TraitReference &trait_reference,
     std::vector<TyTy::SubstitutionParamMapping> substitutions)
     : TypeCheckImplItem (parent, self), trait_reference (trait_reference),
-      resolved_trait_item (TraitItemReference::error_node ()),
+      resolved_trait_item (&TraitItemReference::error_node ()),
       substitutions (substitutions)
   {
     rust_assert (is_trait_impl_block ());
@@ -542,7 +551,7 @@ private:
   bool is_trait_impl_block () const { return !trait_reference.is_error (); }
 
   TraitReference &trait_reference;
-  TraitItemReference &resolved_trait_item;
+  TraitItemReference *resolved_trait_item;
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
 };
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h
index cc102dff638..6692bb6321c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.h
@@ -113,15 +113,14 @@ public:
 
     bool is_trait_impl_block = !trait_reference->is_error ();
 
-    std::vector<std::reference_wrapper<const TraitItemReference>>
-      trait_item_refs;
+    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
 	  {
-	    auto &trait_item_ref
+	    auto trait_item_ref
 	      = TypeCheckImplItemWithTrait::Resolve (&impl_block,
 						     impl_item.get (), self,
 						     *trait_reference,
@@ -141,12 +140,11 @@ public:
 	for (auto &trait_item_ref : trait_reference->get_trait_items ())
 	  {
 	    bool found = false;
-	    for (const TraitItemReference &implemented_trait_item :
-		 trait_item_refs)
+	    for (auto implemented_trait_item : trait_item_refs)
 	      {
 		std::string trait_item_name = trait_item_ref.get_identifier ();
 		std::string impl_item_name
-		  = implemented_trait_item.get_identifier ();
+		  = implemented_trait_item->get_identifier ();
 		found = trait_item_name.compare (impl_item_name) == 0;
 		if (found)
 		  break;
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 1add4faa59a..b751bcdb316 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -251,7 +251,7 @@ public:
 
     for (auto &item : it->second)
       {
-	if (item.first->can_eq (self, false, false))
+	if (item.first->can_eq (self, false))
 	  {
 	    *mapping = item.second;
 	    return true;
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc
index cfb96bbd0e4..478a31235c6 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -40,7 +40,7 @@ TypeBoundsProbe::scan ()
       if (!ok)
 	return true;
 
-      if (!receiver->can_eq (impl_type, false, false))
+      if (!receiver->can_eq (impl_type, false))
 	return true;
 
       possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h
index 634753034a7..5620b62b7bd 100644
--- a/gcc/rust/typecheck/rust-tyty-cmp.h
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -418,10 +418,10 @@ public:
   }
 
 protected:
-  BaseCmp (const BaseType *base, bool emit_errors, bool autoderef_mode)
+  BaseCmp (const BaseType *base, bool emit_errors)
     : mappings (Analysis::Mappings::get ()),
       context (Resolver::TypeCheckContext::get ()), ok (false),
-      emit_error_flag (emit_errors), autoderef_mode_flag (autoderef_mode)
+      emit_error_flag (emit_errors)
   {}
 
   Analysis::Mappings *mappings;
@@ -429,7 +429,6 @@ protected:
 
   bool ok;
   bool emit_error_flag;
-  bool autoderef_mode_flag;
 
 private:
   /* Returns a pointer to the ty that created this rule. */
@@ -441,8 +440,8 @@ class InferCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  InferCmp (const InferType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  InferCmp (const InferType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const BoolType &type) override
@@ -690,8 +689,8 @@ class FnCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  FnCmp (const FnType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  FnCmp (const FnType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -712,7 +711,7 @@ public:
 	auto a = base->param_at (i).second;
 	auto b = type.param_at (i).second;
 
-	if (!a->can_eq (b, emit_error_flag, autoderef_mode_flag))
+	if (!a->can_eq (b, emit_error_flag))
 	  {
 	    emit_error_flag = false;
 	    BaseCmp::visit (type);
@@ -721,8 +720,7 @@ public:
       }
 
     if (!base->get_return_type ()->can_eq (type.get_return_type (),
-					   emit_error_flag,
-					   autoderef_mode_flag))
+					   emit_error_flag))
       {
 	emit_error_flag = false;
 	BaseCmp::visit (type);
@@ -742,8 +740,8 @@ class FnptrCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  FnptrCmp (const FnPtr *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  FnptrCmp (const FnPtr *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -767,8 +765,7 @@ public:
 
     auto this_ret_type = base->get_return_type ();
     auto other_ret_type = type.get_return_type ();
-    if (!this_ret_type->can_eq (other_ret_type, emit_error_flag,
-				autoderef_mode_flag))
+    if (!this_ret_type->can_eq (other_ret_type, emit_error_flag))
       {
 	BaseCmp::visit (type);
 	return;
@@ -778,8 +775,7 @@ public:
       {
 	auto this_param = base->param_at (i);
 	auto other_param = type.param_at (i);
-	if (!this_param->can_eq (other_param, emit_error_flag,
-				 autoderef_mode_flag))
+	if (!this_param->can_eq (other_param, emit_error_flag))
 	  {
 	    BaseCmp::visit (type);
 	    return;
@@ -799,8 +795,7 @@ public:
 
     auto this_ret_type = base->get_return_type ();
     auto other_ret_type = type.get_return_type ();
-    if (!this_ret_type->can_eq (other_ret_type, emit_error_flag,
-				autoderef_mode_flag))
+    if (!this_ret_type->can_eq (other_ret_type, emit_error_flag))
       {
 	BaseCmp::visit (type);
 	return;
@@ -810,8 +805,7 @@ public:
       {
 	auto this_param = base->param_at (i);
 	auto other_param = type.param_at (i).second;
-	if (!this_param->can_eq (other_param, emit_error_flag,
-				 autoderef_mode_flag))
+	if (!this_param->can_eq (other_param, emit_error_flag))
 	  {
 	    BaseCmp::visit (type);
 	    return;
@@ -831,8 +825,8 @@ class ClosureCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  ClosureCmp (const ClosureType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  ClosureCmp (const ClosureType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
 private:
@@ -845,8 +839,8 @@ class ArrayCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  ArrayCmp (const ArrayType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  ArrayCmp (const ArrayType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const ArrayType &type) override
@@ -854,8 +848,7 @@ public:
     // check base type
     const BaseType *base_element = base->get_element_type ();
     const BaseType *other_element = type.get_element_type ();
-    if (!base_element->can_eq (other_element, emit_error_flag,
-			       autoderef_mode_flag))
+    if (!base_element->can_eq (other_element, emit_error_flag))
       {
 	BaseCmp::visit (type);
 	return;
@@ -876,8 +869,8 @@ class BoolCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  BoolCmp (const BoolType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  BoolCmp (const BoolType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const BoolType &type) override { ok = true; }
@@ -899,8 +892,8 @@ class IntCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  IntCmp (const IntType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  IntCmp (const IntType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -925,8 +918,8 @@ class UintCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  UintCmp (const UintType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  UintCmp (const UintType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -951,8 +944,8 @@ class FloatCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  FloatCmp (const FloatType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  FloatCmp (const FloatType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -977,8 +970,8 @@ class ADTCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  ADTCmp (const ADTType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  ADTCmp (const ADTType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const ADTType &type) override
@@ -1020,8 +1013,7 @@ public:
 	    TyTy::BaseType *this_field_ty = base_field->get_field_type ();
 	    TyTy::BaseType *other_field_ty = other_field->get_field_type ();
 
-	    if (!this_field_ty->can_eq (other_field_ty, emit_error_flag,
-					autoderef_mode_flag))
+	    if (!this_field_ty->can_eq (other_field_ty, emit_error_flag))
 	      {
 		BaseCmp::visit (type);
 		return;
@@ -1032,8 +1024,6 @@ public:
     ok = true;
   }
 
-  void visit (const ParamType &type) override { ok = true; }
-
 private:
   const BaseType *get_base () const override { return base; }
   const ADTType *base;
@@ -1044,8 +1034,8 @@ class TupleCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  TupleCmp (const TupleType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  TupleCmp (const TupleType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const TupleType &type) override
@@ -1061,7 +1051,7 @@ public:
 	BaseType *bo = base->get_field (i);
 	BaseType *fo = type.get_field (i);
 
-	if (!bo->can_eq (fo, emit_error_flag, autoderef_mode_flag))
+	if (!bo->can_eq (fo, emit_error_flag))
 	  {
 	    BaseCmp::visit (type);
 	    return;
@@ -1083,8 +1073,8 @@ class USizeCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  USizeCmp (const USizeType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  USizeCmp (const USizeType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -1106,8 +1096,8 @@ class ISizeCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  ISizeCmp (const ISizeType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  ISizeCmp (const ISizeType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -1129,8 +1119,8 @@ class CharCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  CharCmp (const CharType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  CharCmp (const CharType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const InferType &type) override
@@ -1152,9 +1142,8 @@ class ReferenceCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  ReferenceCmp (const ReferenceType *base, bool emit_errors,
-		bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  ReferenceCmp (const ReferenceType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const ReferenceType &type) override
@@ -1162,17 +1151,14 @@ public:
     auto base_type = base->get_base ();
     auto other_base_type = type.get_base ();
 
-    // rust is permissive about mutablity here you can always go from mutable to
-    // immutable but not the otherway round
-    bool mutability_ok = base->is_mutable () ? type.is_mutable () : true;
-    if (!mutability_ok)
+    bool mutability_match = base->is_mutable () == type.is_mutable ();
+    if (!mutability_match)
       {
 	BaseCmp::visit (type);
 	return;
       }
 
-    if (!base_type->can_eq (other_base_type, emit_error_flag,
-			    autoderef_mode_flag))
+    if (!base_type->can_eq (other_base_type, emit_error_flag))
       {
 	BaseCmp::visit (type);
 	return;
@@ -1191,8 +1177,8 @@ class PointerCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  PointerCmp (const PointerType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  PointerCmp (const PointerType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const ReferenceType &type) override
@@ -1209,8 +1195,7 @@ public:
 	return;
       }
 
-    if (!base_type->can_eq (other_base_type, emit_error_flag,
-			    autoderef_mode_flag))
+    if (!base_type->can_eq (other_base_type, emit_error_flag))
       {
 	BaseCmp::visit (type);
 	return;
@@ -1229,8 +1214,8 @@ class ParamCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  ParamCmp (const ParamType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  ParamCmp (const ParamType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   // param types are a placeholder we shouldn't have cases where we unify
@@ -1252,7 +1237,7 @@ public:
     bool ok = context->lookup_type (base->get_ty_ref (), &lookup);
     rust_assert (ok);
 
-    return lookup->can_eq (other, emit_error_flag, autoderef_mode_flag);
+    return lookup->can_eq (other, emit_error_flag);
   }
 
   // imagine the case where we have:
@@ -1263,16 +1248,14 @@ public:
   // generic arguments
   void visit (const ParamType &) override { ok = true; }
 
-  void visit (const TupleType &) override { ok = true; }
-
-  void visit (const ADTType &) override { ok = true; }
-
   void visit (const InferType &) override { ok = true; }
 
   void visit (const FnType &) override { ok = true; }
 
   void visit (const FnPtr &) override { ok = true; }
 
+  void visit (const ADTType &) override { ok = true; }
+
   void visit (const ArrayType &) override { ok = true; }
 
   void visit (const BoolType &) override { ok = true; }
@@ -1289,9 +1272,9 @@ public:
 
   void visit (const CharType &) override { ok = true; }
 
-  void visit (const ReferenceType &) override { ok = !autoderef_mode_flag; }
+  void visit (const ReferenceType &) override { ok = true; }
 
-  void visit (const PointerType &) override { ok = !autoderef_mode_flag; }
+  void visit (const PointerType &) override { ok = true; }
 
   void visit (const StrType &) override { ok = true; }
 
@@ -1315,8 +1298,8 @@ class StrCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  StrCmp (const StrType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  StrCmp (const StrType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const StrType &type) override { ok = true; }
@@ -1333,8 +1316,8 @@ class NeverCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  NeverCmp (const NeverType *base, bool emit_errors, bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  NeverCmp (const NeverType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const NeverType &type) override { ok = true; }
@@ -1351,9 +1334,8 @@ class PlaceholderCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  PlaceholderCmp (const PlaceholderType *base, bool emit_errors,
-		  bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  PlaceholderCmp (const PlaceholderType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   bool can_eq (const BaseType *other) override
@@ -1362,7 +1344,7 @@ public:
       return BaseCmp::can_eq (other);
 
     BaseType *lookup = base->resolve ();
-    return lookup->can_eq (other, emit_error_flag, autoderef_mode_flag);
+    return lookup->can_eq (other, emit_error_flag);
   }
 
   void visit (const TupleType &) override { ok = true; }
@@ -1417,9 +1399,8 @@ class DynamicCmp : public BaseCmp
   using Rust::TyTy::BaseCmp::visit;
 
 public:
-  DynamicCmp (const DynamicObjectType *base, bool emit_errors,
-	      bool autoderef_mode)
-    : BaseCmp (base, emit_errors, autoderef_mode), base (base)
+  DynamicCmp (const DynamicObjectType *base, bool emit_errors)
+    : BaseCmp (base, emit_errors), base (base)
   {}
 
   void visit (const DynamicObjectType &type) override
diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h
index 450a93f28a1..349813b7076 100644
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ b/gcc/rust/typecheck/rust-tyty-rules.h
@@ -25,9 +25,6 @@
 #include "rust-hir-map.h"
 #include "rust-hir-type-check.h"
 
-extern ::Backend *
-rust_get_backend ();
-
 namespace Rust {
 namespace TyTy {
 
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 679187b16fd..b5427b71a54 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -91,8 +91,12 @@ BaseType::bounds_compatible (const BaseType &other, Location locus,
 	}
 
       if (emit_error)
-	rust_error_at (r, "bounds not satisfied for %s %<%s%> is not satisfied",
-		       other.get_name ().c_str (), missing_preds.c_str ());
+	{
+	  rust_error_at (r,
+			 "bounds not satisfied for %s %<%s%> is not satisfied",
+			 other.get_name ().c_str (), missing_preds.c_str ());
+	  // rust_assert (!emit_error);
+	}
     }
 
   return unsatisfied_bounds.size () == 0;
@@ -201,10 +205,9 @@ InferType::unify (BaseType *other)
 }
 
 bool
-InferType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+InferType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  InferCmp r (this, emit_errors, autoderef_mode);
+  InferCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -279,8 +282,7 @@ ErrorType::unify (BaseType *other)
 }
 
 bool
-ErrorType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+ErrorType::can_eq (const BaseType *other, bool emit_errors) const
 {
   return get_kind () == other->get_kind ();
 }
@@ -685,10 +687,9 @@ ADTType::cast (BaseType *other)
 }
 
 bool
-ADTType::can_eq (const BaseType *other, bool emit_errors,
-		 bool autoderef_mode) const
+ADTType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  ADTCmp r (this, emit_errors, autoderef_mode);
+  ADTCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -888,10 +889,9 @@ TupleType::cast (BaseType *other)
 }
 
 bool
-TupleType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+TupleType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  TupleCmp r (this, emit_errors, autoderef_mode);
+  TupleCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -993,10 +993,9 @@ FnType::cast (BaseType *other)
 }
 
 bool
-FnType::can_eq (const BaseType *other, bool emit_errors,
-		bool autoderef_mode) const
+FnType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  FnCmp r (this, emit_errors, autoderef_mode);
+  FnCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1211,10 +1210,9 @@ FnPtr::cast (BaseType *other)
 }
 
 bool
-FnPtr::can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const
+FnPtr::can_eq (const BaseType *other, bool emit_errors) const
 {
-  FnptrCmp r (this, emit_errors, autoderef_mode);
+  FnptrCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1278,10 +1276,9 @@ ClosureType::unify (BaseType *other)
 }
 
 bool
-ClosureType::can_eq (const BaseType *other, bool emit_errors,
-		     bool autoderef_mode) const
+ClosureType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  ClosureCmp r (this, emit_errors, autoderef_mode);
+  ClosureCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1360,10 +1357,9 @@ ArrayType::cast (BaseType *other)
 }
 
 bool
-ArrayType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+ArrayType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  ArrayCmp r (this, emit_errors, autoderef_mode);
+  ArrayCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1434,10 +1430,9 @@ BoolType::cast (BaseType *other)
 }
 
 bool
-BoolType::can_eq (const BaseType *other, bool emit_errors,
-		  bool autoderef_mode) const
+BoolType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  BoolCmp r (this, emit_errors, autoderef_mode);
+  BoolCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1501,10 +1496,9 @@ IntType::cast (BaseType *other)
 }
 
 bool
-IntType::can_eq (const BaseType *other, bool emit_errors,
-		 bool autoderef_mode) const
+IntType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  IntCmp r (this, emit_errors, autoderef_mode);
+  IntCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1579,10 +1573,9 @@ UintType::cast (BaseType *other)
 }
 
 bool
-UintType::can_eq (const BaseType *other, bool emit_errors,
-		  bool autoderef_mode) const
+UintType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  UintCmp r (this, emit_errors, autoderef_mode);
+  UintCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1651,10 +1644,9 @@ FloatType::cast (BaseType *other)
 }
 
 bool
-FloatType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+FloatType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  FloatCmp r (this, emit_errors, autoderef_mode);
+  FloatCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1715,10 +1707,9 @@ USizeType::cast (BaseType *other)
 }
 
 bool
-USizeType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+USizeType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  USizeCmp r (this, emit_errors, autoderef_mode);
+  USizeCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1768,10 +1759,9 @@ ISizeType::cast (BaseType *other)
 }
 
 bool
-ISizeType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+ISizeType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  ISizeCmp r (this, emit_errors, autoderef_mode);
+  ISizeCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1821,10 +1811,9 @@ CharType::cast (BaseType *other)
 }
 
 bool
-CharType::can_eq (const BaseType *other, bool emit_errors,
-		  bool autoderef_mode) const
+CharType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  CharCmp r (this, emit_errors, autoderef_mode);
+  CharCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1875,10 +1864,9 @@ ReferenceType::cast (BaseType *other)
 }
 
 bool
-ReferenceType::can_eq (const BaseType *other, bool emit_errors,
-		       bool autoderef_mode) const
+ReferenceType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  ReferenceCmp r (this, emit_errors, autoderef_mode);
+  ReferenceCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -1962,10 +1950,9 @@ PointerType::cast (BaseType *other)
 }
 
 bool
-PointerType::can_eq (const BaseType *other, bool emit_errors,
-		     bool autoderef_mode) const
+PointerType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  PointerCmp r (this, emit_errors, autoderef_mode);
+  PointerCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -2072,10 +2059,9 @@ ParamType::cast (BaseType *other)
 }
 
 bool
-ParamType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+ParamType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  ParamCmp r (this, emit_errors, autoderef_mode);
+  ParamCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -2130,7 +2116,7 @@ ParamType::is_equal (const BaseType &other) const
     return false;
 
   if (can_resolve ())
-    return resolve ()->can_eq (other2.resolve (), false, false);
+    return resolve ()->can_eq (other2.resolve (), false);
 
   return get_symbol ().compare (other2.get_symbol ()) == 0;
 }
@@ -2194,10 +2180,9 @@ StrType::cast (BaseType *other)
 }
 
 bool
-StrType::can_eq (const BaseType *other, bool emit_errors,
-		 bool autoderef_mode) const
+StrType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  StrCmp r (this, emit_errors, autoderef_mode);
+  StrCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -2247,10 +2232,9 @@ NeverType::cast (BaseType *other)
 }
 
 bool
-NeverType::can_eq (const BaseType *other, bool emit_errors,
-		   bool autoderef_mode) const
+NeverType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  NeverCmp r (this, emit_errors, autoderef_mode);
+  NeverCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -2303,10 +2287,9 @@ PlaceholderType::cast (BaseType *other)
 }
 
 bool
-PlaceholderType::can_eq (const BaseType *other, bool emit_errors,
-			 bool autoderef_mode) const
+PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  PlaceholderCmp r (this, emit_errors, autoderef_mode);
+  PlaceholderCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
@@ -2404,10 +2387,9 @@ ProjectionType::cast (BaseType *other)
 }
 
 bool
-ProjectionType::can_eq (const BaseType *other, bool emit_errors,
-			bool autoderef_mode) const
+ProjectionType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  return base->can_eq (other, emit_errors, autoderef_mode);
+  return base->can_eq (other, emit_errors);
 }
 
 BaseType *
@@ -2511,10 +2493,9 @@ DynamicObjectType::unify (BaseType *other)
 }
 
 bool
-DynamicObjectType::can_eq (const BaseType *other, bool emit_errors,
-			   bool autoderef_mode) const
+DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const
 {
-  DynamicCmp r (this, emit_errors, autoderef_mode);
+  DynamicCmp r (this, emit_errors);
   return r.can_eq (other);
 }
 
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index f2c250fbe39..873f5d8d484 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -314,8 +314,7 @@ public:
   //
   // It can also be used to optional emit errors for trait item compatibility
   // checks
-  virtual bool can_eq (const BaseType *other, bool emit_errors,
-		       bool autoderef_mode) const = 0;
+  virtual bool can_eq (const BaseType *other, bool emit_errors) const = 0;
 
   // this is the base coercion interface for types
   virtual BaseType *coerce (BaseType *other) = 0;
@@ -460,8 +459,7 @@ public:
 
   BaseType *unify (BaseType *other) override;
 
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
@@ -499,8 +497,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -536,8 +533,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -626,8 +622,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1252,8 +1247,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1387,8 +1381,7 @@ public:
   std::string get_identifier () const { return identifier; }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1507,8 +1500,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1578,8 +1570,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1642,8 +1633,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1684,8 +1674,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1722,8 +1711,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1767,8 +1755,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1810,8 +1797,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1845,8 +1831,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1873,8 +1858,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1901,8 +1885,7 @@ public:
   std::string get_name () const override final { return as_string (); }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1936,8 +1919,7 @@ public:
   }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -1987,8 +1969,7 @@ public:
   }
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -2033,8 +2014,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -2071,8 +2051,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -2106,8 +2085,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -2175,8 +2153,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
 
@@ -2233,8 +2210,7 @@ public:
   std::string as_string () const override;
 
   BaseType *unify (BaseType *other) override;
-  bool can_eq (const BaseType *other, bool emit_errors,
-	       bool autoderef_mode) const override final;
+  bool can_eq (const BaseType *other, bool emit_errors) const override final;
   BaseType *coerce (BaseType *other) override;
   BaseType *cast (BaseType *other) override;
   bool is_equal (const BaseType &other) const override;
diff --git a/gcc/testsuite/rust/execute/torture/method2.rs b/gcc/testsuite/rust/execute/torture/method2.rs
new file mode 100644
index 00000000000..f532b4488c6
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/method2.rs
@@ -0,0 +1,76 @@
+// { dg-additional-options "-w" }
+// { dg-output "foo_deref\nimm_deref\n" }
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+    type Target;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+impl<T> Deref for &T {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe {
+            let a = "imm_deref\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+
+        *self
+    }
+}
+
+impl<T> Deref for &mut T {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe {
+            let a = "mut_deref\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+
+        *self
+    }
+}
+
+struct Bar(i32);
+impl Bar {
+    fn foobar(self) -> i32 {
+        self.0
+    }
+}
+
+struct Foo<T>(T);
+impl<T> Deref for Foo<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        unsafe {
+            let a = "foo_deref\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+
+        &self.0
+    }
+}
+
+pub fn main() -> i32 {
+    let bar = Bar(123);
+    let foo: Foo<&Bar> = Foo(&bar);
+    let foobar: i32 = foo.foobar();
+
+    foobar - 123
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:00 [gcc/devel/rust/master] MethodResolution should respect the autoderef cycle Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).