about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-12-19 22:51:39 +0000
committerbors <bors@rust-lang.org>2018-12-19 22:51:39 +0000
commitdaa8792f17ad5484ec1e3b0b1e2557f8603219d0 (patch)
tree526ffe35c2e094649bc7c142b8f15ee08a4a10ef
parent790f4c566d9802dfcadc26398dde2051cfe6ec9f (diff)
parentb4db387a6c886d4242a94d997c48967abd63314c (diff)
downloadrust-daa8792f17ad5484ec1e3b0b1e2557f8603219d0.tar.gz
rust-daa8792f17ad5484ec1e3b0b1e2557f8603219d0.zip
Auto merge of #54252 - arielb1:deref-query, r=nikomatsakis
process nested obligations in autoderef

Fixes #53843.

r? @nikomatsakis
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/infer/canonical/query_response.rs25
-rw-r--r--src/librustc/traits/fulfill.rs26
-rw-r--r--src/librustc/traits/query/method_autoderef.rs55
-rw-r--r--src/librustc/traits/query/mod.rs1
-rw-r--r--src/librustc/ty/query/config.rs6
-rw-r--r--src/librustc/ty/query/mod.rs5
-rw-r--r--src/librustc/ty/query/plumbing.rs1
-rw-r--r--src/librustc_typeck/check/autoderef.rs164
-rw-r--r--src/librustc_typeck/check/callee.rs10
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/method/confirm.rs6
-rw-r--r--src/librustc_typeck/check/method/mod.rs1
-rw-r--r--src/librustc_typeck/check/method/probe.rs305
-rw-r--r--src/librustc_typeck/check/mod.rs35
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/test/run-pass/issue-53843.rs34
18 files changed, 488 insertions, 192 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 56f475314ae..f4d7ef59404 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -669,6 +669,7 @@ define_dep_nodes!( <'tcx>
     [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
 
     [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
+    [] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),
 
     [input] TargetFeaturesWhitelist,
 
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index 43bc9d88895..2a8a340ab54 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -117,6 +117,31 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         Ok(Lrc::new(canonical_result))
     }
 
+    /// A version of `make_canonicalized_query_response` that does
+    /// not pack in obligations, for contexts that want to drop
+    /// pending obligations instead of treating them as an ambiguity (e.g.
+    /// typeck "probing" contexts).
+    ///
+    /// If you DO want to keep track of pending obligations (which
+    /// include all region obligations, so this includes all cases
+    /// that care about regions) with this function, you have to
+    /// do it yourself, by e.g. having them be a part of the answer.
+    pub fn make_query_response_ignoring_pending_obligations<T>(
+        &self,
+        inference_vars: CanonicalVarValues<'tcx>,
+        answer: T
+    ) -> Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'gcx>>::Lifted>>
+    where
+        T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
+    {
+        self.canonicalize_response(&QueryResponse {
+            var_values: inference_vars,
+            region_constraints: vec![],
+            certainty: Certainty::Proven, // Ambiguities are OK!
+            value: answer,
+        })
+    }
+
     /// Helper for `make_canonicalized_query_response` that does
     /// everything up until the final canonicalization.
     fn make_query_response<T>(
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index bc091a4e7e0..09c7bd67970 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -61,6 +61,16 @@ pub struct FulfillmentContext<'tcx> {
     // type-lives-for-region constraints, and because the type
     // is well-formed, the constraints should hold.
     register_region_obligations: bool,
+    // Is it OK to register obligations into this infcx inside
+    // an infcx snapshot?
+    //
+    // The "primary fulfillment" in many cases in typeck lives
+    // outside of any snapshot, so any use of it inside a snapshot
+    // will lead to trouble and therefore is checked against, but
+    // other fulfillment contexts sometimes do live inside of
+    // a snapshot (they don't *straddle* a snapshot, so there
+    // is no trouble there).
+    usable_in_snapshot: bool
 }
 
 #[derive(Clone, Debug)]
@@ -74,14 +84,24 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
-            register_region_obligations: true
+            register_region_obligations: true,
+            usable_in_snapshot: false,
+        }
+    }
+
+    pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
+        FulfillmentContext {
+            predicates: ObligationForest::new(),
+            register_region_obligations: true,
+            usable_in_snapshot: true,
         }
     }
 
     pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
-            register_region_obligations: false
+            register_region_obligations: false,
+            usable_in_snapshot: false
         }
     }
 
@@ -195,7 +215,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
 
         debug!("register_predicate_obligation(obligation={:?})", obligation);
 
