@@ -26,14 +26,16 @@ use super::{
26
26
27
27
use fmt_macros:: { Parser , Piece , Position } ;
28
28
use hir:: def_id:: DefId ;
29
- use infer:: InferCtxt ;
30
- use ty:: { self , ToPredicate , ToPolyTraitRef , Ty , TyCtxt } ;
29
+ use infer:: { self , InferCtxt , TypeOrigin } ;
30
+ use ty:: { self , ToPredicate , ToPolyTraitRef , TraitRef , Ty , TyCtxt , TypeFoldable } ;
31
31
use ty:: fast_reject;
32
32
use ty:: fold:: { TypeFoldable , TypeFolder } ;
33
+ use ty:: :: subst:: { self , Subst } ;
33
34
use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
34
35
35
36
use std:: cmp;
36
37
use std:: fmt;
38
+ use syntax:: ast;
37
39
use syntax:: attr:: { AttributeMethods , AttrMetaMethods } ;
38
40
use syntax:: ast;
39
41
use syntax:: codemap:: Span ;
@@ -60,6 +62,154 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
60
62
}
61
63
}
62
64
65
+ fn impl_self_ty < ' a , ' tcx > ( fcx : & InferCtxt < ' a , ' tcx > ,
66
+ did : DefId ,
67
+ obligation : PredicateObligation < ' tcx > )
68
+ -> subst:: Substs < ' tcx > {
69
+ let tcx = fcx. tcx ;
70
+
71
+ let ity = tcx. lookup_item_type ( did) ;
72
+ let ( tps, rps, _) =
73
+ ( ity. generics . types . get_slice ( subst:: TypeSpace ) ,
74
+ ity. generics . regions . get_slice ( subst:: TypeSpace ) ,
75
+ ity. ty ) ;
76
+
77
+ let rps = fcx. region_vars_for_defs ( obligation. cause . span , rps) ;
78
+ let mut substs = subst:: Substs :: new (
79
+ subst:: VecPerParamSpace :: empty ( ) ,
80
+ subst:: VecPerParamSpace :: new ( rps, Vec :: new ( ) , Vec :: new ( ) ) ) ;
81
+ fcx. type_vars_for_defs ( obligation. cause . span , subst:: ParamSpace :: TypeSpace , & mut substs, tps) ;
82
+ substs
83
+ }
84
+
85
+ fn get_current_failing_impl < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
86
+ trait_ref : & TraitRef < ' tcx > ,
87
+ obligation : & PredicateObligation < ' tcx > )
88
+ -> Option < DefId > {
89
+ let simp = fast_reject:: simplify_type ( infcx. tcx ,
90
+ trait_ref. self_ty ( ) ,
91
+ true ) ;
92
+ let trait_def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ) ;
93
+
94
+ match simp {
95
+ Some ( _) => {
96
+ let mut ret = None ;
97
+ trait_def. for_each_impl ( infcx. tcx , |def_id| {
98
+ let imp = infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
99
+ let imp = imp. subst ( infcx. tcx , & impl_self_ty ( infcx, def_id, obligation. clone ( ) ) ) ;
100
+ if ret. is_none ( ) {
101
+ for error in infcx. reported_trait_errors . borrow ( ) . iter ( ) {
102
+ if let ty:: Predicate :: Trait ( ref t) = error. predicate {
103
+ if infer:: mk_eqty ( infcx, true , TypeOrigin :: Misc ( obligation. cause . span ) ,
104
+ t. skip_binder ( ) . trait_ref . self_ty ( ) ,
105
+ imp. self_ty ( ) ) . is_ok ( ) {
106
+ ret = Some ( def_id) ;
107
+ break ;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ } ) ;
113
+ ret
114
+ } ,
115
+ None => None ,
116
+ }
117
+ }
118
+
119
+ fn find_attr < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
120
+ def_id : DefId ,
121
+ attr_name : & str )
122
+ -> Option < ast:: Attribute > {
123
+ for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
124
+ if item. check_name ( attr_name) {
125
+ return Some ( item. clone ( ) ) ;
126
+ }
127
+ }
128
+ None
129
+ }
130
+
131
+ fn report_on_unimplemented < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
132
+ trait_ref : & TraitRef < ' tcx > ,
133
+ obligation : & PredicateObligation < ' tcx > )
134
+ -> Option < String > {
135
+ let def_id = match get_current_failing_impl ( infcx, trait_ref, obligation) {
136
+ Some ( def_id) => {
137
+ if let Some ( _) = find_attr ( infcx, def_id, "rustc_on_unimplemented" ) {
138
+ def_id
139
+ } else {
140
+ trait_ref. def_id
141
+ }
142
+ } ,
143
+ None => trait_ref. def_id ,
144
+ } ;
145
+ let span = obligation. cause . span ;
146
+ let mut report = None ;
147
+
148
+ for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
149
+ if item. check_name ( "rustc_on_unimplemented" ) {
150
+ let err_sp = item. meta ( ) . span . substitute_dummy ( span) ;
151
+ let def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ) ;
152
+ let trait_str = def. trait_ref . to_string ( ) ;
153
+ if let Some ( ref istring) = item. value_str ( ) {
154
+ let mut generic_map = def. generics . types . iter_enumerated ( )
155
+ . map ( |( param, i, gen) | {
156
+ ( gen. name . as_str ( ) . to_string ( ) ,
157
+ trait_ref. substs . types . get ( param, i)
158
+ . to_string ( ) )
159
+ } ) . collect :: < FnvHashMap < String , String > > ( ) ;
160
+ generic_map. insert ( "Self" . to_string ( ) ,
161
+ trait_ref. self_ty ( ) . to_string ( ) ) ;
162
+ let parser = Parser :: new ( & istring) ;
163
+ let mut errored = false ;
164
+ let err: String = parser. filter_map ( |p| {
165
+ match p {
166
+ Piece :: String ( s) => Some ( s) ,
167
+ Piece :: NextArgument ( a) => match a. position {
168
+ Position :: ArgumentNamed ( s) => match generic_map. get ( s) {
169
+ Some ( val) => Some ( val) ,
170
+ None => {
171
+ span_err ! ( infcx. tcx. sess, err_sp, E0272 ,
172
+ "the #[rustc_on_unimplemented] \
173
+ attribute on \
174
+ trait definition for {} refers to \
175
+ non-existent type parameter {}",
176
+ trait_str, s) ;
177
+ errored = true ;
178
+ None
179
+ }
180
+ } ,
181
+ _ => {
182
+ span_err ! ( infcx. tcx. sess, err_sp, E0273 ,
183
+ "the #[rustc_on_unimplemented] \
184
+ attribute on \
185
+ trait definition for {} must have named \
186
+ format arguments, \
187
+ eg `#[rustc_on_unimplemented = \
188
+ \" foo {{T}}\" ]`",
189
+ trait_str) ;
190
+ errored = true ;
191
+ None
192
+ }
193
+ }
194
+ }
195
+ } ) . collect ( ) ;
196
+ // Report only if the format string checks out
197
+ if !errored {
198
+ report = Some ( err) ;
199
+ }
200
+ } else {
201
+ span_err ! ( infcx. tcx. sess, err_sp, E0274 ,
202
+ "the #[rustc_on_unimplemented] attribute on \
203
+ trait definition for {} must have a value, \
204
+ eg `#[rustc_on_unimplemented = \" foo\" ]`",
205
+ trait_str) ;
206
+ }
207
+ break ;
208
+ }
209
+ }
210
+ report
211
+ }
212
+
63
213
impl < ' a , ' gcx , ' tcx > InferCtxt < ' a , ' gcx , ' tcx > {
64
214
pub fn report_fulfillment_errors ( & self , errors : & Vec < FulfillmentError < ' tcx > > ) {
65
215
for error in errors {
@@ -403,7 +553,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
403
553
self . resolve_type_vars_if_possible ( trait_predicate) ;
404
554
405
555
if self . tcx . sess . has_errors ( ) && trait_predicate. references_error ( ) {
406
- return ;
556
+ let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
557
+ let mut err = struct_span_err ! (
558
+ infcx. tcx. sess, obligation. cause. span, E0277 ,
559
+ "the trait bound `{}` is not satisfied" ,
560
+ trait_ref. to_predicate( ) ) ;
561
+
562
+ // Try to report a help message
563
+
564
+ if !trait_ref. has_infer_types ( ) &&
565
+ predicate_can_apply ( infcx, trait_ref)
566
+ {
567
+ // If a where-clause may be useful, remind the
568
+ // user that they can add it.
569
+ //
570
+ // don't display an on-unimplemented note, as
571
+ // these notes will often be of the form
572
+ // "the type `T` can't be frobnicated"
573
+ // which is somewhat confusing.
574
+ err. help ( & format ! ( "consider adding a `where {}` bound" ,
575
+ trait_ref. to_predicate( ) ) ) ;
576
+ } else if let Some ( s) = on_unimplemented_note ( infcx, trait_ref,
577
+ obligation. cause . span ) {
578
+ // Otherwise, if there is an on-unimplemented note,
579
+ // display it.
580
+ err. note ( & s) ;
407
581
} else {
408
582
let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
409
583
@@ -450,7 +624,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
450
624
}
451
625
err
452
626
}
453
- } ,
627
+ }
628
+
454
629
ty:: Predicate :: Equate ( ref predicate) => {
455
630
let predicate = self . resolve_type_vars_if_possible ( predicate) ;
456
631
let err = self . equality_predicate ( span,
0 commit comments