Move suggestion list creation to coerce check
This commit is contained in:
parent
164f0105bb
commit
021d97d1c5
4 changed files with 332 additions and 60 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
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);
|
||||
// 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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue