@@ -8,6 +8,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
8
8
use rustc_middle:: ty:: adjustment:: {
9
9
Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability ,
10
10
} ;
11
+ use rustc_middle:: ty:: fold:: TypeFolder ;
11
12
use rustc_middle:: ty:: TyKind :: { Adt , Array , Char , FnDef , Never , Ref , Str , Tuple , Uint } ;
12
13
use rustc_middle:: ty:: {
13
14
self , suggest_constraining_type_param, Ty , TyCtxt , TypeFoldable , TypeVisitor ,
@@ -436,29 +437,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
436
437
// we don't want the note in the else clause to be emitted
437
438
} else if let [ ty] = & visitor. 0 [ ..] {
438
439
if let ty:: Param ( p) = ty. kind {
439
- // FIXME: This *guesses* that constraining the type param
440
- // will make the operation available, but this is only true
441
- // when the corresponding trait has a blanket
442
- // implementation, like the following:
443
- // `impl<'a> PartialEq for &'a [T] where T: PartialEq {}`
444
- // The correct thing to do would be to verify this
445
- // projection would hold.
446
- if * ty != lhs_ty {
440
+ // Check if the method would be found if the type param wasn't
441
+ // involved. If so, it means that adding a trait bound to the param is
442
+ // enough. Otherwise we do not give the suggestion.
443
+ let mut eraser = TypeParamEraser ( & self , expr. span ) ;
444
+ let needs_bound = self
445
+ . lookup_op_method (
446
+ eraser. fold_ty ( lhs_ty) ,
447
+ & [ eraser. fold_ty ( rhs_ty) ] ,
448
+ Op :: Binary ( op, is_assign) ,
449
+ )
450
+ . is_ok ( ) ;
451
+ if needs_bound {
452
+ suggest_constraining_param (
453
+ self . tcx ,
454
+ self . body_id ,
455
+ & mut err,
456
+ ty,
457
+ rhs_ty,
458
+ missing_trait,
459
+ p,
460
+ use_output,
461
+ ) ;
462
+ } else if * ty != lhs_ty {
463
+ // When we know that a missing bound is responsible, we don't show
464
+ // this note as it is redundant.
447
465
err. note ( & format ! (
448
466
"the trait `{}` is not implemented for `{}`" ,
449
467
missing_trait, lhs_ty
450
468
) ) ;
451
469
}
452
- suggest_constraining_param (
453
- self . tcx ,
454
- self . body_id ,
455
- & mut err,
456
- ty,
457
- rhs_ty,
458
- missing_trait,
459
- p,
460
- use_output,
461
- ) ;
462
470
} else {
463
471
bug ! ( "type param visitor stored a non type param: {:?}" , ty. kind) ;
464
472
}
@@ -656,10 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
656
664
) ;
657
665
err. span_label (
658
666
ex. span ,
659
- format ! (
660
- "cannot apply unary operator `{}`" ,
661
- op. as_str( )
662
- ) ,
667
+ format ! ( "cannot apply unary operator `{}`" , op. as_str( ) ) ,
663
668
) ;
664
669
match actual. kind {
665
670
Uint ( _) if op == hir:: UnOp :: UnNeg => {
@@ -954,3 +959,21 @@ impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
954
959
ty. super_visit_with ( self )
955
960
}
956
961
}
962
+
963
+ struct TypeParamEraser < ' a , ' tcx > ( & ' a FnCtxt < ' a , ' tcx > , Span ) ;
964
+
965
+ impl TypeFolder < ' tcx > for TypeParamEraser < ' _ , ' tcx > {
966
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
967
+ self . 0 . tcx
968
+ }
969
+
970
+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
971
+ match ty. kind {
972
+ ty:: Param ( _) => self . 0 . next_ty_var ( TypeVariableOrigin {
973
+ kind : TypeVariableOriginKind :: MiscVariable ,
974
+ span : self . 1 ,
975
+ } ) ,
976
+ _ => ty. super_fold_with ( self ) ,
977
+ }
978
+ }
979
+ }
0 commit comments