@@ -18,9 +18,12 @@ use super::{
1818 SelectionError ,
1919} ;
2020
21+ use fmt_macros:: { Parser , Piece , Position } ;
2122use middle:: infer:: InferCtxt ;
22- use middle:: ty:: { self , AsPredicate , ReferencesError , ToPolyTraitRef } ;
23+ use middle:: ty:: { self , AsPredicate , ReferencesError , ToPolyTraitRef , TraitRef } ;
24+ use std:: collections:: HashMap ;
2325use syntax:: codemap:: Span ;
26+ use syntax:: attr:: { AttributeMethods , AttrMetaMethods } ;
2427use util:: ppaux:: { Repr , UserString } ;
2528
2629pub fn report_fulfillment_errors < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
@@ -62,6 +65,69 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
6265 }
6366}
6467
68+ fn report_on_unimplemented < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
69+ trait_ref : & TraitRef < ' tcx > ) -> Option < String > {
70+ let def_id = trait_ref. def_id ;
71+ let mut report = None ;
72+ ty:: each_attr ( infcx. tcx , def_id, |item| {
73+ if item. check_name ( "on_unimplemented" ) {
74+ if let Some ( ref istring) = item. value_str ( ) {
75+ let def = ty:: lookup_trait_def ( infcx. tcx , def_id) ;
76+ let mut generic_map = def. generics . types . iter_enumerated ( )
77+ . map ( |( param, i, gen) | {
78+ ( gen. name . as_str ( ) . to_string ( ) ,
79+ trait_ref. substs . types . get ( param, i)
80+ . user_string ( infcx. tcx ) )
81+ } ) . collect :: < HashMap < String , String > > ( ) ;
82+ generic_map. insert ( "Self" . to_string ( ) ,
83+ trait_ref. self_ty ( ) . user_string ( infcx. tcx ) ) ;
84+ let parser = Parser :: new ( istring. get ( ) ) ;
85+ let mut errored = false ;
86+ let err: String = parser. filter_map ( |p| {
87+ match p {
88+ Piece :: String ( s) => Some ( s) ,
89+ Piece :: NextArgument ( a) => match a. position {
90+ Position :: ArgumentNamed ( s) => match generic_map. get ( s) {
91+ Some ( val) => Some ( val. as_slice ( ) ) ,
92+ None => {
93+ infcx. tcx . sess
94+ . span_err ( item. meta ( ) . span ,
95+ format ! ( "there is no type parameter \
96+ {} on trait {}",
97+ s, def. trait_ref
98+ . user_string( infcx. tcx) )
99+ . as_slice ( ) ) ;
100+ errored = true ;
101+ None
102+ }
103+ } ,
104+ _ => {
105+ infcx. tcx . sess . span_err ( item. meta ( ) . span ,
106+ "only named substitution \
107+ parameters are allowed") ;
108+ errored = true ;
109+ None
110+ }
111+ }
112+ }
113+ } ) . collect ( ) ;
114+ // Report only if the format string checks out
115+ if !errored {
116+ report = Some ( err) ;
117+ }
118+ } else {
119+ infcx. tcx . sess . span_err ( item. meta ( ) . span ,
120+ "this attribute must have a value, \
121+ eg `#[on_unimplemented = \" foo\" ]`")
122+ }
123+ false
124+ } else {
125+ true
126+ }
127+ } ) ;
128+ report
129+ }
130+
65131pub fn report_selection_error < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
66132 obligation : & PredicateObligation < ' tcx > ,
67133 error : & SelectionError < ' tcx > )
@@ -88,12 +154,20 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
88154 infcx. resolve_type_vars_if_possible ( trait_predicate) ;
89155 if !trait_predicate. references_error ( ) {
90156 let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
157+ // Check if it has a custom "#[on_unimplemented]" error message,
158+ // report with that message if it does
159+ let custom_note = report_on_unimplemented ( infcx, & * trait_ref. 0 ) ;
91160 infcx. tcx . sess . span_err (
92161 obligation. cause . span ,
93162 format ! (
94163 "the trait `{}` is not implemented for the type `{}`" ,
95164 trait_ref. user_string( infcx. tcx) ,
96165 trait_ref. self_ty( ) . user_string( infcx. tcx) ) . as_slice ( ) ) ;
166+ if let Some ( s) = custom_note {
167+ infcx. tcx . sess . span_note (
168+ obligation. cause . span ,
169+ s. as_slice ( ) ) ;
170+ }
97171 }
98172 }
99173
0 commit comments