-        assert!(!infcx.is_in_snapshot());
+        assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
 
         self.predicates.register_obligation(PendingPredicateObligation {
             obligation,
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs
new file mode 100644
index 00000000000..175883eb2a7
--- /dev/null
+++ b/src/librustc/traits/query/method_autoderef.rs
@@ -0,0 +1,55 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc_data_structures::sync::Lrc;
+use infer::canonical::{Canonical, QueryResponse};
+use ty::Ty;
+
+#[derive(Debug)]
+pub struct CandidateStep<'tcx> {
+    pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    pub autoderefs: usize,
+    // true if the type results from a dereference of a raw pointer.
+    // when assembling candidates, we include these steps, but not when
+    // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
+    // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
+    // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
+    pub from_unsafe_deref: bool,
+    pub unsize: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct MethodAutoderefStepsResult<'tcx> {
+    /// The valid autoderef steps that could be find.
+    pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
+    /// If Some(T), a type autoderef reported an error on.
+    pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
+    /// If `true`, `steps` has been truncated due to reaching the
+    /// recursion limit.
+    pub reached_recursion_limit: bool,
+}
+
+#[derive(Debug)]
+pub struct MethodAutoderefBadTy<'tcx> {
+    pub reached_raw_pointer: bool,
+    pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+}
+
+impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
+    reached_raw_pointer, ty
+});
+
+impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
+    reached_recursion_limit, steps, opt_bad_ty
+});
+
+impl_stable_hash_for!(struct CandidateStep<'tcx> {
+    self_ty, autoderefs, from_unsafe_deref, unsize
+});
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index 13683d85444..b11cb737764 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -21,6 +21,7 @@ use ty::{self, Ty};
 
 pub mod dropck_outlives;
 pub mod evaluate_obligation;
+pub mod method_autoderef;
 pub mod normalize;
 pub mod normalize_erasing_regions;
 pub mod outlives_bounds;
diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs
index fd9143be679..b320c29dfad 100644
--- a/src/librustc/ty/query/config.rs
+++ b/src/librustc/ty/query/config.rs
@@ -827,6 +827,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_pre
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::method_autoderef_steps<'tcx> {
+    fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> {
+        format!("computing autoderef types for `{:?}`", goal).into()
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "looking up the whitelist of target features".into()
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index f760ebbd759..c9ffab21b78 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -40,6 +40,7 @@ use traits::query::{
     CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
     CanonicalTypeOpNormalizeGoal, NoSolution,
 };
+use traits::query::method_autoderef::MethodAutoderefStepsResult;
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::query::outlives_bounds::OutlivesBound;
@@ -668,6 +669,10 @@ define_queries! { <'tcx>
 
         [] fn substitute_normalize_and_test_predicates:
             substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
+
+        [] fn method_autoderef_steps: MethodAutoderefSteps(
+            CanonicalTyGoal<'tcx>
+        ) -> MethodAutoderefStepsResult<'tcx>,
     },
 
     Other {
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 7e799d2d6c3..a73b92ed713 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1116,6 +1116,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TypeOpNormalizePolyFnSig |
         DepKind::TypeOpNormalizeFnSig |
         DepKind::SubstituteNormalizeAndTestPredicates |
+        DepKind::MethodAutoderefSteps |
         DepKind::InstanceDefSizeEstimate |
         DepKind::ProgramClausesForEnv |
 
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index 1b594342c9a..d240f45c7d9 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -8,20 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use astconv::AstConv;
-
 use super::{FnCtxt, PlaceOp, Needs};
 use super::method::MethodCallee;
 
-use rustc::infer::InferOk;
+use rustc::infer::{InferCtxt, InferOk};
 use rustc::session::DiagnosticMessageId;
-use rustc::traits;
-use rustc::ty::{self, Ty, TraitRef};
+use rustc::traits::{self, TraitEngine};
+use rustc::ty::{self, Ty, TyCtxt, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
 use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 
 use syntax_pos::Span;
-use syntax::ast::Ident;
+use syntax::ast::{self, Ident};
 
 use std::iter;
 
@@ -32,20 +30,24 @@ enum AutoderefKind {
 }
 
 pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
-    fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    body_id: ast::NodeId,
+    param_env: ty::ParamEnv<'tcx>,
     steps: Vec<(Ty<'tcx>, AutoderefKind)>,
     cur_ty: Ty<'tcx>,
     obligations: Vec<traits::PredicateObligation<'tcx>>,
     at_start: bool,
     include_raw_pointers: bool,
     span: Span,
+    silence_errors: bool,
+    reached_recursion_limit: bool
 }
 
 impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
     type Item = (Ty<'tcx>, usize);
 
     fn next(&mut self) -> Option<Self::Item> {
-        let tcx = self.fcx.tcx;
+        let tcx = self.infcx.tcx;
 
         debug!("autoderef: steps={:?}, cur_ty={:?}",
                self.steps,
@@ -57,24 +59,10 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
         }
 
         if self.steps.len() >= *tcx.sess.recursion_limit.get() {
-            // We've reached the recursion limit, error gracefully.
-            let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
-            let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
-                              self.cur_ty);
-            let error_id = (DiagnosticMessageId::ErrorId(55), Some(self.span), msg);
-            let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
-            if fresh {
-                struct_span_err!(tcx.sess,
-                                 self.span,
-                                 E0055,
-                                 "reached the recursion limit while auto-dereferencing `{:?}`",
-                                 self.cur_ty)
-                    .span_label(self.span, "deref recursion limit reached")
-                    .help(&format!(
-                        "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
-                        suggested_limit))
-                    .emit();
+            if !self.silence_errors {
+                report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
             }
+            self.reached_recursion_limit = true;
             return None;
         }
 
@@ -107,10 +95,32 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+               param_env: ty::ParamEnv<'tcx>,
+               body_id: ast::NodeId,
+               span: Span,
+               base_ty: Ty<'tcx>)
+               -> Autoderef<'a, 'gcx, 'tcx>
+    {
+        Autoderef {
+            infcx,
+            body_id,
+            param_env,
+            steps: vec![],
+            cur_ty: infcx.resolve_type_vars_if_possible(&base_ty),
+            obligations: vec![],
+            at_start: true,
+            include_raw_pointers: false,
+            silence_errors: false,
+            reached_recursion_limit: false,
+            span,
+        }
+    }
+
     fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         debug!("overloaded_deref_ty({:?})", ty);
 
-        let tcx = self.fcx.tcx();
+        let tcx = self.infcx.tcx;
 
         // <cur_ty as Deref>
         let trait_ref = TraitRef {
@@ -118,43 +128,52 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
             substs: tcx.mk_substs_trait(self.cur_ty, &[]),
         };
 
-        let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
+        let cause = traits::ObligationCause::misc(self.span, self.body_id);
 
         let obligation = traits::Obligation::new(cause.clone(),
-                                                 self.fcx.param_env,
+                                                 self.param_env,
                                                  trait_ref.to_predicate());
-        if !self.fcx.predicate_may_hold(&obligation) {
+        if !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
             return None;
         }
 
-        let mut selcx = traits::SelectionContext::new(self.fcx);
-        let normalized_ty = traits::normalize_projection_type(&mut selcx,
-                                                              self.fcx.param_env,
-                                                              ty::ProjectionTy::from_ref_and_name(
-                                                                  tcx,
-                                                                  trait_ref,
-                                                                  Ident::from_str("Target"),
-                                                              ),
-                                                              cause,
-                                                              0,
-                                                              &mut self.obligations);
-
-        debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty);
+        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+        let normalized_ty = fulfillcx.normalize_projection_type(
+            &self.infcx,
+            self.param_env,
+            ty::ProjectionTy::from_ref_and_name(
+                tcx,
+                trait_ref,
+                Ident::from_str("Target"),
+            ),
+            cause);
+        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+            // This shouldn't happen, except for evaluate/fulfill mismatches,
+            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+            // by design).
+            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling",
+                   e);
+            return None;
+        }
+        let obligations = fulfillcx.pending_obligations();
+        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})",
+               ty, normalized_ty, obligations);
+        self.obligations.extend(obligations);
 
