Skip to content

Commit 9549fd5

Browse files
Move suggestion list creation to coerce check
1 parent 05796e2 commit 9549fd5

File tree

4 files changed

+329
-63
lines changed

4 files changed

+329
-63
lines changed

src/librustc/infer/error_reporting.rs

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ use hir::def::Def;
8282
use hir::def_id::DefId;
8383
use infer::{self, TypeOrigin};
8484
use middle::region;
85-
use ty::{self, ImplOrTraitItem, Ty, TyCtxt, TypeFoldable};
85+
use ty::{self, /*ImplOrTraitItem, Ty,*/ TyCtxt, TypeFoldable};
8686
use ty::{Region, ReFree};
8787
use ty::error::TypeError;
8888

8989
use std::cell::{Cell, RefCell};
9090
use std::char::from_u32;
9191
use std::fmt;
92+
//use std::rc::Rc;
9293
use syntax::ast;
9394
use syntax::parse::token;
9495
use syntax::ptr::P;
@@ -232,6 +233,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
232233
}
233234
}
234235

236+
/*struct MethodInfo<'tcx> {
237+
ast: Option<ast::Attribute>,
238+
id: DefId,
239+
item: Rc<ImplOrTraitItem<'tcx>>,
240+
}
241+
242+
impl<'tcx> MethodInfo<'tcx> {
243+
fn new(ast: Option<ast::Attribute>, id: DefId, item: Rc<ImplOrTraitItem<'tcx>>) -> MethodInfo {
244+
MethodInfo {
245+
ast: ast,
246+
id: id,
247+
item: item,
248+
}
249+
}
250+
}*/
251+
235252
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
236253
pub fn report_region_errors(&self,
237254
errors: &Vec<RegionResolutionError<'tcx>>) {
@@ -582,36 +599,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
582599
}
583600
}
584601

585-
if let Some((found, (expected_ty, _))) = self.get_ids(values) {
602+
//if let Some((found, (expected_ty, expected))) = self.get_ids(values) {
586603
// look for expected with found id
587-
self.tcx.populate_inherent_implementations_for_type_if_necessary(found);
604+
/*self.tcx.populate_inherent_implementations_for_type_if_necessary(found);
588605
if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&found) {
589-
let mut methods: Vec<(Option<ast::Attribute>, DefId, ImplOrTraitItem<'tcx>)> = Vec::new();
606+
let mut methods: Vec<MethodInfo> = Vec::new();
590607
for impl_ in impl_infos {
591608
methods.append(&mut self.tcx
592609
.impl_or_trait_items(*impl_)
593610
.iter()
594-
.map(|&did| (None, did, self.tcx.impl_or_trait_item(did)))
595-
.filter(|&(_, _, ref x)| {
596-
self.matches_return_type(x, &expected_ty)
611+
.map(|&did| MethodInfo::new(None, did, Rc::new(self.tcx.impl_or_trait_item(did))))
612+
.filter(|ref x| {
613+
self.matches_return_type(&*x.item, &expected_ty)
597614
})
598615
.collect());
599616
}
600-
let safe_suggestions: Vec<_> = methods.iter()
601-
.map(|&(_, ref id, ref x)| (self.find_attr(*id, "safe_suggestion"), id, x))
602-
.filter(|&(ref res, _, _)| res.is_some())
603-
.collect();
604-
if safe_suggestions.len() > 0 {
605-
for (_, _, method) in safe_suggestions {
606-
println!("safe ==> {:?}", method.name());
607-
}
608-
} else {
609-
for &(_, _, ref method) in methods.iter() {
610-
println!("not safe ==> {:?}", method.name());
617+
for did in self.tcx.sess.cstore.implementations_of_trait(None) {
618+
if did == found {
619+
methods.append(
620+
self.tcx.sess.cstore.impl_or_trait_items(did)
621+
.iter()
622+
.map(|&did| MethodInfo::new(None, did, Rc::new(self.tcx.impl_or_trait_item(did))))
623+
.filter(|ref x| {
624+
self.matches_return_type(&*x.item, &expected_ty)
625+
})
626+
.collect());
627+
;
611628
}
612629
}
613-
}
614-
}
630+
let safe_suggestions: Vec<_> =
631+
methods.iter()
632+
.map(|ref x| MethodInfo::new(self.find_attr(x.id, "safe_suggestion"), x.id, x.item.clone()))
633+
.filter(|ref x| x.ast.is_some())
634+
.collect();
635+
if safe_suggestions.len() > 0 {
636+
println!("safe");
637+
self.get_best_match(&safe_suggestions);
638+
} else {
639+
println!("not safe");
640+
self.get_best_match(&methods);
641+
}*/
642+
/*let mode = probe::Mode::MethodCall;
643+
if let Ok(ret) = self.probe_return(DUMMY_SP, mode, expected, found, DUMMY_NODE_ID) {
644+
println!("got it");
645+
} else {
646+
println!("sad...");
647+
}*/
648+
//}
615649
}
616650

