Skip to content

Commit

Permalink
Make errors allow for cross-crate issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Jan 11, 2015
1 parent dc0de42 commit e183277
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 19 deletions.
48 changes: 31 additions & 17 deletions src/librustc/middle/traits/error_reporting.rs
Expand Up @@ -22,7 +22,7 @@ use fmt_macros::{Parser, Piece, Position};
use middle::infer::InferCtxt;
use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
use std::collections::HashMap;
use syntax::codemap::Span;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::attr::{AttributeMethods, AttrMetaMethods};
use util::ppaux::{Repr, UserString};

Expand Down Expand Up @@ -66,13 +66,20 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}

fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
trait_ref: &TraitRef<'tcx>) -> Option<String> {
trait_ref: &TraitRef<'tcx>,
span: Span) -> Option<String> {
let def_id = trait_ref.def_id;
let mut report = None;
ty::each_attr(infcx.tcx, def_id, |item| {
if item.check_name("on_unimplemented") {
let err_sp = if item.meta().span == DUMMY_SP {
span
} else {
item.meta().span
};
let def = ty::lookup_trait_def(infcx.tcx, def_id);
let trait_str = def.trait_ref.user_string(infcx.tcx);
if let Some(ref istring) = item.value_str() {
let def = ty::lookup_trait_def(infcx.tcx, def_id);
let mut generic_map = def.generics.types.iter_enumerated()
.map(|(param, i, gen)| {
(gen.name.as_str().to_string(),
Expand All @@ -91,20 +98,24 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
Some(val) => Some(val.as_slice()),
None => {
infcx.tcx.sess
.span_err(item.meta().span,
format!("there is no type parameter \
{} on trait {}",
s, def.trait_ref
.user_string(infcx.tcx))
.span_err(err_sp,
format!("the #[on_unimplemented] attribute on \
trait definition for {} refers to \
non-existent type parameter {}",
trait_str, s)
.as_slice());
errored = true;
None
}
},
_ => {
infcx.tcx.sess.span_err(item.meta().span,
"only named substitution \
parameters are allowed");
infcx.tcx.sess
.span_err(err_sp,
format!("the #[on_unimplemented] attribute on \
trait definition for {} must have named \
format arguments, \
eg `#[on_unimplemented = \"foo {{T}}\"]`",
trait_str).as_slice());
errored = true;
None
}
Expand All @@ -116,9 +127,11 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
report = Some(err);
}
} else {
infcx.tcx.sess.span_err(item.meta().span,
"this attribute must have a value, \
eg `#[on_unimplemented = \"foo\"]`")
infcx.tcx.sess.span_err(err_sp,
format!("the #[on_unimplemented] attribute on \
trait definition for {} must have a value, \
eg `#[on_unimplemented = \"foo\"]`",
trait_str).as_slice());
}
false
} else {
Expand Down Expand Up @@ -154,15 +167,16 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
infcx.resolve_type_vars_if_possible(trait_predicate);
if !trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref();
// Check if it has a custom "#[on_unimplemented]" error message,
// report with that message if it does
let custom_note = report_on_unimplemented(infcx, &*trait_ref.0);
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the trait `{}` is not implemented for the type `{}`",
trait_ref.user_string(infcx.tcx),
trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
// Check if it has a custom "#[on_unimplemented]" error message,
// report with that message if it does
let custom_note = report_on_unimplemented(infcx, &*trait_ref.0,
obligation.cause.span);
if let Some(s) = custom_note {
infcx.tcx.sess.span_note(
obligation.cause.span,
Expand Down
4 changes: 2 additions & 2 deletions src/test/compile-fail/on-unimplemented.rs
Expand Up @@ -26,11 +26,11 @@ fn collect<A, I: Iterator<Item=A>, B: MyFromIterator<A>>(it: I) -> B {
MyFromIterator::my_from_iter(it)
}

#[on_unimplemented] //~ ERROR this attribute must have a value
#[on_unimplemented] //~ ERROR the #[on_unimplemented] attribute on trait definition for BadAnnotation1 must have a value, eg `#[on_unimplemented = "foo"]`
trait BadAnnotation1 {}

#[on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
//~^ ERROR there is no type parameter C on trait BadAnnotation2<A, B>
//~^ ERROR the #[on_unimplemented] attribute on trait definition for BadAnnotation2<A, B> refers to non-existent type parameter C
trait BadAnnotation2<A,B> {}

fn trigger1<T: BadAnnotation1>(t: T) {}
Expand Down

0 comments on commit e183277

Please sign in to comment.