@@ -25,13 +25,15 @@ use super::{
25
25
26
26
use fmt_macros:: { Parser , Piece , Position } ;
27
27
use middle:: def_id:: DefId ;
28
- use middle:: infer:: InferCtxt ;
28
+ use middle:: infer:: { self , InferCtxt , TypeOrigin } ;
29
29
use middle:: ty:: { self , ToPredicate , ToPolyTraitRef , TraitRef , Ty , TyCtxt , TypeFoldable } ;
30
30
use middle:: ty:: fast_reject;
31
+ use middle:: subst:: { self , Subst } ;
31
32
use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
32
33
33
34
use std:: cmp;
34
35
use std:: fmt;
36
+ use syntax:: ast;
35
37
use syntax:: attr:: { AttributeMethods , AttrMetaMethods } ;
36
38
use syntax:: codemap:: Span ;
37
39
use syntax:: errors:: DiagnosticBuilder ;
@@ -105,15 +107,93 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
105
107
}
106
108
}
107
109
110
+ fn impl_self_ty < ' a , ' tcx > ( fcx : & InferCtxt < ' a , ' tcx > ,
111
+ did : DefId ,
112
+ obligation : PredicateObligation < ' tcx > )
113
+ -> subst:: Substs < ' tcx > {
114
+ let tcx = fcx. tcx ;
115
+
116
+ let ity = tcx. lookup_item_type ( did) ;
117
+ let ( tps, rps, _) =
118
+ ( ity. generics . types . get_slice ( subst:: TypeSpace ) ,
119
+ ity. generics . regions . get_slice ( subst:: TypeSpace ) ,
120
+ ity. ty ) ;
121
+
122
+ let rps = fcx. region_vars_for_defs ( obligation. cause . span , rps) ;
123
+ let mut substs = subst:: Substs :: new (
124
+ subst:: VecPerParamSpace :: empty ( ) ,
125
+ subst:: VecPerParamSpace :: new ( rps, Vec :: new ( ) , Vec :: new ( ) ) ) ;
126
+ fcx. type_vars_for_defs ( obligation. cause . span , subst:: ParamSpace :: TypeSpace , & mut substs, tps) ;
127
+ substs
128
+ }
129
+
130
+ fn get_current_failing_impl < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
131
+ trait_ref : & TraitRef < ' tcx > ,
132
+ obligation : & PredicateObligation < ' tcx > )
133
+ -> Option < DefId > {
134
+ let simp = fast_reject:: simplify_type ( infcx. tcx ,
135
+ trait_ref. self_ty ( ) ,
136
+ true ) ;
137
+ let trait_def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ) ;
138
+
139
+ match simp {
140
+ Some ( _) => {
141
+ let mut ret = None ;
142
+ trait_def. for_each_impl ( infcx. tcx , |def_id| {
143
+ let imp = infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
144
+ let imp = imp. subst ( infcx. tcx , & impl_self_ty ( infcx, def_id, obligation. clone ( ) ) ) ;
145
+ if ret. is_none ( ) {
146
+ for error in infcx. reported_trait_errors . borrow ( ) . iter ( ) {
147
+ if let ty:: Predicate :: Trait ( ref t) = error. predicate {
148
+ if infer:: mk_eqty ( infcx, true , TypeOrigin :: Misc ( obligation. cause . span ) ,
149
+ t. skip_binder ( ) . trait_ref . self_ty ( ) ,
150
+ imp. self_ty ( ) ) . is_ok ( ) {
151
+ ret = Some ( def_id) ;
152
+ break ;
153
+ }
154
+ }
155
+ }
156
+ }
157
+ } ) ;
158
+ ret
159
+ } ,
160
+ None => None ,
161
+ }
162
+ }
163
+
164
+ fn find_attr < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
165
+ def_id : DefId ,
166
+ attr_name : & str )
167
+ -> Option < ast:: Attribute > {
168
+ for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
169
+ if item. check_name ( attr_name) {
170
+ return Some ( item. clone ( ) ) ;
171
+ }
172
+ }
173
+ None
174
+ }
175
+
108
176
fn report_on_unimplemented < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
109
177
trait_ref : & TraitRef < ' tcx > ,
110
- span : Span ) -> Option < String > {
111
- let def_id = trait_ref. def_id ;
178
+ obligation : & PredicateObligation < ' tcx > )
179
+ -> Option < String > {
180
+ let def_id = match get_current_failing_impl ( infcx, trait_ref, obligation) {
181
+ Some ( def_id) => {
182
+ if let Some ( _) = find_attr ( infcx, def_id, "rustc_on_unimplemented" ) {
183
+ def_id
184
+ } else {
185
+ trait_ref. def_id
186
+ }
187
+ } ,
188
+ None => trait_ref. def_id ,
189
+ } ;
190
+ let span = obligation. cause . span ;
112
191
let mut report = None ;
192
+
113
193
for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
114
194
if item. check_name ( "rustc_on_unimplemented" ) {
115
195
let err_sp = item. meta ( ) . span . substitute_dummy ( span) ;
116
- let def = infcx. tcx . lookup_trait_def ( def_id) ;
196
+ let def = infcx. tcx . lookup_trait_def ( trait_ref . def_id ) ;
117
197
let trait_str = def. trait_ref . to_string ( ) ;
118
198
if let Some ( ref istring) = item. value_str ( ) {
119
199
let mut generic_map = def. generics . types . iter_enumerated ( )
@@ -134,24 +214,24 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
134
214
Some ( val) => Some ( val) ,
135
215
None => {
136
216
span_err ! ( infcx. tcx. sess, err_sp, E0272 ,
137
- "the #[rustc_on_unimplemented] \
138
- attribute on \
139
- trait definition for {} refers to \
140
- non-existent type parameter {}",
141
- trait_str, s) ;
217
+ "the #[rustc_on_unimplemented] \
218
+ attribute on \
219
+ trait definition for {} refers to \
220
+ non-existent type parameter {}",
221
+ trait_str, s) ;
142
222
errored = true ;
143
223
None
144
224
}
145
225
} ,
146
226
_ => {
147
- span_err ! ( infcx. tcx. sess, err_sp, E0273 ,
148
- "the #[rustc_on_unimplemented] \
149
- attribute on \
150
- trait definition for {} must have named \
151
- format arguments, \
152
- eg `#[rustc_on_unimplemented = \
153
- \" foo {{T}}\" ]`",
154
- trait_str) ;
227
+ span_err ! ( infcx. tcx. sess, err_sp, E0273 ,
228
+ "the #[rustc_on_unimplemented] \
229
+ attribute on \
230
+ trait definition for {} must have named \
231
+ format arguments, \
232
+ eg `#[rustc_on_unimplemented = \
233
+ \" foo {{T}}\" ]`",
234
+ trait_str) ;
155
235
errored = true ;
156
236
None
157
237
}
@@ -164,10 +244,10 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
164
244
}
165
245
} else {
166
246
span_err ! ( infcx. tcx. sess, err_sp, E0274 ,
167
- "the #[rustc_on_unimplemented] attribute on \
168
- trait definition for {} must have a value, \
169
- eg `#[rustc_on_unimplemented = \" foo\" ]`",
170
- trait_str) ;
247
+ "the #[rustc_on_unimplemented] attribute on \
248
+ trait definition for {} must have a value, \
249
+ eg `#[rustc_on_unimplemented = \" foo\" ]`",
250
+ trait_str) ;
171
251
}
172
252
break ;
173
253
}
@@ -368,7 +448,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
368
448
// Check if it has a custom "#[rustc_on_unimplemented]"
369
449
// error message, report with that message if it does
370
450
let custom_note = report_on_unimplemented ( infcx, & trait_ref. 0 ,
371
- obligation. cause . span ) ;
451
+ obligation) ;
372
452
if let Some ( s) = custom_note {
373
453
err. fileline_note ( obligation. cause . span , & s) ;
374
454
} else {
0 commit comments