@@ -26,14 +26,16 @@ use super::{
2626
2727use fmt_macros:: { Parser , Piece , Position } ;
2828use 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 } ;
3131use ty:: fast_reject;
3232use ty:: fold:: { TypeFoldable , TypeFolder } ;
33+ use ty:: :: subst:: { self , Subst } ;
3334use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
3435
3536use std:: cmp;
3637use std:: fmt;
38+ use syntax:: ast;
3739use syntax:: attr:: { AttributeMethods , AttrMetaMethods } ;
3840use syntax:: ast;
3941use syntax:: codemap:: Span ;
@@ -60,6 +62,154 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
6062 }
6163}
6264
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+
63213impl < ' a , ' gcx , ' tcx > InferCtxt < ' a , ' gcx , ' tcx > {
64214 pub fn report_fulfillment_errors ( & self , errors : & Vec < FulfillmentError < ' tcx > > ) {
65215 for error in errors {
@@ -403,7 +553,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
403553 self . resolve_type_vars_if_possible ( trait_predicate) ;
404554
405555 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) ;
407581 } else {
408582 let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
409583
@@ -450,7 +624,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
450624 }
451625 err
452626 }
453- } ,
627+ }
628+
454629 ty:: Predicate :: Equate ( ref predicate) => {
455630 let predicate = self . resolve_type_vars_if_possible ( predicate) ;
456631 let err = self . equality_predicate ( span,
0 commit comments