about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2016-10-26 23:53:47 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2016-12-20 11:37:15 +0100
commit021d97d1c5e053176961970ccbcad9f2802e9c91 (patch)
tree2426658ee5c0fe7d2130afc5cc36e5683804f6bd
parent164f0105bb65f31b89e5fb7f368c9e6f5833a3f8 (diff)
downloadrust-021d97d1c5e053176961970ccbcad9f2802e9c91.tar.gz
rust-021d97d1c5e053176961970ccbcad9f2802e9c91.zip
Move suggestion list creation to coerce check
-rw-r--r--src/librustc/infer/error_reporting.rs104
-rw-r--r--src/librustc_typeck/check/demand.rs89
-rw-r--r--src/librustc_typeck/check/method/mod.rs28
-rw-r--r--src/librustc_typeck/check/method/probe.rs173
4 files changed, 333 insertions, 61 deletions
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 98cbd742b10..8fed2a82095 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -83,13 +83,14 @@ use hir::def_id::DefId;
 use infer;
 use middle::region;
 use traits::{ObligationCause, ObligationCauseCode};
-use ty::{self, ImplOrTraitItem, Ty, TyCtxt, TypeFoldable};
+use ty::{self, TyCtxt, TypeFoldable};
 use ty::{Region, ReFree};
 use ty::error::TypeError;
 
 use std::cell::{Cell, RefCell};
 use std::char::from_u32;
 use std::fmt;
+//use std::rc::Rc;
 use syntax::ast;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
@@ -233,6 +234,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
+/*struct MethodInfo<'tcx> {
+    ast: Option<ast::Attribute>,
+    id: DefId,
+    item: Rc<ImplOrTraitItem<'tcx>>,
+}
+
+impl<'tcx> MethodInfo<'tcx> {
+    fn new(ast: Option<ast::Attribute>, id: DefId, item: Rc<ImplOrTraitItem<'tcx>>) -> MethodInfo {
+        MethodInfo {
+            ast: ast,
+            id: id,
+            item: item,
+        }
+    }
+}*/
+
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn report_region_errors(&self,
                                 errors: &Vec<RegionResolutionError<'tcx>>) {
@@ -583,36 +600,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            if let Some((found, (expected_ty, _))) = self.get_ids(values) {
+            //if let Some((found, (expected_ty, expected))) = self.get_ids(values) {
                 // look for expected with found id
-                self.tcx.populate_inherent_implementations_for_type_if_necessary(found);
+                /*self.tcx.populate_inherent_implementations_for_type_if_necessary(found);
                 if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&found) {
-                    let mut methods: Vec<(Option<ast::Attribute>, DefId, ImplOrTraitItem<'tcx>)> = Vec::new();
+                    let mut methods: Vec<MethodInfo> = Vec::new();
                     for impl_ in impl_infos {
                         methods.append(&mut self.tcx
                                                 .impl_or_trait_items(*impl_)
                                                 .iter()
-                                                .map(|&did| (None, did, self.tcx.impl_or_trait_item(did)))
-                                                .filter(|&(_, _, ref x)| {
-                                                    self.matches_return_type(x, &expected_ty)
+                                                .map(|&did| MethodInfo::new(None, did, Rc::new(self.tcx.impl_or_trait_item(did))))
+                                                .filter(|ref x| {
+                                                    self.matches_return_type(&*x.item, &expected_ty)
                                                 })
                                                 .collect());
                     }
-                    let safe_suggestions: Vec<_> = methods.iter()
-                                                  .map(|&(_, ref id, ref x)| (self.find_attr(*id, "safe_suggestion"), id, x))
-                                                  .filter(|&(ref res, _, _)| res.is_some())
-                                                  .collect();
-                    if safe_suggestions.len() > 0 {
-                        for (_, _, method) in safe_suggestions {
-                            println!("safe ==> {:?}", method.name());
-                        }
-                    } else {
-                        for &(_, _, ref method) in methods.iter() {
-                            println!("not safe ==> {:?}", method.name());
+                    for did in self.tcx.sess.cstore.implementations_of_trait(None) {
+                        if did == found {
+                            methods.append(
+                                self.tcx.sess.cstore.impl_or_trait_items(did)
+                                                    .iter()
+                                                    .map(|&did| MethodInfo::new(None, did, Rc::new(self.tcx.impl_or_trait_item(did))))
+                                                    .filter(|ref x| {
+                                                        self.matches_return_type(&*x.item, &expected_ty)
+                                                    })
+                                                    .collect());
+                            ;
                         }
                     }
-                }
-            }
+                    let safe_suggestions: Vec<_> =
+                        methods.iter()
+                               .map(|ref x| MethodInfo::new(self.find_attr(x.id, "safe_suggestion"), x.id, x.item.clone()))
+                               .filter(|ref x| x.ast.is_some())
+                               .collect();
+                    if safe_suggestions.len() > 0 {
+                        println!("safe");
+                        self.get_best_match(&safe_suggestions);
+                    } else {
+                        println!("not safe");
+                        self.get_best_match(&methods);
+                    }*/
+                    /*let mode = probe::Mode::MethodCall;
+                    if let Ok(ret) = self.probe_return(DUMMY_SP, mode, expected, found,                               DUMMY_NODE_ID) {
+                        println!("got it");
+                    } else {
+                        println!("sad...");
+                    }*/
+            //}
         }
 
         diag.span_label(span, &terr);
@@ -625,6 +659,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.note_and_explain_type_err(diag, terr, span);
     }
 
