From 044b07dd2089d8e3786c5939fc948710d722845f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 30 Nov 2016 17:00:08 -0800 Subject: [PATCH] Update to last master --- src/librustc_typeck/check/demand.rs | 131 +++++----------------- src/librustc_typeck/check/method/probe.rs | 32 +++--- src/librustc_typeck/check/mod.rs | 2 +- 3 files changed, 44 insertions(+), 121 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 4704193da0c4..c09fde04ba4c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -17,7 +17,8 @@ use rustc::traits::ObligationCause; use syntax::ast; use syntax_pos::{self, Span}; use rustc::hir; -use rustc::ty::{self, ImplOrTraitItem}; +use rustc::hir::def::Def; +use rustc::ty::{self, AssociatedItem}; use super::method::probe; @@ -31,11 +32,7 @@ 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 + self.report_mismatched_types(&cause, expected, actual, e).emit(); } } } @@ -59,74 +56,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// This function is used to determine potential "simple" improvements or users' errors and - /// provide them useful help. For example: - /// - /// ``` - /// fn some_fn(s: &str) {} - /// - /// let x = "hey!".to_owned(); - /// some_fn(x); // error - /// ``` - /// - /// No need to find every potential function which could make a coercion to transform a - /// `String` into a `&str` since a `&` would do the trick! - /// - /// In addition of this check, it also checks between references mutability state. If the - /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with - /// `&mut`!". - fn check_ref(&self, - expr: &hir::Expr, - checked_ty: Ty<'tcx>, - expected: Ty<'tcx>) - -> Option { - match (&expected.sty, &checked_ty.sty) { - (&ty::TyRef(_, expected_mutability), - &ty::TyRef(_, checked_mutability)) => { - // check if there is a mutability difference - if checked_mutability.mutbl == hir::Mutability::MutImmutable && - checked_mutability.mutbl != expected_mutability.mutbl && - self.can_sub_types(&checked_mutability.ty, - expected_mutability.ty).is_ok() { - if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { - return Some(format!("try with `&mut {}`", &src.replace("&", ""))); - } - } - None - } - (&ty::TyRef(_, mutability), _) => { - // Check if it can work when put into a ref. For example: - // - // ``` - // fn bar(x: &mut i32) {} - // - // let x = 0u32; - // bar(&x); // error, expected &mut - // ``` - let ref_ty = match mutability.mutbl { - hir::Mutability::MutMutable => self.tcx.mk_mut_ref( - self.tcx.mk_region(ty::ReStatic), - checked_ty), - hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( - self.tcx.mk_region(ty::ReStatic), - checked_ty), - }; - if self.try_coerce(expr, ref_ty, expected).is_ok() { - if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { - return Some(format!("try with `{}{}`", - match mutability.mutbl { - hir::Mutability::MutMutable => "&mut ", - hir::Mutability::MutImmutable => "&", - }, - &src)); - } - } - None - } - _ => None, - } - } - // Checks that the type of `expr` can be coerced to `expected`. pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); @@ -134,37 +63,24 @@ 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; - let suggestions = if let Some(s) = self.check_ref(expr, checked_ty, expected) { - Some(s) - } else { - let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, - mode, - expected, - checked_ty, - ast::DUMMY_NODE_ID); - if suggestions.len() > 0 { - Some(format!("here are some functions which \ - might fulfill your needs:\n - {}", - self.get_best_match(&suggestions))) - } else { - None - } + let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, + mode, + expected, + checked_ty, + ast::DUMMY_NODE_ID); + let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); + if suggestions.len() > 0 { + err.help(&format!("here are some functions which \ + might fulfill your needs:\n - {}", + self.get_best_match(&suggestions))); }; - 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 format_method_suggestion(&self, method: &ImplOrTraitItem<'tcx>) -> String { + fn format_method_suggestion(&self, method: &AssociatedItem) -> String { format!(".{}({})", - method.name(), + method.name, if self.has_not_input_arg(method) { "" } else { @@ -172,7 +88,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } - fn display_suggested_methods(&self, methods: &[ImplOrTraitItem<'tcx>]) -> String { + fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> String { methods.iter() .take(5) .map(|method| self.format_method_suggestion(&*method)) @@ -180,7 +96,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .join("\n - ") } - fn get_best_match(&self, methods: &[ImplOrTraitItem<'tcx>]) -> String { + fn get_best_match(&self, methods: &[AssociatedItem]) -> String { let no_argument_methods: Vec<_> = methods.iter() .filter(|ref x| self.has_not_input_arg(&*x)) @@ -194,10 +110,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // This function checks if the method isn't static and takes other arguments than `self`. - fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool { - match *method { - ImplOrTraitItem::MethodTraitItem(ref x) => { - x.fty.sig.skip_binder().inputs.len() == 1 + fn has_not_input_arg(&self, method: &AssociatedItem) -> bool { + match method.def() { + Def::Method(def_id) => { + match self.tcx.item_type(def_id).sty { + ty::TypeVariants::TyFnDef(_, _, fty) => { + fty.sig.skip_binder().inputs.len() == 1 + } + _ => false, + } } _ => false, } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a1393aa882ea..04d714f269a5 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,7 +16,6 @@ use super::suggest; use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; -use rustc::infer::InferOk; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; @@ -162,7 +161,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_type: Ty<'tcx>, self_ty: Ty<'tcx>, scope_expr_id: ast::NodeId) - -> Vec> { + -> Vec { debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})", self_ty, return_type, @@ -643,13 +642,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Ok(()) } - pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>, + pub fn matches_return_type(&self, method: &ty::AssociatedItem, expected: ty::Ty<'tcx>) -> bool { - match *method { - ty::ImplOrTraitItem::MethodTraitItem(ref x) => { + match method.def() { + Def::Method(def_id) => { + let fty = self.tcx.item_type(def_id).fn_sig(); self.probe(|_| { - let substs = self.fresh_substs_for_item(self.span, method.def_id()); - let output = x.fty.sig.output().subst(self.tcx, substs); + let substs = self.fresh_substs_for_item(self.span, method.def_id); + let output = fty.output().subst(self.tcx, substs); let (output, _) = self.replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, &output); self.can_sub_types(output, expected).is_ok() @@ -906,12 +906,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn candidate_method_names(&self) -> Vec { - let mut set = FnvHashSet(); + let mut set = FxHashSet(); let mut names: Vec<_> = self.inherent_candidates .iter() .chain(&self.extension_candidates) - .map(|candidate| candidate.item.name()) + .map(|candidate| candidate.item.name) .filter(|&name| set.insert(name)) .collect(); @@ -1353,19 +1353,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. fn associated_item(&self, def_id: DefId) -> Option { - self.fcx.associated_item(def_id, self.item_name) + match self.looking_for { + LookingFor::MethodName(item_name) => self.fcx.associated_item(def_id, item_name), + _ => None, + } } - fn impl_or_trait_item(&self, def_id: DefId) -> Option> { + fn impl_or_trait_item(&self, def_id: DefId) -> Option { match self.looking_for { LookingFor::MethodName(name) => { - self.fcx.impl_or_trait_item(def_id, name) + self.fcx.associated_item(def_id, name) } LookingFor::ReturnType(return_ty) => { self.tcx - .impl_or_trait_items(def_id) - .iter() - .map(|&did| self.tcx.impl_or_trait_item(did)) + .associated_items(def_id) + .map(|did| self.tcx.associated_item(did.def_id)) .find(|m| self.matches_return_type(m, return_ty)) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 92d96b407192..3086721852de 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3697,7 +3697,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match result { Ok(ty) => ctxt.unified = ty, Err(err) => { - self.report_mismatched_types(&cause, ctxt.unified, e_ty, err); + self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(); } }