From 07a3ede5f2ee2db963b73453f43126a71f5092bd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Oct 2016 00:43:00 +0200 Subject: [PATCH] Return DiagnosticBuilder to add help suggestions --- src/librustc/infer/error_reporting.rs | 154 -------------------------- src/librustc/infer/mod.rs | 4 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/demand.rs | 65 +++++++---- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- 7 files changed, 50 insertions(+), 183 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 8fed2a820951..a67af1d5dcc3 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -90,7 +90,6 @@ 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; @@ -234,22 +233,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -/*struct MethodInfo<'tcx> { - ast: Option, - id: DefId, - item: Rc>, -} - -impl<'tcx> MethodInfo<'tcx> { - fn new(ast: Option, id: DefId, item: Rc>) -> MethodInfo { - MethodInfo { - ast: ast, - id: id, - item: item, - } - } -}*/ - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_region_errors(&self, errors: &Vec>) { @@ -599,54 +582,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag.note_expected_found(&"type", &expected, &found); } } - - //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); - if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&found) { - let mut methods: Vec = Vec::new(); - for impl_ in impl_infos { - methods.append(&mut self.tcx - .impl_or_trait_items(*impl_) - .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()); - } - 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); @@ -659,32 +594,6 @@ 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 { - for item in self.tcx.get_attrs(def_id).iter() { - if item.check_name(attr_name) { - return Some(item.clone()); - } - } - None - }*/ - pub fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) @@ -713,69 +622,6 @@ 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) => { - self.can_sub_types(x.fty.sig.skip_binder().output, expected).is_ok() - } - _ => false, - } - } - - fn get_id(&self, ty: Ty<'tcx>) -> Option { - match ty.sty { - ty::TyTrait(box ref data) => Some(data.principal.def_id()), - ty::TyAdt(def, _) => Some(def.did), - ty::TyBox(ref ty) => self.get_id(*ty), // since we don't want box's methods by type's - ty::TyChar => self.tcx.lang_items.char_impl(), - ty::TyStr => self.tcx.lang_items.str_impl(), - ty::TySlice(_) => self.tcx.lang_items.slice_impl(), - ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { - self.tcx.lang_items.const_ptr_impl() - } - ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { - self.tcx.lang_items.mut_ptr_impl() - } - ty::TyInt(ast::IntTy::I8) => self.tcx.lang_items.i8_impl(), - ty::TyInt(ast::IntTy::I16) => self.tcx.lang_items.i16_impl(), - ty::TyInt(ast::IntTy::I32) => self.tcx.lang_items.i32_impl(), - ty::TyInt(ast::IntTy::I64) => self.tcx.lang_items.i64_impl(), - ty::TyInt(ast::IntTy::Is) => self.tcx.lang_items.isize_impl(), - ty::TyUint(ast::UintTy::U8) => self.tcx.lang_items.u8_impl(), - ty::TyUint(ast::UintTy::U16) => self.tcx.lang_items.u16_impl(), - ty::TyUint(ast::UintTy::U32) => self.tcx.lang_items.u32_impl(), - ty::TyUint(ast::UintTy::U64) => self.tcx.lang_items.u64_impl(), - ty::TyUint(ast::UintTy::Us) => self.tcx.lang_items.usize_impl(), - ty::TyFloat(ast::FloatTy::F32) => self.tcx.lang_items.f32_impl(), - ty::TyFloat(ast::FloatTy::F64) => self.tcx.lang_items.f64_impl(), - _ => None, - } - } - - // Yep, returned value super ugly. it'll certainly become `Option<(DefId, ty::Ty<'tcx>)>` - // in a close future. Or maybe a struct? - fn get_ids(&self, values: Option>) -> Option<(DefId, (ty::Ty<'tcx>, DefId))> { - match values { - // for now, only handling non trait types - Some(infer::Types(ref exp_found)) => { - match (self.get_id(exp_found.found), self.get_id(exp_found.expected)) { - (Some(found), Some(expected)) => Some((found, (exp_found.expected, expected))), - _ => None, - } - } - _ => None, - } - }*/ - fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9b58334e6580..6bbe40950b75 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1367,9 +1367,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - err: TypeError<'tcx>) { + err: TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { let trace = TypeTrace::types(cause, true, expected, actual); - self.report_and_explain_type_error(trace, &err).emit(); + self.report_and_explain_type_error(trace, &err) } pub fn report_conflicting_default_types(&self, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 624201eaab69..ff50ee11b390 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { (result_ty, arm_ty) }; - self.report_mismatched_types(&cause, expected, found, e); + self.report_mismatched_types(&cause, expected, found, e).emit(); self.tcx.types.err } }; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index db711e4a31db..01a961949bc3 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -51,7 +51,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.register_predicates(obligations); }, Err(e) => { +<<<<<<< HEAD self.report_mismatched_types(&cause, expected, actual, e); +======= + self.report_mismatched_types(origin, expected, actual, e).emit(); +>>>>>>> Return DiagnosticBuilder to add help suggestions } } } @@ -70,7 +74,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.register_predicates(obligations); }, Err(e) => { - self.report_mismatched_types(cause, expected, actual, e); + self.report_mismatched_types(cause, expected, actual, e).emit(); } } } @@ -82,7 +86,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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, + let suggestions = + if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP, mode, expected, checked_ty, ast::DUMMY_NODE_ID) { let suggestions: Vec<_> = methods.iter() @@ -93,43 +98,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + if suggestions.len() > 0 { + 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(); + Some(if safe_suggestions.len() > 0 { + self.get_best_match(&safe_suggestions) + } else { + format!("no safe suggestion found, here are functions which match your \ + needs but be careful:\n - {}", + self.get_best_match(&suggestions)) + }) } else { - self.get_best_match(&suggestions); + None } + } else { + None + }; + let mut err = self.report_mismatched_types(origin, expected, expr_ty, e); + if let Some(suggestions) = suggestions { + err.help(&suggestions); } +<<<<<<< HEAD self.report_mismatched_types(&cause, expected, expr_ty, e); +======= + err.emit(); +>>>>>>> Return DiagnosticBuilder to add help suggestions } } fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String { if methods.len() == 1 { - println!("unique match ==> {:?}", methods[0].item.name()); - return String::new(); + return format!(" - {}", methods[0].item.name()); } 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()); - } + no_argument_methods.iter() + .map(|method| format!("{}", method.item.name())) + .collect::>() + .join("\n - ") } else { - for ref method in methods.iter() { - println!("not best ==> {:?}", method.item.name()); - } + methods.iter() + .map(|method| format!("{}", method.item.name())) + .collect::>() + .join("\n - ") } - String::new() } fn get_impl_id(&self, impl_: &ImplOrTraitItem<'tcx>) -> Option { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 58dff935a16b..92d96b407192 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2986,7 +2986,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } Err(e) => { - self.report_mismatched_types(&cause, expected_ty, found_ty, e); + self.report_mismatched_types(&cause, expected_ty, found_ty, e).emit(); self.tcx.types.err } } @@ -3880,7 +3880,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match result { Ok(ty) => unified = ty, Err(e) => { - self.report_mismatched_types(&cause, unified, e_ty, e); + self.report_mismatched_types(&cause, unified, e_ty, e).emit(); } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f575d4d8bab7..0e5a16987c12 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -356,7 +356,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { infcx.report_mismatched_types(&cause, mk_ptr(mt_b.ty), target, - ty::error::TypeError::Mutability); + ty::error::TypeError::Mutability).emit(); } (mt_a.ty, mt_b.ty, unsize_trait, None) }; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 50d4c3cd0c99..ec17813ed2a5 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -185,7 +185,7 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, true } Err(err) => { - infcx.report_mismatched_types(cause, expected, actual, err); + infcx.report_mismatched_types(cause, expected, actual, err).emit(); false } }