+    /*fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String {
+        let no_argument_methods: Vec<&MethodInfo> =
+            methods.iter()
+                   .filter(|ref x| self.has_not_input_arg(&*x.item))
+                   .collect();
+        if no_argument_methods.len() > 0 {
+            for ref method in no_argument_methods {
+                println!("best match ==> {:?}", method.item.name());
+            }
+        } else {
+            for ref method in methods.iter() {
+                println!("not best ==> {:?}", method.item.name());
+            }
+        }
+        String::new()
+    }
+
     fn find_attr(&self, def_id: DefId, attr_name: &str) -> Option<ast::Attribute> {
         for item in self.tcx.get_attrs(def_id).iter() {
             if item.check_name(attr_name) {
@@ -632,7 +683,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
         }
         None
-    }
+    }*/
 
     pub fn report_and_explain_type_error(&self,
                                          trace: TypeTrace<'tcx>,
@@ -662,6 +713,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /*fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool {
+        match *method {
+            ImplOrTraitItem::MethodTraitItem(ref x) => {
+                x.fty.sig.skip_binder().inputs.len() == 1
+            }
+            _ => false,
+        }
+    }
+
     fn matches_return_type(&self, method: &ImplOrTraitItem<'tcx>, expected: &ty::Ty<'tcx>) -> bool {
         match *method {
             ImplOrTraitItem::MethodTraitItem(ref x) => {
@@ -714,7 +774,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
             _ => None,
         }
-    }
+    }*/
 
     fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index ef1c08bdab5..db711e4a31d 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -14,8 +14,32 @@ use rustc::ty::Ty;
 use rustc::infer::{InferOk};
 use rustc::traits::ObligationCause;
 
-use syntax_pos::Span;
+use syntax::ast;
+use syntax_pos::{self, Span};
 use rustc::hir;
+use rustc::ty::{self, ImplOrTraitItem};
+
+use hir::def_id::DefId;
+
+use std::rc::Rc;
+
+use super::method::probe;
+
+struct MethodInfo<'tcx> {
+    ast: Option<ast::Attribute>,
+    id: DefId,
+    item: Rc<ImplOrTraitItem<'tcx>>,
+}
+
+impl<'tcx> MethodInfo<'tcx> {
+    fn new(ast: Option<ast::Attribute>, id: DefId, item: Rc<ImplOrTraitItem<'tcx>>) -> MethodInfo {
+        MethodInfo {
+            ast: ast,
+            id: id,
+            item: item,
+        }
+    }
+}
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     // Requires that the two types unify, and prints an error message if
@@ -57,7 +81,70 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
             let cause = self.misc(expr.span);
             let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
+            let mode = probe::Mode::MethodCall;
+            if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP, mode, expected,
+                                                   checked_ty, ast::DUMMY_NODE_ID) {
+                let suggestions: Vec<_> =
+                    methods.iter()
+                           .filter_map(|ref x| {
+                            if let Some(id) = self.get_impl_id(&x.item) {
+                                Some(MethodInfo::new(None, id, Rc::new(x.item.clone())))
+                            } else {
+                                None
+                            }})
+                           .collect();
+                let safe_suggestions: Vec<_> =
+                    suggestions.iter()
+                               .map(|ref x| MethodInfo::new(
+                                                self.find_attr(x.id, "safe_suggestion"),
+                                                               x.id,
+                                                               x.item.clone()))
+                               .filter(|ref x| x.ast.is_some())
+                               .collect();
+                if safe_suggestions.len() > 0 {
+                    self.get_best_match(&safe_suggestions);
+                } else {
+                    self.get_best_match(&suggestions);
+                }
+            }
             self.report_mismatched_types(&cause, expected, expr_ty, e);
         }
     }
