@@ -13,10 +13,12 @@ use super::{
1313 FulfillmentErrorCode ,
1414 MismatchedProjectionTypes ,
1515 Obligation ,
16+ ObligationCause ,
1617 ObligationCauseCode ,
1718 OutputTypeParameterMismatch ,
1819 TraitNotObjectSafe ,
1920 PredicateObligation ,
21+ SelectionContext ,
2022 SelectionError ,
2123 ObjectSafetyViolation ,
2224 MethodViolationCode ,
@@ -26,8 +28,9 @@ use super::{
2628use fmt_macros:: { Parser , Piece , Position } ;
2729use middle:: def_id:: DefId ;
2830use infer:: InferCtxt ;
29- use ty:: { self , ToPredicate , ToPolyTraitRef , TraitRef , Ty , TyCtxt , TypeFoldable } ;
31+ use ty:: { self , ToPredicate , ToPolyTraitRef , Ty , TyCtxt } ;
3032use ty:: fast_reject;
33+ use ty:: fold:: { TypeFoldable , TypeFolder } ;
3134use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
3235
3336use std:: cmp;
@@ -100,9 +103,10 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
100103 }
101104}
102105
103- fn report_on_unimplemented < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
104- trait_ref : & TraitRef < ' tcx > ,
105- span : Span ) -> Option < String > {
106+ fn on_unimplemented_note < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
107+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
108+ span : Span ) -> Option < String > {
109+ let trait_ref = trait_ref. skip_binder ( ) ;
106110 let def_id = trait_ref. def_id ;
107111 let mut report = None ;
108112 for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
@@ -357,14 +361,20 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
357361 let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
358362 let mut err = struct_span_err ! (
359363 infcx. tcx. sess, obligation. cause. span, E0277 ,
360- "the trait `{}` is not implemented for the type `{}`" ,
361- trait_ref, trait_ref. self_ty( ) ) ;
362-
363- // Check if it has a custom "#[rustc_on_unimplemented]"
364- // error message, report with that message if it does
365- let custom_note = report_on_unimplemented ( infcx, & trait_ref. 0 ,
366- obligation. cause . span ) ;
367- if let Some ( s) = custom_note {
364+ "the predicate `{}` is not satisfied" ,
365+ trait_ref. to_predicate( ) ) ;
366+
367+ // Try to report a good error message.
368+
369+ if !trait_ref. has_infer_types ( ) &&
370+ predicate_can_apply ( infcx, trait_ref)
371+ {
372+ err. fileline_help ( obligation. cause . span , & format ! (
373+ "consider adding a `where {}` bound" ,
374+ trait_ref. to_predicate( )
375+ ) ) ;
376+ } else if let Some ( s) = on_unimplemented_note ( infcx, trait_ref,
377+ obligation. cause . span ) {
368378 err. fileline_note ( obligation. cause . span , & s) ;
369379 } else {
370380 let simp = fast_reject:: simplify_type ( infcx. tcx ,
@@ -644,6 +654,55 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
644654 }
645655}
646656
657+ /// Returns whether the trait predicate may apply for *some* assignment
658+ /// to the type parameters.
659+ fn predicate_can_apply < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
660+ pred : ty:: PolyTraitRef < ' tcx > )
661+ -> bool
662+ {
663+ struct ParamToVarFolder < ' a , ' tcx : ' a > {
664+ infcx : & ' a InferCtxt < ' a , ' tcx > ,
665+ var_map : FnvHashMap < Ty < ' tcx > , Ty < ' tcx > >
666+ }
667+
668+ impl < ' a , ' tcx > TypeFolder < ' tcx > for ParamToVarFolder < ' a , ' tcx >
669+ {
670+ fn tcx ( & self ) -> & TyCtxt < ' tcx > { self . infcx . tcx }
671+
672+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
673+ if let ty:: TyParam ( ..) = ty. sty {
674+ let infcx = self . infcx ;
675+ self . var_map . entry ( ty) . or_insert_with ( || infcx. next_ty_var ( ) )
676+ } else {
677+ ty. super_fold_with ( self )
678+ }
679+ }
680+ }
681+
682+ infcx. probe ( |_| {
683+ let mut selcx = SelectionContext :: new ( infcx) ;
684+
685+ let cleaned_pred = pred. fold_with ( & mut ParamToVarFolder {
686+ infcx : infcx,
687+ var_map : FnvHashMap ( )
688+ } ) ;
689+
690+ let cleaned_pred = super :: project:: normalize (
691+ & mut selcx,
692+ ObligationCause :: dummy ( ) ,
693+ & cleaned_pred
694+ ) . value ;
695+
696+ let obligation = Obligation :: new (
697+ ObligationCause :: dummy ( ) ,
698+ cleaned_pred. to_predicate ( )
699+ ) ;
700+
701+ selcx. evaluate_obligation ( & obligation)
702+ } )
703+ }
704+
705+
647706fn need_type_info < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
648707 span : Span ,
649708 ty : Ty < ' tcx > )
0 commit comments