SelectionError,
};
+use fmt_macros::{Parser, Piece, Position};
use middle::infer::InferCtxt;
-use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef};
+use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
+use std::collections::HashMap;
use syntax::codemap::Span;
+use syntax::attr::{AttributeMethods, AttrMetaMethods};
use util::ppaux::{Repr, UserString};
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}
+fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+ trait_ref: &TraitRef<'tcx>) -> 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") {
+ 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(),
+ 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(item.meta().span,
+ format!("there is no type parameter \
+ {} on trait {}",
+ s, def.trait_ref
+ .user_string(infcx.tcx))
+ .as_slice());
+ errored = true;
+ None
+ }
+ },
+ _ => {
+ infcx.tcx.sess.span_err(item.meta().span,
+ "only named substitution \
+ parameters are allowed");
+ errored = true;
+ None
+ }
+ }
+ }
+ }).collect();
+ // Report only if the format string checks out
+ if !errored {
+ report = Some(err);
+ }
+ } else {
+ infcx.tcx.sess.span_err(item.meta().span,
+ "this attribute must have a value, \
+ eg `#[on_unimplemented = \"foo\"]`")
+ }
+ false
+ } else {
+ true
+ }
+ });
+ report
+}
+
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'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());
+ if let Some(s) = custom_note {
+ infcx.tcx.sess.span_note(
+ obligation.cause.span,
+ s.as_slice());
+ }
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+// ignore-tidy-linelength
+
+#[on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"]
+trait Foo<Bar, Baz, Quux>{}
+
+fn foobar<U: Clone, T: Foo<u8, U, u32>>() -> T {
+
+}
+
+#[on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"]
+trait MyFromIterator<A> {
+ /// Build a container with elements from an external iterator.
+ fn my_from_iter<T: Iterator<Item=A>>(iterator: T) -> Self;
+}
+
+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
+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>
+trait BadAnnotation2<A,B> {}
+
+fn trigger1<T: BadAnnotation1>(t: T) {}
+fn trigger2<A, B, T: BadAnnotation2<A,B>>(t: T) {}
+
+pub fn main() {
+ let x = vec!(1u8, 2, 3, 4);
+ let y: Option<Vec<u8>> = collect(x.iter()); // this should give approximately the same error for x.iter().collect()
+ //~^ ERROR
+ //~^^ NOTE a collection of type `core::option::Option<collections::vec::Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
+ let x: String = foobar(); //~ ERROR
+ //~^ NOTE test error `collections::string::String` with `u8` `_` `u32`
+
+ // The following two have errors in their annotations, so the regular error should be thrown
+ trigger1(1u8); //~ ERROR the trait `BadAnnotation1` is not implemented for the type `u8`
+ trigger2::<u8, u8, u8>(1u8); //~ ERROR the trait `BadAnnotation2<u8, u8>` is not implemented
+
+}