+
+    fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String {
+        if methods.len() == 1 {
+            println!("unique match ==> {:?}", methods[0].item.name());
+            return String::new();
+        }
+        let no_argument_methods: Vec<&MethodInfo> =
+            methods.iter()
+                   .filter(|ref x| self.has_not_input_arg(&*x.item))
+                   .collect();
+        if no_argument_methods.len() > 0 {
+            for ref method in no_argument_methods {
+                println!("best match ==> {:?}", method.item.name());
+            }
+        } else {
+            for ref method in methods.iter() {
+                println!("not best ==> {:?}", method.item.name());
+            }
+        }
+        String::new()
+    }
+
+    fn get_impl_id(&self, impl_: &ImplOrTraitItem<'tcx>) -> Option<DefId> {
+        match *impl_ {
+            ty::ImplOrTraitItem::MethodTraitItem(ref m) => Some((*m).def_id),
+            _ => None,
+        }
+    }
+
+    fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool {
+        match *method {
+            ImplOrTraitItem::MethodTraitItem(ref x) => {
+                x.fty.sig.skip_binder().inputs.len() == 1
+            }
+            _ => false,
+        }
+    }
 }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index b29eab780e0..0af32c8fe6d 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -30,7 +30,7 @@ pub use self::CandidateSource::*;
 pub use self::suggest::AllTraitsVec;
 
 mod confirm;
-mod probe;
+pub mod probe;
 mod suggest;
 
 pub enum MethodError<'tcx> {
@@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let mode = probe::Mode::MethodCall;
         let self_ty = self.resolve_type_vars_if_possible(&self_ty);
-        let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
+        let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?.remove(0);
 
         if let Some(import_id) = pick.import_id {
             self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -328,7 +328,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         expr_id: ast::NodeId)
                         -> Result<Def, MethodError<'tcx>> {
         let mode = probe::Mode::Path;
-        let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
+        let picks = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
+        let pick = &picks[0];
 
         if let Some(import_id) = pick.import_id {
             self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -353,4 +354,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                            -> Option<ty::AssociatedItem> {
         self.tcx.associated_items(def_id).find(|item| item.name == item_name)
     }
+
+    fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>,
+                           expected: ty::Ty<'tcx>) -> bool {
+        match *method {
+            ty::ImplOrTraitItem::MethodTraitItem(ref x) => {
+                self.can_sub_types(x.fty.sig.skip_binder().output, expected).is_ok()
+            }
+            _ => false,
+        }
+    }
+
+    pub fn impl_or_return_item(&self,
+                               def_id: DefId,
+                               return_type: ty::Ty<'tcx>)
+                               -> Option<ty::ImplOrTraitItem<'tcx>> {
+        self.tcx
+            .impl_or_trait_items(def_id)
+            .iter()
+            .map(|&did| self.tcx.impl_or_trait_item(did))
+            .find(|m| self.matches_return_type(m, return_type))
+    }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 5cb0804b1bc..32de37764f6 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -32,11 +32,16 @@ use std::rc::Rc;
 use self::CandidateKind::*;
 pub use self::PickKind::*;
 
+pub enum LookingFor<'tcx> {
+    MethodName(ast::Name),
+    ReturnType(Ty<'tcx>),
+}
+
 struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
     span: Span,
     mode: Mode,
-    item_name: ast::Name,
+    looking_for: LookingFor<'tcx>,
     steps: Rc<Vec<CandidateStep<'tcx>>>,
     opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate<'tcx>>,
@@ -129,7 +134,7 @@ pub enum PickKind<'tcx> {
                     ty::PolyTraitRef<'tcx>),
 }
 
-pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
+pub type PickResult<'tcx> = Result<Vec<Pick<'tcx>>, MethodError<'tcx>>;
 
 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
 pub enum Mode {
@@ -144,6 +149,20 @@ pub enum Mode {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
+    pub fn probe_return(&self,
+                        span: Span,
+                        mode: Mode,
+                        return_type: Ty<'tcx>,
+                        self_ty: Ty<'tcx>,
+                        scope_expr_id: ast::NodeId)
+                        -> PickResult<'tcx> {
+        debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})",
+               self_ty,
+               return_type,
+               scope_expr_id);
+        self._probe(span, mode, LookingFor::ReturnType(return_type), self_ty, scope_expr_id)
+    }
+
     pub fn probe_method(&self,
                         span: Span,
                         mode: Mode,
@@ -155,6 +174,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                self_ty,
                item_name,
                scope_expr_id);
+        self._probe(span, mode, LookingFor::MethodName(item_name), self_ty, scope_expr_id)
+    }
+
+    fn _probe(&self,
+              span: Span,
+              mode: Mode,
+              looking_for: LookingFor<'tcx>,
+              self_ty: Ty<'tcx>,
+              scope_expr_id: ast::NodeId)
+              -> PickResult<'tcx> {
 
         // FIXME(#18741) -- right now, creating the steps involves evaluating the
         // `*` operator, which registers obligations that then escape into
@@ -207,14 +236,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // that we create during the probe process are removed later
         self.probe(|_| {
             let mut probe_cx =
-                ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps);
+                ProbeContext::new(self, span, mode, looking_for,
+                                  steps, opt_simplified_steps);
             probe_cx.assemble_inherent_candidates();
             probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
             probe_cx.pick()
         })
     }
 
-    fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option<Vec<CandidateStep<'tcx>>> {
+    fn create_steps(&self,
+                    span: Span,
+                    self_ty: Ty<'tcx>)
+                    -> Option<Vec<CandidateStep<'tcx>>> {
         // FIXME: we don't need to create the entire steps in one pass
 
         let mut autoderef = self.autoderef(span, self_ty);
@@ -247,13 +280,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         Some(steps)
     }
+
+    pub fn find_attr(&self, def_id: DefId, attr_name: &str) -> Option<ast::Attribute> {
+        for item in self.tcx.get_attrs(def_id).iter() {
+            if item.check_name(attr_name) {
+                return Some(item.clone());
+            }
+        }
+        None
+    }
 }
 
 impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
            span: Span,
            mode: Mode,
-           item_name: ast::Name,
+           looking_for: LookingFor<'tcx>,
            steps: Vec<CandidateStep<'tcx>>,
            opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
            -> ProbeContext<'a, 'gcx, 'tcx> {
@@ -261,7 +303,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             fcx: fcx,
             span: span,
             mode: mode,
-            item_name: item_name,
+            looking_for: looking_for,
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
             impl_dups: FxHashSet(),
@@ -584,6 +626,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         Ok(())
     }
 
+    fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>,
+                           expected: &ty::Ty<'tcx>) -> bool {
+        match *method {
+            ty::ImplOrTraitItem::MethodTraitItem(ref x) => {
+                self.can_sub_types(x.fty.sig.skip_binder().output, expected).is_ok()
+            }
+            _ => false,
+        }
+    }
+
     fn assemble_extension_candidates_for_trait(&mut self,
                                                trait_def_id: DefId)
                                                -> Result<(), MethodError<'tcx>> {
@@ -591,8 +643,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                trait_def_id);
 
         // Check whether `trait_def_id` defines a method with suitable name:
