@@ -13,10 +13,12 @@ use super::{
13
13
FulfillmentErrorCode ,
14
14
MismatchedProjectionTypes ,
15
15
Obligation ,
16
+ ObligationCause ,
16
17
ObligationCauseCode ,
17
18
OutputTypeParameterMismatch ,
18
19
TraitNotObjectSafe ,
19
20
PredicateObligation ,
21
+ SelectionContext ,
20
22
SelectionError ,
21
23
ObjectSafetyViolation ,
22
24
MethodViolationCode ,
@@ -26,8 +28,9 @@ use super::{
26
28
use fmt_macros:: { Parser , Piece , Position } ;
27
29
use hir:: def_id:: DefId ;
28
30
use infer:: InferCtxt ;
29
- use ty:: { self , ToPredicate , ToPolyTraitRef , TraitRef , Ty , TyCtxt , TypeFoldable } ;
31
+ use ty:: { self , ToPredicate , ToPolyTraitRef , Ty , TyCtxt } ;
30
32
use ty:: fast_reject;
33
+ use ty:: fold:: { TypeFoldable , TypeFolder } ;
31
34
use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
32
35
33
36
use std:: cmp;
@@ -90,12 +93,7 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
90
93
let predicate =
91
94
infcx. resolve_type_vars_if_possible ( & obligation. predicate ) ;
92
95
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 ( ) {
99
97
let mut err = struct_span_err ! ( infcx. tcx. sess, obligation. cause. span, E0271 ,
100
98
"type mismatch resolving `{}`: {}" ,
101
99
predicate,
@@ -105,9 +103,10 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
105
103
}
106
104
}
107
105
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 ( ) ;
111
110
let def_id = trait_ref. def_id ;
112
111
let mut report = None ;
113
112
for item in infcx. tcx . get_attrs ( def_id) . iter ( ) {
@@ -175,6 +174,53 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
175
174
report
176
175
}
177
176
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
+
178
224
/// Reports that an overflow has occurred and halts compilation. We
179
225
/// halt compilation unconditionally because it is important that
180
226
/// overflows never be masked -- they basically represent computations
@@ -362,56 +408,39 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
362
408
let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
363
409
let mut err = struct_span_err ! (
364
410
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.
373
434
err. fileline_note ( obligation. cause . span , & s) ;
374
435
} 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.
399
438
439
+ let impl_candidates =
440
+ find_similar_impl_candidates ( infcx, trait_ref) ;
400
441
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) ;
415
444
}
416
445
}
417
446
note_obligation_cause ( infcx, & mut err, obligation) ;
@@ -649,6 +678,55 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
649
678
}
650
679
}
651
680
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
+
652
730
fn need_type_info < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
653
731
span : Span ,
654
732
ty : Ty < ' tcx > )
0 commit comments