Skip to content

Commit 021d97d

Browse files
Move suggestion list creation to coerce check
1 parent 164f010 commit 021d97d

File tree

4 files changed

+333
-61
lines changed

4 files changed

+333
-61
lines changed

src/librustc/infer/error_reporting.rs

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,14 @@ use hir::def_id::DefId;
8383
use infer;
8484
use middle::region;
8585
use traits::{ObligationCause, ObligationCauseCode};
86-
use ty::{self, ImplOrTraitItem, Ty, TyCtxt, TypeFoldable};
86+
use ty::{self, TyCtxt, TypeFoldable};
8787
use ty::{Region, ReFree};
8888
use ty::error::TypeError;
8989

9090
use std::cell::{Cell, RefCell};
9191
use std::char::from_u32;
9292
use std::fmt;
93+
//use std::rc::Rc;
9394
use syntax::ast;
9495
use syntax::ptr::P;
9596
use syntax::symbol::Symbol;
@@ -233,6 +234,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
233234
}
234235
}
235236

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

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

618652
diag.span_label(span, &terr);
@@ -625,14 +659,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
625659
self.tcx.note_and_explain_type_err(diag, terr, span);
626660
}
627661

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

637688
pub fn report_and_explain_type_error(&self,
638689
trace: TypeTrace<'tcx>,
@@ -662,6 +713,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
662713
}
663714
}
664715

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

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

src/librustc_typeck/check/demand.rs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,32 @@ use rustc::ty::Ty;
1414
use rustc::infer::{InferOk};
1515
use rustc::traits::ObligationCause;
1616

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

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

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);
@@ -328,7 +328,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
328328
expr_id: ast::NodeId)
329329
-> Result<Def, MethodError<'tcx>> {
330330
let mode = probe::Mode::Path;
331-
let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
331+
let picks = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
332+
let pick = &picks[0];
332333

333334
if let Some(import_id) = pick.import_id {
334335
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -353,4 +354,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
353354
-> Option<ty::AssociatedItem> {
354355
self.tcx.associated_items(def_id).find(|item| item.name == item_name)
355356
}
357+
358+
fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>,
359+
expected: ty::Ty<'tcx>) -> bool {
360+
match *method {
361+
ty::ImplOrTraitItem::MethodTraitItem(ref x) => {
362+
self.can_sub_types(x.fty.sig.skip_binder().output, expected).is_ok()
363+
}
364+
_ => false,
365+
}
366+
}
367+
368+
pub fn impl_or_return_item(&self,
369+
def_id: DefId,
370+
return_type: ty::Ty<'tcx>)
371+
-> Option<ty::ImplOrTraitItem<'tcx>> {
372+
self.tcx
373+
.impl_or_trait_items(def_id)
374+
.iter()
375+
.map(|&did| self.tcx.impl_or_trait_item(did))
376+
.find(|m| self.matches_return_type(m, return_type))
377+
}
356378
}

0 commit comments

Comments
 (0)