-        Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
+        Some(self.infcx.resolve_type_vars_if_possible(&normalized_ty))
     }
 
     /// Returns the final type, generating an error if it is an
     /// unresolved inference variable.
-    pub fn unambiguous_final_ty(&self) -> Ty<'tcx> {
-        self.fcx.structurally_resolved_type(self.span, self.cur_ty)
+    pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+        fcx.structurally_resolved_type(self.span, self.cur_ty)
     }
 
     /// Returns the final type we ended up with, which may well be an
     /// inference variable (we will resolve it first, if possible).
     pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
-        self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
+        self.infcx.resolve_type_vars_if_possible(&self.cur_ty)
     }
 
     pub fn step_count(&self) -> usize {
@@ -162,19 +181,19 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
     }
 
     /// Returns the adjustment steps.
-    pub fn adjust_steps(&self, needs: Needs)
+    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs)
                         -> Vec<Adjustment<'tcx>> {
-        self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(needs))
+        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
     }
 
-    pub fn adjust_steps_as_infer_ok(&self, needs: Needs)
+    pub fn adjust_steps_as_infer_ok(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs)
                                     -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let mut obligations = vec![];
         let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
             .chain(iter::once(self.cur_ty));
         let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
             if let AutoderefKind::Overloaded = kind {
-                self.fcx.try_overloaded_deref(self.span, source, needs)
+                fcx.try_overloaded_deref(self.span, source, needs)
                     .and_then(|InferOk { value: method, obligations: o }| {
                         obligations.extend(o);
                         if let ty::Ref(region, _, mutbl) = method.sig.output().sty {
@@ -211,8 +230,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
         self
     }
 
-    pub fn finalize(self) {
-        let fcx = self.fcx;
+    pub fn silence_errors(mut self) -> Self {
+        self.silence_errors = true;
+        self
+    }
+
+    pub fn reached_recursion_limit(&self) -> bool {
+        self.reached_recursion_limit
+    }
+
+    pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
         fcx.register_predicates(self.into_obligations());
     }
 
@@ -221,17 +248,32 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
     }
 }
 
+pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>(
+    tcx: TyCtxt<'a, 'gcx, 'tcx>, span: Span, ty: Ty<'tcx>)
+{
+    // We've reached the recursion limit, error gracefully.
+    let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
+    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
+                      ty);
+    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
+    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+    if fresh {
+        struct_span_err!(tcx.sess,
+                         span,
+                         E0055,
+                         "reached the recursion limit while auto-dereferencing `{:?}`",
+                         ty)
+            .span_label(span, "deref recursion limit reached")
+            .help(&format!(
+                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                suggested_limit))
+            .emit();
+    }
+}
+
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
-        Autoderef {
-            fcx: self,
-            steps: vec![],
-            cur_ty: self.resolve_type_vars_if_possible(&base_ty),
-            obligations: vec![],
-            at_start: true,
-            include_raw_pointers: false,
-            span,
-        }
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
     }
 
     pub fn try_overloaded_deref(&self,
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 75ae8688834..0ec181e59d0 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef);
         }