-        let maybe_item = self.tcx.associated_items(trait_def_id)
-                             .find(|item| item.name == self.item_name);
+        let trait_items = self.tcx.associated_items(trait_def_id);
+        let maybe_item = match self.looking_for {
+            LookingFor::MethodName(item_name) => {
+                trait_items.iter()
+                           .find(|item| item.name == item_name)
+            }
+            LookingFor::ReturnType(item_ty) => {
+                trait_items.iter()
+                           .find(|item| {
+                                self.matches_return_type(item, &item_ty)
+                            })
+            }
+        };
         let item = match maybe_item {
             Some(i) => i,
             None => {
@@ -837,8 +900,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     // THE ACTUAL SEARCH
 
     fn pick(mut self) -> PickResult<'tcx> {
-        if let Some(r) = self.pick_core() {
-            return r;
+        if let Some(ret) = self.pick_core() {
+            return ret;
         }
 
         let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
@@ -855,6 +918,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let out_of_scope_traits = match self.pick_core() {
             Some(Ok(p)) => vec![p.item.container.id()],
+            //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
             Some(Err(MethodError::Ambiguity(v))) => {
                 v.into_iter()
                     .map(|source| {
@@ -896,9 +960,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
         let steps = self.steps.clone();
+        let mut ret = Vec::new();
 
-        // find the first step that works
-        steps.iter().filter_map(|step| self.pick_step(step)).next()
+        for step in steps.iter() {
+            match self.pick_step(step) {
+                Some(Ok(mut elems)) => ret.append(&mut elems),
+                _ => {}
+            }
+        }
+        if ret.len() < 1 {
+            None
+        } else {
+            Some(Ok(ret))
+        }
     }
 
     fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
@@ -929,16 +1003,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         }
 
         self.pick_method(step.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::TyRef(_, mt) = step.self_ty.sty {
-                    pick.autoderefs += 1;
-                    pick.autoref = Some(mt.mutbl);
+            r.map(|mut picks| {
+                for pick in picks.iter_mut() {
+                    pick.autoderefs = step.autoderefs;
+
+                    // Insert a `&*` or `&mut *` if this is a reference type:
+                    if let ty::TyRef(_, mt) = step.self_ty.sty {
+                        pick.autoderefs += 1;
+                        pick.autoref = Some(mt.mutbl);
+                    }
                 }
 
-                pick
+                picks
             })
         })
     }
@@ -949,9 +1025,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         // In general, during probing we erase regions. See
         // `impl_self_ty()` for an explanation.
         let region = tcx.mk_region(ty::ReErased);
+        let mut res = Vec::new();
 
         // Search through mutabilities in order to find one where pick works:
-        [hir::MutImmutable, hir::MutMutable]
+        for _ in [hir::MutImmutable, hir::MutMutable]
             .iter()
             .filter_map(|&m| {
                 let autoref_ty = tcx.mk_ref(region,
@@ -960,19 +1037,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                                                 mutbl: m,
                                             });
                 self.pick_method(autoref_ty).map(|r| {
-                    r.map(|mut pick| {
-                        pick.autoderefs = step.autoderefs;
-                        pick.autoref = Some(m);
-                        pick.unsize = if step.unsize {
-                            Some(step.self_ty)
-                        } else {
-                            None
-                        };
-                        pick
+                    r.map(|mut picks| {
+                        for pick in picks.iter_mut() {
+                            pick.autoderefs = step.autoderefs;
+                            pick.autoref = Some(m);
+                            pick.unsize = if step.unsize {
+                                Some(step.self_ty)
+                            } else {
+                                None
+                            };
+                        }
+                        res.append(&mut picks);
                     })
                 })
-            })
-            .nth(0)
+            }) {}
+
+        if res.len() < 1 {
+            None
+        } else {
+            Some(Ok(res))
+        }
     }
 
     fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
@@ -1002,7 +1086,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                            probes: &[Candidate<'tcx>],
                            possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
                            -> Option<PickResult<'tcx>> {
-        let mut applicable_candidates: Vec<_> = probes.iter()
+        let applicable_candidates: Vec<_> = probes.iter()
             .filter(|&probe| self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
             .collect();
 
@@ -1011,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         if applicable_candidates.len() > 1 {
             match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
                 Some(pick) => {
-                    return Some(Ok(pick));
+                    return Some(Ok(vec![pick]));
                 }
                 None => {}
             }
@@ -1022,7 +1106,15 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             return Some(Err(MethodError::Ambiguity(sources)));
         }
 
-        applicable_candidates.pop().map(|probe| Ok(probe.to_unadjusted_pick()))
+        let ret: Vec<_> = applicable_candidates.iter()
+                                               .map(|probe| probe.to_unadjusted_pick())
+                                               .collect();
+
+        if ret.len() < 1 {
+            None
+        } else {
+            Some(Ok(ret))
+        }
     }
 
     fn consider_probe(&self,
@@ -1262,6 +1354,17 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn associated_item(&self, def_id: DefId) -> Option<ty::AssociatedItem> {
         self.fcx.associated_item(def_id, self.item_name)
     }
+
+    fn impl_or_trait_item(&self, def_id: DefId) -> Option<ty::ImplOrTraitItem<'tcx>> {
+        match self.looking_for {
+            LookingFor::MethodName(name) => {
+                self.fcx.impl_or_trait_item(def_id, name)
+            }
+            LookingFor::ReturnType(return_ty) => {
+                self.fcx.impl_or_return_item(def_id, return_ty)
+            }
+        }
+    }
 }
 
 impl<'tcx> Candidate<'tcx> {