@@ -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 hir:: 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;
@@ -90,12 +93,7 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
9093 let predicate =
9194 infcx. resolve_type_vars_if_possible ( & obligation. predicate ) ;
9295
93- // The TyError created by normalize_to_error can end up being unified
94- // into all obligations: for example, if our obligation is something
95- // like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>,
96- // then $X will be unified with TyError, but the error still needs to be
97- // reported.
98- if !infcx. tcx . sess . has_errors ( ) || !predicate. references_error ( ) {
96+ if !predicate. references_error ( ) {
9997 let mut err = struct_span_err ! ( infcx. tcx. sess, obligation. cause. span, E0271 ,
10098 "type mismatch resolving `{}`: {}" ,
10199 predicate,
@@ -105,9 +103,10 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
105103 }
106104}
107105
108- fn report_on_unimplemented < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
109- trait_ref : & TraitRef < ' tcx > ,
110- 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 ( ) ;
111110 let def_id = trait_ref. def_id ;
112111 let mut report = None ;
113112 for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
@@ -175,6 +174,53 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
175174 report
176175}
177176
177+ fn find_similar_impl_candidates < ' a , ' tcx > (
178+ infcx : & InferCtxt < ' a , ' tcx > ,
179+ trait_ref : ty:: PolyTraitRef < ' tcx > )
180+ -> Vec < ty:: TraitRef < ' tcx > >
181+ {
182+ let simp = fast_reject:: simplify_type ( infcx. tcx ,
183+ trait_ref. skip_binder ( ) . self_ty ( ) ,
184+ true ) ;
185+ let mut impl_candidates = Vec :: new ( ) ;
186+ let trait_def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ( ) ) ;
187+
188+ match simp {
189+ Some ( simp) => trait_def. for_each_impl ( infcx. tcx , |def_id| {
190+ let imp = infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
191+ let imp_simp = fast_reject:: simplify_type ( infcx. tcx ,
192+ imp. self_ty ( ) ,
193+ true ) ;
194+ if let Some ( imp_simp) = imp_simp {
195+ if simp != imp_simp {
196+ return ;
197+ }
198+ }
199+ impl_candidates. push ( imp) ;
200+ } ) ,
201+ None => trait_def. for_each_impl ( infcx. tcx , |def_id| {
202+ impl_candidates. push (
203+ infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ) ;
204+ } )
205+ } ;
206+ impl_candidates
207+ }
208+
209+ fn report_similar_impl_candidates ( span : Span ,
210+ err : & mut DiagnosticBuilder ,
211+ impl_candidates : & [ ty:: TraitRef ] )
212+ {
213+ err. fileline_help ( span, & format ! ( "the following implementations were found:" ) ) ;
214+
215+ let end = cmp:: min ( 4 , impl_candidates. len ( ) ) ;
216+ for candidate in & impl_candidates[ 0 ..end] {
217+ err. fileline_help ( span, & format ! ( " {:?}" , candidate) ) ;
218+ }
219+ if impl_candidates. len ( ) > 4 {
220+ err. fileline_help ( span, & format ! ( "and {} others" , impl_candidates. len( ) -4 ) ) ;
221+ }
222+ }
223+
178224/// Reports that an overflow has occurred and halts compilation. We
179225/// halt compilation unconditionally because it is important that
180226/// overflows never be masked -- they basically represent computations
@@ -362,56 +408,39 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
362408 let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
363409 let mut err = struct_span_err ! (
364410 infcx. tcx. sess, obligation. cause. span, E0277 ,
365- "the trait `{}` is not implemented for the type `{}`" ,
366- trait_ref, trait_ref. self_ty( ) ) ;
367-
368- // Check if it has a custom "#[rustc_on_unimplemented]"
369- // error message, report with that message if it does
370- let custom_note = report_on_unimplemented ( infcx, & trait_ref. 0 ,
371- obligation. cause . span ) ;
372- if let Some ( s) = custom_note {
411+ "the trait bound `{}` is not satisfied" ,
412+ trait_ref. to_predicate( ) ) ;
413+
414+ // Try to report a help message
415+
416+ if !trait_ref. has_infer_types ( ) &&
417+ predicate_can_apply ( infcx, trait_ref)
418+ {
419+ // If a where-clause may be useful, remind the
420+ // user that they can add it.
421+ //
422+ // don't display an on-unimplemented note, as
423+ // these notes will often be of the form
424+ // "the type `T` can't be frobnicated"
425+ // which is somewhat confusing.
426+ err. fileline_help ( obligation. cause . span , & format ! (
427+ "consider adding a `where {}` bound" ,
428+ trait_ref. to_predicate( )
429+ ) ) ;
430+ } else if let Some ( s) = on_unimplemented_note ( infcx, trait_ref,
431+ obligation. cause . span ) {
432+ // Otherwise, if there is an on-unimplemented note,
433+ // display it.
373434 err. fileline_note ( obligation. cause . span , & s) ;
374435 } else {
375- let simp = fast_reject:: simplify_type ( infcx. tcx ,
376- trait_ref. self_ty ( ) ,
377- true ) ;
378- let mut impl_candidates = Vec :: new ( ) ;
379- let trait_def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ( ) ) ;
380-
381- match simp {
382- Some ( simp) => trait_def. for_each_impl ( infcx. tcx , |def_id| {
383- let imp = infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
384- let imp_simp = fast_reject:: simplify_type ( infcx. tcx ,
385- imp. self_ty ( ) ,
386- true ) ;
387- if let Some ( imp_simp) = imp_simp {
388- if simp != imp_simp {
389- return ;
390- }
391- }
392- impl_candidates. push ( imp) ;
393- } ) ,
394- None => trait_def. for_each_impl ( infcx. tcx , |def_id| {
395- impl_candidates. push (
396- infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ) ;
397- } )
398- } ;
436+ // If we can't show anything useful, try to find
437+ // similar impls.
399438
439+ let impl_candidates =
440+ find_similar_impl_candidates ( infcx, trait_ref) ;
400441 if impl_candidates. len ( ) > 0 {
401- err. fileline_help (
402- obligation. cause . span ,
403- & format ! ( "the following implementations were found:" ) ) ;
404-
405- let end = cmp:: min ( 4 , impl_candidates. len ( ) ) ;
406- for candidate in & impl_candidates[ 0 ..end] {
407- err. fileline_help ( obligation. cause . span ,
408- & format ! ( " {:?}" , candidate) ) ;
409- }
410- if impl_candidates. len ( ) > 4 {
411- err. fileline_help ( obligation. cause . span ,
412- & format ! ( "and {} others" ,
413- impl_candidates. len( ) -4 ) ) ;
414- }
442+ report_similar_impl_candidates ( obligation. cause . span ,
443+ & mut err, & impl_candidates) ;
415444 }
416445 }
417446 note_obligation_cause ( infcx, & mut err, obligation) ;
@@ -649,6 +678,55 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
649678 }
650679}
651680
681+ /// Returns whether the trait predicate may apply for *some* assignment
682+ /// to the type parameters.
683+ fn predicate_can_apply < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
684+ pred : ty:: PolyTraitRef < ' tcx > )
685+ -> bool
686+ {
687+ struct ParamToVarFolder < ' a , ' tcx : ' a > {
688+ infcx : & ' a InferCtxt < ' a , ' tcx > ,
689+ var_map : FnvHashMap < Ty < ' tcx > , Ty < ' tcx > >
690+ }
691+
692+ impl < ' a , ' tcx > TypeFolder < ' tcx > for ParamToVarFolder < ' a , ' tcx >
693+ {
694+ fn tcx ( & self ) -> & TyCtxt < ' tcx > { self . infcx . tcx }
695+
696+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
697+ if let ty:: TyParam ( ..) = ty. sty {
698+ let infcx = self . infcx ;
699+ self . var_map . entry ( ty) . or_insert_with ( || infcx. next_ty_var ( ) )
700+ } else {
701+ ty. super_fold_with ( self )
702+ }
703+ }
704+ }
705+
706+ infcx. probe ( |_| {
707+ let mut selcx = SelectionContext :: new ( infcx) ;
708+
709+ let cleaned_pred = pred. fold_with ( & mut ParamToVarFolder {
710+ infcx : infcx,
711+ var_map : FnvHashMap ( )
712+ } ) ;
713+
714+ let cleaned_pred = super :: project:: normalize (
715+ & mut selcx,
716+ ObligationCause :: dummy ( ) ,
717+ & cleaned_pred
718+ ) . value ;
719+
720+ let obligation = Obligation :: new (
721+ ObligationCause :: dummy ( ) ,
722+ cleaned_pred. to_predicate ( )
723+ ) ;
724+
725+ selcx. evaluate_obligation ( & obligation)
726+ } )
727+ }
728+
729+
652730fn need_type_info < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
653731 span : Span ,
654732 ty : Ty < ' tcx > )
0 commit comments