-        autoderef.finalize();
+        autoderef.finalize(self);
 
         let output = match result {
             None => {
@@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 callee_expr: &'gcx hir::Expr,
                                 autoderef: &Autoderef<'a, 'gcx, 'tcx>)
                                 -> Option<CallStep<'tcx>> {
-        let adjusted_ty = autoderef.unambiguous_final_ty();
+        let adjusted_ty = autoderef.unambiguous_final_ty(self);
         debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
                call_expr,
                adjusted_ty);
@@ -97,7 +97,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // If the callee is a bare function or a closure, then we're all set.
         match adjusted_ty.sty {
             ty::FnDef(..) | ty::FnPtr(_) => {
-                let adjustments = autoderef.adjust_steps(Needs::None);
+                let adjustments = autoderef.adjust_steps(self, Needs::None);
                 self.apply_adjustments(callee_expr, adjustments);
                 return Some(CallStep::Builtin(adjusted_ty));
             }
@@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         infer::FnCall,
                         &closure_ty
                     ).0;
-                    let adjustments = autoderef.adjust_steps(Needs::None);
+                    let adjustments = autoderef.adjust_steps(self, Needs::None);
                     self.record_deferred_call_resolution(def_id, DeferredCallResolution {
                         call_expr,
                         callee_expr,
@@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
 
         self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
-            let mut adjustments = autoderef.adjust_steps(Needs::None);
+            let mut adjustments = autoderef.adjust_steps(self, Needs::None);
             adjustments.extend(autoref);
             self.apply_adjustments(callee_expr, adjustments);
             CallStep::Overloaded(method)
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 8d844fe3a69..d616d88905b 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -419,7 +419,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
         let needs = Needs::maybe_mut_place(mt_b.mutbl);
         let InferOk { value: mut adjustments, obligations: o }
-            = autoderef.adjust_steps_as_infer_ok(needs);
+            = autoderef.adjust_steps_as_infer_ok(self, needs);
         obligations.extend(o);
         obligations.extend(autoderef.into_obligations());
 
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 11fb3889a74..3902dddd0d4 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -161,9 +161,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
         assert_eq!(n, pick.autoderefs);
 
-        let mut adjustments = autoderef.adjust_steps(Needs::None);
+        let mut adjustments = autoderef.adjust_steps(self, Needs::None);
 
-        let mut target = autoderef.unambiguous_final_ty();
+        let mut target = autoderef.unambiguous_final_ty(self);
 
         if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
@@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             assert!(pick.unsize.is_none());
         }
 
-        autoderef.finalize();
+        autoderef.finalize(self);
 
         // Write out the final adjustments.
         self.apply_adjustments(self.self_expr, adjustments);
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 858d8c742df..5ecbfcd132c 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -39,6 +39,7 @@ use self::probe::{IsSuggestion, ProbeScope};
 
 pub fn provide(providers: &mut ty::query::Providers) {
     suggest::provide(providers);
+    probe::provide(providers);
 }
 
 #[derive(Clone, Copy, Debug)]
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index dd3c022d53b..190419048b4 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -13,28 +13,35 @@ use super::NoMatchData;
 use super::{CandidateSource, ImplSource, TraitSource};
 use super::suggest;
 
+use check::autoderef::{self, Autoderef};
 use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
 use namespace::Namespace;
+
+use rustc_data_structures::sync::Lrc;
 use rustc::hir;
 use rustc::lint;
 use rustc::session::config::nightly_options;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
-use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
+use rustc::traits::query::{CanonicalTyGoal};
+use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
+use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy};
+use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
 use rustc::ty::GenericParamDefKind;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
 use rustc::infer::{self, InferOk};
+use rustc::infer::canonical::{Canonical, QueryResponse};
+use rustc::infer::canonical::{OriginalQueryValues};
 use rustc::middle::stability;
 use syntax::ast;
 use syntax::util::lev_distance::{lev_distance, find_best_match_for_name};
-use syntax_pos::{Span, symbol::Symbol};
+use syntax_pos::{DUMMY_SP, Span, symbol::Symbol};
 use std::iter;
 use std::mem;
 use std::ops::Deref;
-use std::rc::Rc;
 use std::cmp::max;
 
 use self::CandidateKind::*;
@@ -51,7 +58,12 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     mode: Mode,
     method_name: Option<ast::Ident>,
     return_type: Option<Ty<'tcx>>,
-    steps: Rc<Vec<CandidateStep<'tcx>>>,
+
+    /// This is the OriginalQueryValues for the steps queries
+    /// that are answered in steps.
+    orig_steps_var_values: OriginalQueryValues<'tcx>,
+    steps: Lrc<Vec<CandidateStep<'gcx>>>,
+
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
     impl_dups: FxHashSet<DefId>,
@@ -82,19 +94,6 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
 }
 
 #[derive(Debug)]