617651
diag.span_label(span, &terr);
@@ -624,14 +658,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
624658
self.tcx.note_and_explain_type_err(diag, terr, span);
625659
}
626660

661+
/*fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String {
662+
let no_argument_methods: Vec<&MethodInfo> =
663+
methods.iter()
664+
.filter(|ref x| self.has_not_input_arg(&*x.item))
665+
.collect();
666+
if no_argument_methods.len() > 0 {
667+
for ref method in no_argument_methods {
668+
println!("best match ==> {:?}", method.item.name());
669+
}
670+
} else {
671+
for ref method in methods.iter() {
672+
println!("not best ==> {:?}", method.item.name());
673+
}
674+
}
675+
String::new()
676+
}
677+
627678
fn find_attr(&self, def_id: DefId, attr_name: &str) -> Option<ast::Attribute> {
628679
for item in self.tcx.get_attrs(def_id).iter() {
629680
if item.check_name(attr_name) {
630681
return Some(item.clone());
631682
}
632683
}
633684
None
634-
}
685+
}*/
635686

636687
pub fn report_and_explain_type_error(&self,
637688
trace: TypeTrace<'tcx>,
@@ -661,6 +712,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
661712
}
662713
}
663714

715+
/*fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool {
716+
match *method {
717+
ImplOrTraitItem::MethodTraitItem(ref x) => {
718+
x.fty.sig.skip_binder().inputs.len() == 1
719+
}
720+
_ => false,
721+
}
722+
}
723+
664724
fn matches_return_type(&self, method: &ImplOrTraitItem<'tcx>, expected: &ty::Ty<'tcx>) -> bool {
665725
match *method {
666726
ImplOrTraitItem::MethodTraitItem(ref x) => {
@@ -713,7 +773,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
713773
}
714774
_ => None,
715775
}
716-
}
776+
}*/
717777

718778
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
719779
&self,

src/librustc_typeck/check/demand.rs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,32 @@ use check::FnCtxt;
1313
use rustc::ty::Ty;
1414
use rustc::infer::{InferOk, TypeOrigin};
1515

16-
use syntax_pos::Span;
16+
use syntax::ast;
17+
use syntax_pos::{self, Span};
1718
use rustc::hir;
19+
use rustc::ty::{self, ImplOrTraitItem};
20+
21+
use hir::def_id::DefId;
22+
23+
use std::rc::Rc;
24+
25+
use super::method::probe;
26+
27+
struct MethodInfo<'tcx> {
28+
ast: Option<ast::Attribute>,
29+
id: DefId,
30+
item: Rc<ImplOrTraitItem<'tcx>>,
31+
}
32+
33+
impl<'tcx> MethodInfo<'tcx> {
34+
fn new(ast: Option<ast::Attribute>, id: DefId, item: Rc<ImplOrTraitItem<'tcx>>) -> MethodInfo {
35+
MethodInfo {
36+
ast: ast,
37+
id: id,
38+
item: item,
39+
}
40+
}
41+
}
1842

