From 4a3acfd9371f59368108ad5e7be28f4268ed862b Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 11 May 2016 14:33:14 +0200 Subject: [PATCH] Update to eddyb's PR --- src/librustc/traits/error_reporting.rs | 328 ++++++++++--------------- 1 file changed, 129 insertions(+), 199 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9f7e6b29e84a2..508261ddfdd6c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,7 +26,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{self, InferCtxt, TypeOrigin}; +use infer::{InferCtxt, TypeOrigin}; use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::fast_reject; use ty::fold::TypeFolder; @@ -37,7 +37,6 @@ use std::cmp; use std::fmt; use syntax::ast; use syntax::attr::{AttributeMethods, AttrMetaMethods}; -use syntax::ast; use syntax::codemap::Span; use syntax::errors::DiagnosticBuilder; @@ -62,26 +61,6 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { } } -fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>, - did: DefId, - obligation: PredicateObligation<'tcx>) - -> subst::Substs<'tcx> { - let tcx = fcx.tcx; - - let ity = tcx.lookup_item_type(did); - let (tps, rps, _) = - (ity.generics.types.get_slice(subst::TypeSpace), - ity.generics.regions.get_slice(subst::TypeSpace), - ity.ty); - - let rps = fcx.region_vars_for_defs(obligation.cause.span, rps); - let mut substs = subst::Substs::new( - subst::VecPerParamSpace::empty(), - subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new())); - fcx.type_vars_for_defs(obligation.cause.span, subst::ParamSpace::TypeSpace, &mut substs, tps); - substs -} - // Enum used to differentiate the "big" and "little" weights. enum Weight { Coarse, @@ -204,141 +183,6 @@ fn get_best_matching_type<'tcx>(imps: &[(DefId, subst::Substs<'tcx>)], } } -fn get_current_failing_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - trait_ref: &TraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>) - -> Option<(DefId, subst::Substs<'tcx>)> { - let simp = fast_reject::simplify_type(infcx.tcx, - trait_ref.self_ty(), - true); - let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id); - - match simp { - Some(_) => { - let mut matching_impls = Vec::new(); - trait_def.for_each_impl(infcx.tcx, |def_id| { - let imp = infcx.tcx.impl_trait_ref(def_id).unwrap(); - let substs = impl_substs(infcx, def_id, obligation.clone()); - let imp = imp.subst(infcx.tcx, &substs); - - if infer::mk_eqty(infcx, true, - TypeOrigin::Misc(obligation.cause.span), - trait_ref.self_ty(), - imp.self_ty()).is_ok() { - matching_impls.push((def_id, imp.substs.clone())); - } - }); - if matching_impls.len() == 0 { - None - } else if matching_impls.len() == 1 { - Some(matching_impls[0].clone()) - } else { - let end = trait_ref.input_types().len() - 1; - // we need to determine which type is the good one! - Some(matching_impls[get_best_matching_type(&matching_impls, - &trait_ref.input_types()[0..end])] - .clone()) - } - }, - None => None, - } -} - -fn find_attr<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - def_id: DefId, - attr_name: &str) - -> Option { - for item in infcx.tcx.get_attrs(def_id).iter() { - if item.check_name(attr_name) { - return Some(item.clone()); - } - } - None -} - -fn on_unimplemented_note<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>) -> Option { - let trait_ref = trait_ref.skip_binder(); - let mut report = None; - let def_id = match get_current_failing_impl(infcx, trait_ref, obligation) { - Some((def_id, _)) => { - if let Some(_) = find_attr(infcx, def_id, "rustc_on_unimplemented") { - def_id - } else { - trait_ref.def_id - } - }, - None => trait_ref.def_id, - }; - let span = obligation.cause.span; - let mut report = None; - - for item in infcx.tcx.get_attrs(def_id).iter() { - if item.check_name("rustc_on_unimplemented") { - let err_sp = item.meta().span.substitute_dummy(span); - let def = infcx.tcx.lookup_trait_def(trait_ref.def_id); - let trait_str = def.trait_ref.to_string(); - if let Some(ref istring) = item.value_str() { - let mut generic_map = def.generics.types.iter_enumerated() - .map(|(param, i, gen)| { - (gen.name.as_str().to_string(), - trait_ref.substs.types.get(param, i) - .to_string()) - }).collect::>(); - generic_map.insert("Self".to_string(), - trait_ref.self_ty().to_string()); - let parser = Parser::new(&istring); - let mut errored = false; - let err: String = parser.filter_map(|p| { - match p { - Piece::String(s) => Some(s), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(s) { - Some(val) => Some(val), - None => { - span_err!(infcx.tcx.sess, err_sp, E0272, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} refers to \ - non-existent type parameter {}", - trait_str, s); - errored = true; - None - } - }, - _ => { - span_err!(infcx.tcx.sess, err_sp, E0273, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} must have named \ - format arguments, \ - eg `#[rustc_on_unimplemented = \ - \"foo {{T}}\"]`", - trait_str); - errored = true; - None - } - } - } - }).collect(); - // Report only if the format string checks out - if !errored { - report = Some(err); - } - } else { - span_err!(infcx.tcx.sess, err_sp, E0274, - "the #[rustc_on_unimplemented] attribute on \ - trait definition for {} must have a value, \ - eg `#[rustc_on_unimplemented = \"foo\"]`", - trait_str); - } - break; - } - } - report -} - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_fulfillment_errors(&self, errors: &Vec>) { for error in errors { @@ -405,16 +249,101 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + fn impl_substs(&self, + did: DefId, + obligation: PredicateObligation<'tcx>) + -> subst::Substs<'tcx> { + let tcx = self.tcx; + + let ity = tcx.lookup_item_type(did); + let (tps, rps, _) = + (ity.generics.types.get_slice(subst::TypeSpace), + ity.generics.regions.get_slice(subst::TypeSpace), + ity.ty); + + let rps = self.region_vars_for_defs(obligation.cause.span, rps); + let mut substs = subst::Substs::new( + subst::VecPerParamSpace::empty(), + subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new())); + self.type_vars_for_defs(obligation.cause.span, + subst::ParamSpace::TypeSpace, + &mut substs, + tps); + substs + } + + fn get_current_failing_impl(&self, + trait_ref: &TraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>) + -> Option<(DefId, subst::Substs<'tcx>)> { + let simp = fast_reject::simplify_type(self.tcx, + trait_ref.self_ty(), + true); + let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); + + match simp { + Some(_) => { + let mut matching_impls = Vec::new(); + trait_def.for_each_impl(self.tcx, |def_id| { + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + let substs = self.impl_substs(def_id, obligation.clone()); + let imp = imp.subst(self.tcx, &substs); + + if self.eq_types(true, + TypeOrigin::Misc(obligation.cause.span), + trait_ref.self_ty(), + imp.self_ty()).is_ok() { + matching_impls.push((def_id, imp.substs.clone())); + } + }); + if matching_impls.len() == 0 { + None + } else if matching_impls.len() == 1 { + Some(matching_impls[0].clone()) + } else { + let end = trait_ref.input_types().len() - 1; + // we need to determine which type is the good one! + Some(matching_impls[get_best_matching_type(&matching_impls, + &trait_ref.input_types()[0..end])] + .clone()) + } + }, + None => None, + } + } + + 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 + } + fn on_unimplemented_note(&self, trait_ref: ty::PolyTraitRef<'tcx>, - span: Span) -> Option { + obligation: &PredicateObligation<'tcx>) -> Option { let trait_ref = trait_ref.skip_binder(); - let def_id = trait_ref.def_id; + let def_id = match self.get_current_failing_impl(trait_ref, obligation) { + Some((def_id, _)) => { + if let Some(_) = self.find_attr(def_id, "rustc_on_unimplemented") { + def_id + } else { + trait_ref.def_id + } + }, + None => trait_ref.def_id, + }; + let span = obligation.cause.span; let mut report = None; for item in self.tcx.get_attrs(def_id).iter() { if item.check_name("rustc_on_unimplemented") { let err_sp = item.meta().span.substitute_dummy(span); - let def = self.tcx.lookup_trait_def(def_id); + let def = self.tcx.lookup_trait_def(trait_ref.def_id); let trait_str = def.trait_ref.to_string(); if let Some(ref istring) = item.value_str() { let mut generic_map = def.generics.types.iter_enumerated() @@ -474,6 +403,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { report } + fn find_similar_impl_candidates(&self, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Vec> + { + let simp = fast_reject::simplify_type(self.tcx, + trait_ref.skip_binder().self_ty(), + true); + let mut impl_candidates = Vec::new(); + let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id()); + + match simp { + Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| { + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + let imp_simp = fast_reject::simplify_type(self.tcx, + imp.self_ty(), + true); + if let Some(imp_simp) = imp_simp { + if simp != imp_simp { + return; + } + } + impl_candidates.push(imp); + }), + None => trait_def.for_each_impl(self.tcx, |def_id| { + impl_candidates.push( + self.tcx.impl_trait_ref(def_id).unwrap()); + }) + }; + impl_candidates + } + fn report_similar_impl_candidates(&self, trait_ref: ty::PolyTraitRef<'tcx>, err: &mut DiagnosticBuilder) @@ -682,30 +642,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.resolve_type_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { - let trait_ref = trait_predicate.to_poly_trait_ref(); - let mut err = struct_span_err!( - infcx.tcx.sess, obligation.cause.span, E0277, - "the trait bound `{}` is not satisfied", - trait_ref.to_predicate()); - - // Try to report a help message - - if !trait_ref.has_infer_types() && - predicate_can_apply(infcx, trait_ref) { - // If a where-clause may be useful, remind the - // user that they can add it. - // - // don't display an on-unimplemented note, as - // these notes will often be of the form - // "the type `T` can't be frobnicated" - // which is somewhat confusing. - err.help(&format!("consider adding a `where {}` bound", - trait_ref.to_predicate())); - } else if let Some(s) = on_unimplemented_note(infcx, trait_ref, - obligation) { - // If it has a custom "#[rustc_on_unimplemented]" - // error message, let's display it! - err.note(&s); + return; } else { let trait_ref = trait_predicate.to_poly_trait_ref(); @@ -727,8 +664,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Try to report a help message if !trait_ref.has_infer_types() && - self.predicate_can_apply(trait_ref) - { + self.predicate_can_apply(trait_ref) { // If a where-clause may be useful, remind the // user that they can add it. // @@ -737,29 +673,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // "the type `T` can't be frobnicated" // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", - trait_ref.to_predicate() - )); - } else if let Some(s) = - self.on_unimplemented_note(trait_ref, span) { - // Otherwise, if there is an on-unimplemented note, - // display it. + trait_ref.to_predicate())); + } else if let Some(s) = self.on_unimplemented_note(trait_ref, + obligation) { + // If it has a custom "#[rustc_on_unimplemented]" + // error message, let's display it! err.note(&s); } else { // If we can't show anything useful, try to find // similar impls. - - self.report_similar_impl_candidates(trait_ref, &mut err); - // If we can't show anything useful, try to find - // similar impls. let impl_candidates = - find_similar_impl_candidates(infcx, trait_ref); + self.find_similar_impl_candidates(trait_ref); if impl_candidates.len() > 0 { self.report_similar_impl_candidates(trait_ref, &mut err); + } } err } - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); } ty::Predicate::Equate(ref predicate) => {