-struct CandidateStep<'tcx> {
-    self_ty: Ty<'tcx>,
-    autoderefs: usize,
-    // true if the type results from a dereference of a raw pointer.
-    // when assembling candidates, we include these steps, but not when
-    // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
-    // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
-    // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
-    from_unsafe_deref: bool,
-    unsize: bool,
-}
-
-#[derive(Debug)]
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
     xform_ret_ty: Option<Ty<'tcx>>,
@@ -249,42 +248,111 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       -> Result<R, MethodError<'tcx>>
         where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result<R, MethodError<'tcx>>
     {
-        // FIXME(#18741) -- right now, creating the steps involves evaluating the
-        // `*` operator, which registers obligations that then escape into
-        // the global fulfillment context and thus has global
-        // side-effects. This is a bit of a pain to refactor. So just let
-        // it ride, although it's really not great, and in fact could I
-        // think cause spurious errors. Really though this part should
-        // take place in the `self.probe` below.
+        let mut orig_values = OriginalQueryValues::default();
+        let param_env_and_self_ty =
+            self.infcx.canonicalize_query(
+                &ParamEnvAnd {
+                    param_env: self.param_env,
+                    value: self_ty
+                }, &mut orig_values);
+
         let steps = if mode == Mode::MethodCall {
-            match self.create_steps(span, scope_expr_id, self_ty, is_suggestion) {
-                Some(steps) => steps,
-                None => {
-                    return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
-                                                                     Vec::new(),
-                                                                     Vec::new(),
-                                                                     None,
-                                                                     mode)))
-                }
-            }
+            self.tcx.method_autoderef_steps(param_env_and_self_ty)
         } else {
-            vec![CandidateStep {
-                     self_ty,
-                     autoderefs: 0,
-                     from_unsafe_deref: false,
-                     unsize: false,
-                 }]
+            self.infcx.probe(|_| {
+                // Mode::Path - the deref steps is "trivial". This turns
+                // our CanonicalQuery into a "trivial" QueryResponse. This
+                // is a bit inefficient, but I don't think that writing
+                // special handling for this "trivial case" is a good idea.
+
+                let infcx = &self.infcx;
+                let (ParamEnvAnd {
+                    param_env: _,
+                    value: self_ty
+                }, canonical_inference_vars) =
+                    infcx.instantiate_canonical_with_fresh_inference_vars(
+                        span, &param_env_and_self_ty);
+                debug!("probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
+                       param_env_and_self_ty, self_ty);
+                MethodAutoderefStepsResult {
+                    steps: Lrc::new(vec![CandidateStep {
+                        self_ty: self.make_query_response_ignoring_pending_obligations(
+                            canonical_inference_vars, self_ty),
+                        autoderefs: 0,
+                        from_unsafe_deref: false,
+                        unsize: false,
+                    }]),
+                    opt_bad_ty: None,
+                    reached_recursion_limit: false
+                }
+            })
         };
 
+        // If our autoderef loop had reached the recursion limit,
+        // report an overflow error, but continue going on with
+        // the truncated autoderef list.
+        if steps.reached_recursion_limit {
+            self.probe(|_| {
+                let ty = &steps.steps.last().unwrap_or_else(|| {
+                    span_bug!(span, "reached the recursion limit in 0 steps?")
+                }).self_ty;
+                let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                autoderef::report_autoderef_recursion_limit_error(self.tcx, span,
+                                                                  ty.value);
+            });
+        }
+
+
+        // If we encountered an `_` type or an error type during autoderef, this is
+        // ambiguous.
+        if let Some(bad_ty) = &steps.opt_bad_ty {
+            if is_suggestion.0 {
+                // Ambiguity was encountered during a suggestion. Just keep going.
+                debug!("ProbeContext: encountered ambiguity in suggestion");
+            } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
+                // this case used to be allowed by the compiler,
+                // so we do a future-compat lint here for the 2015 edition
+                // (see https://github.com/rust-lang/rust/issues/46906)
+                if self.tcx.sess.rust_2018() {
+                    span_err!(self.tcx.sess, span, E0699,
+                              "the type of this value must be known \
+                               to call a method on a raw pointer on it");
+                } else {
+                   self.tcx.lint_node(
+                        lint::builtin::TYVAR_BEHIND_RAW_POINTER,
+                        scope_expr_id,
+                        span,
+                        "type annotations needed");
+                }
+            } else {
+                // Encountered a real ambiguity, so abort the lookup. If `ty` is not
+                // an `Err`, report the right "type annotations needed" error pointing
+                // to it.
+                let ty = &bad_ty.ty;
+                let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                let ty = self.structurally_resolved_type(span, ty.value);
+                assert_eq!(ty, self.tcx.types.err);
+                return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
+                                                                 Vec::new(),
+                                                                 Vec::new(),
+                                                                 None,
+                                                                 mode)));
+            }
+        }
+
         debug!("ProbeContext: steps for self_ty={:?} are {:?}",
                self_ty,
                steps);
 