1943
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2044
// Requires that the two types unify, and prints an error message if
@@ -58,7 +82,70 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5882
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
5983
let origin = TypeOrigin::Misc(expr.span);
6084
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
85+
let mode = probe::Mode::MethodCall;
86+
if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP, mode, expected,
87+
checked_ty, ast::DUMMY_NODE_ID) {
88+
let suggestions: Vec<_> =
89+
methods.iter()
90+
.filter_map(|ref x| {
91+
if let Some(id) = self.get_impl_id(&x.item) {
92+
Some(MethodInfo::new(None, id, Rc::new(x.item.clone())))
93+
} else {
94+
None
95+
}})
96+
.collect();
97+
let safe_suggestions: Vec<_> =
98+
suggestions.iter()
99+
.map(|ref x| MethodInfo::new(
100+
self.find_attr(x.id, "safe_suggestion"),
101+
x.id,
102+
x.item.clone()))
103+
.filter(|ref x| x.ast.is_some())
104+
.collect();
105+
if safe_suggestions.len() > 0 {
106+
self.get_best_match(&safe_suggestions);
107+
} else {
108+
self.get_best_match(&suggestions);
109+
}
110+
}
61111
self.report_mismatched_types(origin, expected, expr_ty, e);
62112
}
63113
}
114+
115+
fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String {
116+
if methods.len() == 1 {
117+
println!("unique match ==> {:?}", methods[0].item.name());
118+
return String::new();
119+
}
120+
let no_argument_methods: Vec<&MethodInfo> =
121+
methods.iter()
122+
.filter(|ref x| self.has_not_input_arg(&*x.item))
123+
.collect();
124+
if no_argument_methods.len() > 0 {
125+
for ref method in no_argument_methods {
126+
println!("best match ==> {:?}", method.item.name());
127+
}
128+
} else {
129+
for ref method in methods.iter() {
130+
println!("not best ==> {:?}", method.item.name());
131+
}
132+
}
133+
String::new()
134+
}
135+
136+
fn get_impl_id(&self, impl_: &ImplOrTraitItem<'tcx>) -> Option<DefId> {
137+
match *impl_ {
138+
ty::ImplOrTraitItem::MethodTraitItem(ref m) => Some((*m).def_id),
139+
_ => None,
140+
}
141+
}
142+
143+
fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool {
144+
match *method {
145+
ImplOrTraitItem::MethodTraitItem(ref x) => {
146+
x.fty.sig.skip_binder().inputs.len() == 1
147+
}
148+
_ => false,
149+
}
150+
}
64151
}

src/librustc_typeck/check/method/mod.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub use self::CandidateSource::*;
3030
pub use self::suggest::AllTraitsVec;
3131

3232
mod confirm;
33-
mod probe;
33+
pub mod probe;
3434
mod suggest;
3535

3636
pub enum MethodError<'tcx> {
@@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
130130

131131
let mode = probe::Mode::MethodCall;
132132
let self_ty = self.resolve_type_vars_if_possible(&self_ty);
133-
let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
133+
let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?.remove(0);
134134

135135
if let Some(import_id) = pick.import_id {
136136
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -353,7 +353,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
353353
expr_id: ast::NodeId)
354354
-> Result<Def, MethodError<'tcx>> {
355355
let mode = probe::Mode::Path;
356-
let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
356+
let picks = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
357+
let pick = &picks[0];
357358

358359
if let Some(import_id) = pick.import_id {
359360
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -381,4 +382,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
381382
.map(|&did| self.tcx.impl_or_trait_item(did))
382383
.find(|m| m.name() == item_name)
383384
}
385+
386+
fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>,
387+
expected: ty::Ty<'tcx>) -> bool {
388+
match *method {
389+
ty::ImplOrTraitItem::MethodTraitItem(ref x) => {
390+
self.can_sub_types(x.fty.sig.skip_binder().output, expected).is_ok()
391+
}
392+
_ => false,
393+
}
394+
}
395+
396+
pub fn impl_or_return_item(&self,
397+
def_id: DefId,
398+
return_type: ty::Ty<'tcx>)
399+
-> Option<ty::ImplOrTraitItem<'tcx>> {
400+
self.tcx
401+
.impl_or_trait_items(def_id)
402+
.iter()
403+
.map(|&did| self.tcx.impl_or_trait_item(did))
404+
.find(|m| self.matches_return_type(m, return_type))
405+
}
384406
}

0 commit comments

Comments
 (0)