about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2018-09-15 20:23:30 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2018-12-15 00:41:28 +0200
commitbe2bb4fa1d5788ba1d2df757090daf5fa75df4a2 (patch)
treea8b100ff4c92272bff2f505a6fbe906974e9001d
parent832ac110df0f58627ec1134bb9caf60d41f93f3c (diff)
downloadrust-be2bb4fa1d5788ba1d2df757090daf5fa75df4a2.tar.gz
rust-be2bb4fa1d5788ba1d2df757090daf5fa75df4a2.zip
implement "isolated" autoderef using the Canonical mechanism
-rw-r--r--src/librustc/infer/canonical/query_response.rs27
-rw-r--r--src/librustc_typeck/check/autoderef.rs36
-rw-r--r--src/librustc_typeck/check/method/probe.rs266
-rw-r--r--src/librustc_typeck/check/mod.rs19
-rw-r--r--src/librustc_typeck/lib.rs1
5 files changed, 239 insertions, 110 deletions
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index 8d2b1d74c55..e225b12366f 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -116,6 +116,33 @@ 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.
+    ///
+    /// TDFX(nikomatsakis): not sure this is the best name.
+    pub fn make_query_response_with_obligations_pending<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_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index c13ed1bd9d0..3fce66a19d8 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -19,7 +19,7 @@ use rustc::ty::{ToPredicate, TypeFoldable};
 use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 
 use syntax_pos::Span;
-use syntax::ast::{NodeId, Ident};
+use syntax::ast::{self, Ident};
 
 use std::iter;
 
@@ -31,7 +31,7 @@ enum AutoderefKind {
 
 pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    body_id: NodeId,
+    body_id: ast::NodeId,
     param_env: ty::ParamEnv<'tcx>,
     steps: Vec<(Ty<'tcx>, AutoderefKind)>,
     cur_ty: Ty<'tcx>,
@@ -107,6 +107,26 @@ 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,
+            span,
+        }
+    }
+
     fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         debug!("overloaded_deref_ty({:?})", ty);
 
@@ -231,17 +251,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
-        Autoderef {
-            infcx: &self.infcx,
-            body_id: self.body_id,
-            param_env: self.param_env,
-            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/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index dd3c022d53b..36aad42e26b 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -13,20 +13,24 @@ use super::NoMatchData;
 use super::{CandidateSource, ImplSource, TraitSource};
 use super::suggest;
 
+use check::autoderef::Autoderef;
 use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
 use namespace::Namespace;
+
 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::ty::{self, ParamEnv, 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};
@@ -51,7 +55,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: Rc<Vec<CandidateStep<'gcx>>>,
+
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
     impl_dups: FxHashSet<DefId>,
@@ -82,8 +91,8 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
 }
 
 #[derive(Debug)]
-struct CandidateStep<'tcx> {
-    self_ty: Ty<'tcx>,
+struct CandidateStep<'gcx> {
+    self_ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
     autoderefs: usize,
     // true if the type results from a dereference of a raw pointer.
     // when assembling candidates, we include these steps, but not when
@@ -249,42 +258,86 @@ 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(&(self.param_env, self_ty), &mut orig_values);
+
+        // FIXME: consider caching this "whole op" here.
         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)))
-                }
-            }
+            create_steps_inner(self.tcx.global_tcx(), span, 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 ((_, self_ty), canonical_inference_vars) =
+                    infcx.instantiate_canonical_with_fresh_inference_vars(
+                        span, &param_env_and_self_ty);
+                debug!("param_env_and_self_ty={:?} self_ty={:?}", param_env_and_self_ty, self_ty);
+                CreateStepsResult {
+                    steps: vec![CandidateStep {
+                        self_ty: self.make_query_response_with_obligations_pending(
+                            canonical_inference_vars, self_ty),
+                        autoderefs: 0,
+                        from_unsafe_deref: false,
+                        unsize: false,
+                    }],
+                    opt_bad_ty: None
+                }
+            })
         };
 
+        // If we encountered an `_` type or an error type during autoderef, this is
+        // ambiguous.
+        if let Some(CreateStepsBadTy { reached_raw_pointer, 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 *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 = self.probe_instantiate_query_response(span, &orig_values, ty)
+                    .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
+                let t = self.structurally_resolved_type(span, ty.value);
+                assert_eq!(t, 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,
+                Rc::new(steps.steps), is_suggestion,
             );
 
             probe_cx.assemble_inherent_candidates();
@@ -297,21 +350,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             op(probe_cx)
         })
     }
+}
+
+#[derive(Debug)]
+struct CreateStepsResult<'gcx> {
+    steps: Vec<CandidateStep<'gcx>>,
+    opt_bad_ty: Option<CreateStepsBadTy<'gcx>>
+}
 
-    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
+#[derive(Debug)]
+struct CreateStepsBadTy<'gcx> {
+    reached_raw_pointer: bool,
+    ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
+}
 
-        let mut autoderef = self.autoderef(span, self_ty).include_raw_pointers();
+fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+                                      span: Span,
+                                      pe_and_self_ty: Canonical<'gcx, (ParamEnv<'gcx>, Ty<'gcx>)>)
+                                      -> CreateStepsResult<'gcx>
+{
+    tcx.infer_ctxt().enter(|ref infcx| {
+        let ((param_env, self_ty), inference_vars) =
+            infcx.instantiate_canonical_with_fresh_inference_vars(span, &pe_and_self_ty);
+        let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, span, self_ty)
+            .include_raw_pointers();
         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_with_obligations_pending(
+                        inference_vars.clone(), ty),
                     autoderefs: d,
                     from_unsafe_deref: reached_raw_pointer,
                     unsize: false,
@@ -325,68 +393,48 @@ 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(CreateStepsBadTy {
+                    reached_raw_pointer,
+                    ty: infcx.make_query_response_with_obligations_pending(
+                        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_with_obligations_pending(
+                        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!("create_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
 
-        Some(steps)
-    }
+        CreateStepsResult { steps, opt_bad_ty }
+    })
 }
 
+
 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: Rc<Vec<CandidateStep<'gcx>>>,
            is_suggestion: IsSuggestion)
            -> ProbeContext<'a, 'gcx, 'tcx> {
         ProbeContext {
@@ -398,7 +446,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 +492,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 +521,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 +672,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 +704,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 +959,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 +987,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 +1002,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 +1015,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 +1360,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 d4c010b45df..7aec741cf4d 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;
@@ -5349,6 +5350,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/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;