]> git.lizzy.rs Git - rust.git/commitdiff
Make errors allow for cross-crate issues
authorManish Goregaokar <manishsmail@gmail.com>
Sun, 11 Jan 2015 11:11:02 +0000 (16:41 +0530)
committerManish Goregaokar <manishsmail@gmail.com>
Sun, 11 Jan 2015 11:11:02 +0000 (16:41 +0530)
src/librustc/middle/traits/error_reporting.rs
src/test/compile-fail/on-unimplemented.rs

index 8903667505b328f77cb9122289b541a54f873a57..0b0079c062db35bff5261f272ea80602a0fd14fa 100644 (file)
@@ -22,7 +22,7 @@
 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};
 
@@ -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(),
@@ -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
                             }
@@ -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 {
@@ -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,
index 5a56e91cdda80b2cc0dc0bf44f7c1821aa219460..3f899288f50d2d639460d3bfc0a4adf5168fc922 100644 (file)
@@ -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)  {}