+
         // this creates one big transaction so that all type variables etc
         // that we create during the probe process are removed later
         self.probe(|_| {
             let mut probe_cx = ProbeContext::new(
-                self, span, mode, method_name, return_type, Rc::new(steps), is_suggestion,
+                self, span, mode, method_name, return_type, orig_values,
+                steps.steps, is_suggestion,
             );
 
             probe_cx.assemble_inherent_candidates();
@@ -297,21 +365,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             op(probe_cx)
         })
     }
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    providers.method_autoderef_steps = method_autoderef_steps;
+}
+
+fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+                                          goal: CanonicalTyGoal<'tcx>)
+                                          -> MethodAutoderefStepsResult<'gcx>
+{
+    debug!("method_autoderef_steps({:?})", goal);
 
-    fn create_steps(&self,
-                    span: Span,
-                    scope_expr_id: ast::NodeId,
-                    self_ty: Ty<'tcx>,
-                    is_suggestion: IsSuggestion)
-                    -> Option<Vec<CandidateStep<'tcx>>> {
-        // FIXME: we don't need to create the entire steps in one pass
+    tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
+        let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-        let mut autoderef = self.autoderef(span, self_ty).include_raw_pointers();
+        let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
+            .include_raw_pointers()
+            .silence_errors();
         let mut reached_raw_pointer = false;
         let mut steps: Vec<_> = autoderef.by_ref()
             .map(|(ty, d)| {
                 let step = CandidateStep {
-                    self_ty: ty,
+                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars.clone(), ty),
                     autoderefs: d,
                     from_unsafe_deref: reached_raw_pointer,
                     unsize: false,
@@ -325,68 +402,52 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             .collect();
 
         let final_ty = autoderef.maybe_ambiguous_final_ty();
-        match final_ty.sty {
-            ty::Infer(ty::TyVar(_)) => {
-                // Ended in an inference variable. If we are doing
-                // a real method lookup, this is a hard error because it's
-                // possible that there will be multiple applicable methods.
-                if !is_suggestion.0 {
-                    if reached_raw_pointer
-                    && !self.tcx.features().arbitrary_self_types {
-                        // this case used to be allowed by the compiler,
-                        // so we do a future-compat lint here for the 2015 edition
-                        // (see https://github.com/rust-lang/rust/issues/46906)
-                        if self.tcx.sess.rust_2018() {
-                          span_err!(self.tcx.sess, span, E0699,
-                                    "the type of this value must be known \
-                                     to call a method on a raw pointer on it");
-                        } else {
-                            self.tcx.lint_node(
-                                lint::builtin::TYVAR_BEHIND_RAW_POINTER,
-                                scope_expr_id,
-                                span,
-                                "type annotations needed");
-                        }
-                    } else {
-                        let t = self.structurally_resolved_type(span, final_ty);
-                        assert_eq!(t, self.tcx.types.err);
-                        return None
-                    }
-                } else {
-                    // If we're just looking for suggestions,
-                    // though, ambiguity is no big thing, we can
-                    // just ignore it.
-                }
+        let opt_bad_ty = match final_ty.sty {
+            ty::Infer(ty::TyVar(_)) |
+            ty::Error => {
+                Some(MethodAutoderefBadTy {
+                    reached_raw_pointer,
+                    ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars, final_ty)
+                })
             }
             ty::Array(elem_ty, _) => {
                 let dereferences = steps.len() - 1;
 
                 steps.push(CandidateStep {
-                    self_ty: self.tcx.mk_slice(elem_ty),
+                    self_ty: infcx.make_query_response_ignoring_pending_obligations(
+                        inference_vars, infcx.tcx.mk_slice(elem_ty)),
                     autoderefs: dereferences,
                     // this could be from an unsafe deref if we had
                     // a *mut/const [T; N]
                     from_unsafe_deref: reached_raw_pointer,
                     unsize: true,
                 });
+
+                None
             }
-            ty::Error => return None,
-            _ => (),
-        }
+            _ => None
+        };
 
-        debug!("create_steps: steps={:?}", steps);
+        debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
 
-        Some(steps)
-    }
+        MethodAutoderefStepsResult {
+            steps: Lrc::new(steps),
+            opt_bad_ty: opt_bad_ty.map(Lrc::new),
+            reached_recursion_limit: autoderef.reached_recursion_limit()
+        }
+    })
 }
 
+
 impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
            span: Span,
            mode: Mode,
            method_name: Option<ast::Ident>,
            return_type: Option<Ty<'tcx>>,
-           steps: Rc<Vec<CandidateStep<'tcx>>>,
+           orig_steps_var_values: OriginalQueryValues<'tcx>,
+           steps: Lrc<Vec<CandidateStep<'gcx>>>,
            is_suggestion: IsSuggestion)
            -> ProbeContext<'a, 'gcx, 'tcx> {
         ProbeContext {
@@ -398,7 +459,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
             impl_dups: FxHashSet::default(),
-            steps: steps,
+            orig_steps_var_values,
+            steps,
             static_candidates: Vec::new(),
             allow_similar_names: false,
             private_candidate: None,
@@ -443,18 +505,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn assemble_inherent_candidates(&mut self) {
         let steps = self.steps.clone();
         for step in steps.iter() {
-            self.assemble_probe(step.self_ty);
+            self.assemble_probe(&step.self_ty);
         }
     }
 
-    fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
+    fn assemble_probe(&mut self, self_ty: &Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>) {
         debug!("assemble_probe: self_ty={:?}", self_ty);
         let lang_items = self.tcx.lang_items();
 
-        match self_ty.sty {
+        match self_ty.value.value.sty {
             ty::Dynamic(ref data, ..) => {
                 let p = data.principal();
-                self.assemble_inherent_candidates_from_object(self_ty, p);
+                self.fcx.probe(|_| {
+                    let InferOk { value: self_ty, obligations: _ } =
+                        self.fcx.probe_instantiate_query_response(
+                            self.span, &self.orig_steps_var_values, self_ty)
+                        .unwrap_or_else(|_| {
+                            span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty)
+                        });
+                    self.assemble_inherent_candidates_from_object(self_ty);
+                });
                 self.assemble_inherent_impl_candidates_for_type(p.def_id());
             }
             ty::Adt(def, _) => {
@@ -464,7 +534,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                 self.assemble_inherent_impl_candidates_for_type(did);
             }
             ty::Param(p) => {
-                self.assemble_inherent_candidates_from_param(self_ty, p);
+                self.assemble_inherent_candidates_from_param(p);
             }
             ty::Char => {
                 let lang_def_id = lang_items.char_impl();
@@ -615,11 +685,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn assemble_inherent_candidates_from_object(&mut self,
-                                                self_ty: Ty<'tcx>,
-                                                principal: ty::PolyExistentialTraitRef<'tcx>) {
+                                                self_ty: Ty<'tcx>) {
         debug!("assemble_inherent_candidates_from_object(self_ty={:?})",
                self_ty);
 
+        let principal = match self_ty.sty {
+            ty::Dynamic(ref data, ..) => data.principal(),
+            _ => span_bug!(self.span, "non-object {:?} in assemble_inherent_candidates_from_object",
+                           self_ty)
+        };
+
         // It is illegal to invoke a method on a trait instance that
         // refers to the `Self` type. An error will be reported by
         // `enforce_object_limitations()` if the method refers to the
@@ -642,7 +717,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn assemble_inherent_candidates_from_param(&mut self,
-                                               _rcvr_ty: Ty<'tcx>,
                                                param_ty: ty::ParamTy) {
         // FIXME -- Do we want to commit to this behavior for param bounds?
 
@@ -898,14 +972,22 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                 // a raw pointer
                 !step.self_ty.references_error() && !step.from_unsafe_deref
             }).flat_map(|step| {
-                self.pick_by_value_method(step).or_else(|| {
-                self.pick_autorefd_method(step, hir::MutImmutable).or_else(|| {
-                self.pick_autorefd_method(step, hir::MutMutable)
+                let InferOk { value: self_ty, obligations: _ } =
+                    self.fcx.probe_instantiate_query_response(
+                        self.span, &self.orig_steps_var_values, &step.self_ty
+                    ).unwrap_or_else(|_| {
+                        span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
+                    });
+                self.pick_by_value_method(step, self_ty).or_else(|| {
+                self.pick_autorefd_method(step, self_ty, hir::MutImmutable).or_else(|| {
+                self.pick_autorefd_method(step, self_ty, hir::MutMutable)
             })})})
             .next()
     }
 
-    fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
+    fn pick_by_value_method(&mut self, step: &CandidateStep<'gcx>, self_ty: Ty<'tcx>)
+                            -> Option<PickResult<'tcx>>
+    {
         //! For each type `T` in the step list, this attempts to find a
         //! method where the (transformed) self type is exactly `T`. We
         //! do however do one transformation on the adjustment: if we
@@ -918,12 +1000,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             return None;
         }
 
-        self.pick_method(step.self_ty).map(|r| {
+        self.pick_method(self_ty).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
 
                 // Insert a `&*` or `&mut *` if this is a reference type:
-                if let ty::Ref(_, _, mutbl) = step.self_ty.sty {
+                if let ty::Ref(_, _, mutbl) = step.self_ty.value.value.sty {
                     pick.autoderefs += 1;
                     pick.autoref = Some(mutbl);
                 }
@@ -933,7 +1015,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         })
     }
 
-    fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>, mutbl: hir::Mutability)
+    fn pick_autorefd_method(&mut self,
+                            step: &CandidateStep<'gcx>,
+                            self_ty: Ty<'tcx>,
+                            mutbl: hir::Mutability)
                             -> Option<PickResult<'tcx>> {
         let tcx = self.tcx;
 
@@ -943,14 +1028,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let autoref_ty = tcx.mk_ref(region,
                                     ty::TypeAndMut {
-                                        ty: step.self_ty, mutbl
+                                        ty: self_ty, mutbl
                                     });
         self.pick_method(autoref_ty).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
                 pick.autoref = Some(mutbl);
                 pick.unsize = if step.unsize {
-                    Some(step.self_ty)
+                    Some(self_ty)
                 } else {
                     None
                 };
@@ -1288,7 +1373,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         let steps = self.steps.clone();
         self.probe(|_| {
             let mut pcx = ProbeContext::new(self.fcx, self.span, self.mode, self.method_name,
-                                            self.return_type, steps, IsSuggestion(true));
+                                            self.return_type,
+                                            self.orig_steps_var_values.clone(),
+                                            steps, IsSuggestion(true));
             pcx.allow_similar_names = true;
             pcx.assemble_inherent_candidates();
             pcx.assemble_extension_candidates_for_traits_in_scope(ast::DUMMY_NODE_ID)?;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 957c8d9f19f..77ffdc6811a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -102,10 +102,11 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use middle::lang_items;
 use namespace::Namespace;
+use rustc::infer::{self, InferCtxt, InferOk, InferResult, RegionVariableOrigin};
+use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi::Abi;
-use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
@@ -2555,7 +2556,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty);
         }
-        autoderef.finalize();
+        autoderef.finalize(self);
         result
     }
 
@@ -2572,7 +2573,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       index_ty: Ty<'tcx>)
                       -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
     {
-        let adjusted_ty = autoderef.unambiguous_final_ty();
+        let adjusted_ty = autoderef.unambiguous_final_ty(self);
         debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
                                index_ty={:?})",
                expr,
@@ -2602,7 +2603,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 debug!("try_index_step: success, using overloaded indexing");
                 let method = self.register_infer_ok_obligations(ok);
 
-                let mut adjustments = autoderef.adjust_steps(needs);
+                let mut adjustments = autoderef.adjust_steps(self, needs);
                 if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].sty {
                     let mutbl = match r_mutbl {
                         hir::MutImmutable => AutoBorrowMutability::Immutable,
@@ -3296,9 +3297,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         // of error recovery.
                         self.write_field_index(expr.id, index);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(needs);
+                            let adjustments = autoderef.adjust_steps(self, needs);
                             self.apply_adjustments(base, adjustments);
-                            autoderef.finalize();
+                            autoderef.finalize(self);
 
                             self.tcx.check_stability(field.did, Some(expr.id), expr.span);
                             return field_ty;
@@ -3311,9 +3312,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     if let Ok(index) = fstr.parse::<usize>() {
                         if fstr == index.to_string() {
                             if let Some(field_ty) = tys.get(index) {
-                                let adjustments = autoderef.adjust_steps(needs);
+                                let adjustments = autoderef.adjust_steps(self, needs);
                                 self.apply_adjustments(base, adjustments);
-                                autoderef.finalize();
+                                autoderef.finalize(self);
 
                                 self.write_field_index(expr.id, index);
                                 return field_ty;
@@ -3324,7 +3325,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => {}
             }
         }
-        autoderef.unambiguous_final_ty();
+        autoderef.unambiguous_final_ty(self);
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
@@ -5372,6 +5373,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         };
         (ctxt, result)
     }
+
+    /// Instantiate a QueryResponse in a probe context, without a
+    /// good ObligationCause.
+    fn probe_instantiate_query_response(
+        &self,
+        span: Span,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    ) -> InferResult<'tcx, Ty<'tcx>>
+    {
+        self.instantiate_query_response_and_region_obligations(
+            &traits::ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            original_values,
+            query_result)
+    }
 }
 
 pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 6471e745aa6..e24548cfb23 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -766,7 +766,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                 potential_self_ty, self_ty);
 
             if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
-                autoderef.finalize();
+                autoderef.finalize(fcx);
                 if let Some(mut err) = fcx.demand_eqtype_with_origin(
                     &cause, self_ty, potential_self_ty) {
                     err.emit();
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 8d6fb8b7f39..fdc81a6ed1a 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -90,6 +90,7 @@ This API is completely unstable and subject to change.
 extern crate syntax_pos;
 
 extern crate arena;
+
 #[macro_use] extern crate rustc;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_data_structures;
diff --git a/src/test/run-pass/issue-53843.rs b/src/test/run-pass/issue-53843.rs
new file mode 100644
index 00000000000..4b15ecb3e54
--- /dev/null
+++ b/src/test/run-pass/issue-53843.rs
@@ -0,0 +1,34 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Deref;
+
+pub struct Pin<P>(P);
+
+impl<P, T> Deref for Pin<P>
+where
+    P: Deref<Target=T>,
+{
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
+
+impl<P> Pin<P> {
+    fn poll(self) {}
+}
+
+fn main() {
+    let mut unit = ();
+    let pin = Pin(&mut unit);
+    pin.poll();
+}