@@ -8,6 +8,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
88use rustc_middle:: ty:: adjustment:: {
99 Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability ,
1010} ;
11+ use rustc_middle:: ty:: fold:: TypeFolder ;
1112use rustc_middle:: ty:: TyKind :: { Adt , Array , Char , FnDef , Never , Ref , Str , Tuple , Uint } ;
1213use rustc_middle:: ty:: {
1314 self , suggest_constraining_type_param, Ty , TyCtxt , TypeFoldable , TypeVisitor ,
@@ -436,29 +437,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
436437 // we don't want the note in the else clause to be emitted
437438 } else if let [ ty] = & visitor. 0 [ ..] {
438439 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.
447465 err. note ( & format ! (
448466 "the trait `{}` is not implemented for `{}`" ,
449467 missing_trait, lhs_ty
450468 ) ) ;
451469 }
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- ) ;
462470 } else {
463471 bug ! ( "type param visitor stored a non type param: {:?}" , ty. kind) ;
464472 }
@@ -656,10 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
656664 ) ;
657665 err. span_label (
658666 ex. span ,
659- format ! (
660- "cannot apply unary operator `{}`" ,
661- op. as_str( )
662- ) ,
667+ format ! ( "cannot apply unary operator `{}`" , op. as_str( ) ) ,
663668 ) ;
664669 match actual. kind {
665670 Uint ( _) if op == hir:: UnOp :: UnNeg => {
@@ -954,3 +959,21 @@ impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
954959 ty. super_visit_with ( self )
955960 }
956961}
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