@@ -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 syntax:: codemap:: Span ;
23+ use middle:: ty:: { self , AsPredicate , ReferencesError , ToPolyTraitRef , TraitRef } ;
24+ use std:: collections:: HashMap ;
25+ use syntax:: codemap:: { DUMMY_SP , 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,85 @@ 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 > ,
70+ span : Span ) -> Option < String > {
71+ let def_id = trait_ref. def_id ;
72+ let mut report = None ;
73+ ty:: each_attr ( infcx. tcx , def_id, |item| {
74+ if item. check_name ( "rustc_on_unimplemented" ) {
75+ let err_sp = if item. meta ( ) . span == DUMMY_SP {
76+ span
77+ } else {
78+ item. meta ( ) . span
79+ } ;
80+ let def = ty:: lookup_trait_def ( infcx. tcx , def_id) ;
81+ let trait_str = def. trait_ref . user_string ( infcx. tcx ) ;
82+ if let Some ( ref istring) = item. value_str ( ) {
83+ let mut generic_map = def. generics . types . iter_enumerated ( )
84+ . map ( |( param, i, gen) | {
85+ ( gen. name . as_str ( ) . to_string ( ) ,
86+ trait_ref. substs . types . get ( param, i)
87+ . user_string ( infcx. tcx ) )
88+ } ) . collect :: < HashMap < String , String > > ( ) ;
89+ generic_map. insert ( "Self" . to_string ( ) ,
90+ trait_ref. self_ty ( ) . user_string ( infcx. tcx ) ) ;
91+ let parser = Parser :: new ( istring. get ( ) ) ;
92+ let mut errored = false ;
93+ let err: String = parser. filter_map ( |p| {
94+ match p {
95+ Piece :: String ( s) => Some ( s) ,
96+ Piece :: NextArgument ( a) => match a. position {
97+ Position :: ArgumentNamed ( s) => match generic_map. get ( s) {
98+ Some ( val) => Some ( val. as_slice ( ) ) ,
99+ None => {
100+ infcx. tcx . sess
101+ . span_err ( err_sp,
102+ format ! ( "the #[rustc_on_unimplemented] \
103+ attribute on \
104+ trait definition for {} refers to \
105+ non-existent type parameter {}",
106+ trait_str, s)
107+ . as_slice ( ) ) ;
108+ errored = true ;
109+ None
110+ }
111+ } ,
112+ _ => {
113+ infcx. tcx . sess
114+ . span_err ( err_sp,
115+ format ! ( "the #[rustc_on_unimplemented] \
116+ attribute on \
117+ trait definition for {} must have named \
118+ format arguments, \
119+ eg `#[rustc_on_unimplemented = \
120+ \" foo {{T}}\" ]`",
121+ trait_str) . as_slice ( ) ) ;
122+ errored = true ;
123+ None
124+ }
125+ }
126+ }
127+ } ) . collect ( ) ;
128+ // Report only if the format string checks out
129+ if !errored {
130+ report = Some ( err) ;
131+ }
132+ } else {
133+ infcx. tcx . sess . span_err ( err_sp,
134+ format ! ( "the #[rustc_on_unimplemented] attribute on \
135+ trait definition for {} must have a value, \
136+ eg `#[rustc_on_unimplemented = \" foo\" ]`",
137+ trait_str) . as_slice ( ) ) ;
138+ }
139+ false
140+ } else {
141+ true
142+ }
143+ } ) ;
144+ report
145+ }
146+
65147pub fn report_selection_error < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
66148 obligation : & PredicateObligation < ' tcx > ,
67149 error : & SelectionError < ' tcx > )
@@ -94,6 +176,14 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
94176 "the trait `{}` is not implemented for the type `{}`" ,
95177 trait_ref. user_string( infcx. tcx) ,
96178 trait_ref. self_ty( ) . user_string( infcx. tcx) ) . as_slice ( ) ) ;
179+ // Check if it has a custom "#[rustc_on_unimplemented]" error message,
180+ // report with that message if it does
181+ let custom_note = report_on_unimplemented ( infcx, & * trait_ref. 0 ,
182+ obligation. cause . span ) ;
183+ if let Some ( s) = custom_note {
184+ infcx. tcx . sess . span_note ( obligation. cause . span ,
185+ s. as_slice ( ) ) ;
186+ }
97187 }
98188 }
99189
0 commit comments