diff options
| author | bors <bors@rust-lang.org> | 2015-01-12 04:45:18 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-01-12 04:45:18 +0000 |
| commit | 0aec4db1c09574da2f30e3844de6d252d79d4939 (patch) | |
| tree | 64ef8983eb848612559f373ab7069e033672745f /src/librustc | |
| parent | 15a41380c14e94052332360b104ec1651f97297b (diff) | |
| parent | 02d0a8bbcf0a64339e4279c4ddb4841189ba5069 (diff) | |
auto merge of #20889 : Manishearth/rust/trait-error, r=nikomatsakis
fixes #20783 r? @nikomatsakis
Diffstat (limited to 'src/librustc')
| -rw-r--r-- | src/librustc/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc/lint/builtin.rs | 1 | ||||
| -rw-r--r-- | src/librustc/middle/traits/error_reporting.rs | 94 |
3 files changed, 94 insertions, 2 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fb7c5296d02..e720a5df598 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -32,6 +32,7 @@ extern crate arena; extern crate flate; +extern crate fmt_macros; extern crate getopts; extern crate graphviz; extern crate libc; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 620b8f277dd..8ed177c82a8 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -666,6 +666,7 @@ impl LintPass for UnusedAttributes { "must_use", "stable", "unstable", + "rustc_on_unimplemented", // FIXME: #19470 this shouldn't be needed forever "old_orphan_check", diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 02c913a9e81..6b4dd101286 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -18,9 +18,12 @@ use super::{ SelectionError, }; +use fmt_macros::{Parser, Piece, Position}; use middle::infer::InferCtxt; -use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef}; -use syntax::codemap::Span; +use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef}; +use std::collections::HashMap; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; use util::ppaux::{Repr, UserString}; pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, @@ -62,6 +65,85 @@ 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>, + 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("rustc_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 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) + .user_string(infcx.tcx)) + }).collect::<HashMap<String, String>>(); + generic_map.insert("Self".to_string(), + trait_ref.self_ty().user_string(infcx.tcx)); + let parser = Parser::new(istring.get()); + 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.as_slice()), + None => { + infcx.tcx.sess + .span_err(err_sp, + format!("the #[rustc_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(err_sp, + format!("the #[rustc_on_unimplemented] \ + attribute on \ + trait definition for {} must have named \ + format arguments, \ + eg `#[rustc_on_unimplemented = \ + \"foo {{T}}\"]`", + trait_str).as_slice()); + errored = true; + None + } + } + } + }).collect(); + // Report only if the format string checks out + if !errored { + report = Some(err); + } + } else { + infcx.tcx.sess.span_err(err_sp, + format!("the #[rustc_on_unimplemented] attribute on \ + trait definition for {} must have a value, \ + eg `#[rustc_on_unimplemented = \"foo\"]`", + trait_str).as_slice()); + } + false + } else { + true + } + }); + report +} + pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) @@ -94,6 +176,14 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, "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 "#[rustc_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, + s.as_slice()); + } } } |
