@@ -18,9 +18,12 @@ use super::{
18
18
SelectionError ,
19
19
} ;
20
20
21
+ use fmt_macros:: { Parser , Piece , Position } ;
21
22
use 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 } ;
24
27
use util:: ppaux:: { Repr , UserString } ;
25
28
26
29
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>,
62
65
}
63
66
}
64
67
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
+
65
147
pub fn report_selection_error < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
66
148
obligation : & PredicateObligation < ' tcx > ,
67
149
error : & SelectionError < ' tcx > )
@@ -94,6 +176,14 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
94
176
"the trait `{}` is not implemented for the type `{}`" ,
95
177
trait_ref. user_string( infcx. tcx) ,
96
178
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
+ }
97
187
}
98
188
}
99
189
0 commit comments