@@ -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 middle:: ty:: { self , AsPredicate , ReferencesError , ToPolyTraitRef , TraitRef } ;
24
+ use std:: collections:: HashMap ;
23
25
use syntax:: codemap:: 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,69 @@ 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 > ) -> 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
+
65
131
pub fn report_selection_error < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
66
132
obligation : & PredicateObligation < ' tcx > ,
67
133
error : & SelectionError < ' tcx > )
@@ -88,12 +154,20 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
88
154
infcx. resolve_type_vars_if_possible ( trait_predicate) ;
89
155
if !trait_predicate. references_error ( ) {
90
156
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 ) ;
91
160
infcx. tcx . sess . span_err (
92
161
obligation. cause . span ,
93
162
format ! (
94
163
"the trait `{}` is not implemented for the type `{}`" ,
95
164
trait_ref. user_string( infcx. tcx) ,
96
165
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
+ }
97
171
}
98
172
}
99
173
0 commit comments