@@ -11,13 +11,12 @@ use rustc_middle::ty::adjustment::{
1111} ; 
1212use  rustc_middle:: ty:: fold:: TypeFolder ; 
1313use  rustc_middle:: ty:: TyKind :: { Adt ,  Array ,  Char ,  FnDef ,  Never ,  Ref ,  Str ,  Tuple ,  Uint } ; 
14- use  rustc_middle:: ty:: { 
15-     self ,  suggest_constraining_type_param,  Ty ,  TyCtxt ,  TypeFoldable ,  TypeVisitor , 
16- } ; 
14+ use  rustc_middle:: ty:: { self ,  Ty ,  TyCtxt ,  TypeFoldable ,  TypeVisitor } ; 
1715use  rustc_span:: source_map:: Spanned ; 
1816use  rustc_span:: symbol:: { sym,  Ident } ; 
1917use  rustc_span:: Span ; 
2018use  rustc_trait_selection:: infer:: InferCtxtExt ; 
19+ use  rustc_trait_selection:: traits:: error_reporting:: suggestions:: InferCtxtExt  as  _; 
2120use  rustc_trait_selection:: traits:: { FulfillmentError ,  TraitEngine ,  TraitEngineExt } ; 
2221
2322use  std:: ops:: ControlFlow ; 
@@ -266,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
266265            Err ( _)  if  lhs_ty. references_error ( )  || rhs_ty. references_error ( )  => self . tcx . ty_error ( ) , 
267266            Err ( errors)  => { 
268267                let  source_map = self . tcx . sess . source_map ( ) ; 
269-                 let  ( mut  err,  missing_trait,  use_output )  = match  is_assign { 
268+                 let  ( mut  err,  missing_trait,  _use_output )  = match  is_assign { 
270269                    IsAssign :: Yes  => { 
271270                        let  mut  err = struct_span_err ! ( 
272271                            self . tcx. sess, 
@@ -449,39 +448,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
449448                        // concatenation (e.g., "Hello " + "World!"). This means 
450449                        // we don't want the note in the else clause to be emitted 
451450                    }  else  if  let  [ ty]  = & visitor. 0 [ ..]  { 
452-                         if  let  ty:: Param ( p)  = * ty. kind ( )  { 
453-                             // Check if the method would be found if the type param wasn't 
454-                             // involved. If so, it means that adding a trait bound to the param is 
455-                             // enough. Otherwise we do not give the suggestion. 
456-                             let  mut  eraser = TypeParamEraser ( self ,  expr. span ) ; 
457-                             let  needs_bound = self 
458-                                 . lookup_op_method ( 
459-                                     eraser. fold_ty ( lhs_ty) , 
460-                                     Some ( eraser. fold_ty ( rhs_ty) ) , 
461-                                     Some ( rhs_expr) , 
462-                                     Op :: Binary ( op,  is_assign) , 
463-                                 ) 
464-                                 . is_ok ( ) ; 
465-                             if  needs_bound { 
466-                                 suggest_constraining_param ( 
467-                                     self . tcx , 
468-                                     self . body_id , 
451+                         // Look for a TraitPredicate in the Fulfillment errors, 
452+                         // and use it to generate a suggestion. 
453+                         // 
454+                         // Note that lookup_op_method must be called again but 
455+                         // with a specific rhs_ty instead of a placeholder so 
456+                         // the resulting predicate generates a more specific 
457+                         // suggestion for the user. 
458+                         let  errors = self 
459+                             . lookup_op_method ( 
460+                                 lhs_ty, 
461+                                 Some ( rhs_ty) , 
462+                                 Some ( rhs_expr) , 
463+                                 Op :: Binary ( op,  is_assign) , 
464+                             ) 
465+                             . unwrap_err ( ) ; 
466+                         let  predicates = errors
467+                             . into_iter ( ) 
468+                             . filter_map ( |error| error. obligation . predicate . to_opt_poly_trait_pred ( ) ) 
469+                             . collect :: < Vec < _ > > ( ) ; 
470+                         if  !predicates. is_empty ( )  { 
471+                             for  pred in  predicates { 
472+                                 self . infcx . suggest_restricting_param_bound ( 
469473                                    & mut  err, 
470-                                     * ty, 
471-                                     rhs_ty, 
472-                                     missing_trait, 
473-                                     p, 
474-                                     use_output, 
474+                                     pred, 
475+                                     self . body_id , 
475476                                ) ; 
476-                             }  else  if  * ty != lhs_ty { 
477-                                 // When we know that a missing bound is responsible, we don't show 
478-                                 // this note as it is redundant. 
479-                                 err. note ( & format ! ( 
480-                                     "the trait `{missing_trait}` is not implemented for `{lhs_ty}`" 
481-                                 ) ) ; 
482477                            } 
483-                         }  else  { 
484-                             bug ! ( "type param visitor stored a non type param: {:?}" ,  ty. kind( ) ) ; 
478+                         }  else  if  * ty != lhs_ty { 
479+                             // When we know that a missing bound is responsible, we don't show 
480+                             // this note as it is redundant. 
481+                             err. note ( & format ! ( 
482+                                 "the trait `{missing_trait}` is not implemented for `{lhs_ty}`" 
483+                             ) ) ; 
485484                        } 
486485                    } 
487486                } 
@@ -671,24 +670,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
671670                        ex. span , 
672671                        format ! ( "cannot apply unary operator `{}`" ,  op. as_str( ) ) , 
673672                    ) ; 
674-                     let  missing_trait = match  op { 
675-                         hir:: UnOp :: Deref  => unreachable ! ( "check unary op `-` or `!` only" ) , 
676-                         hir:: UnOp :: Not  => "std::ops::Not" , 
677-                         hir:: UnOp :: Neg  => "std::ops::Neg" , 
678-                     } ; 
673+ 
679674                    let  mut  visitor = TypeParamVisitor ( vec ! [ ] ) ; 
680675                    visitor. visit_ty ( operand_ty) ; 
681-                     if  let  [ ty]  = & visitor. 0 [ ..]  && let  ty:: Param ( p)  = * operand_ty. kind ( )  { 
682-                         suggest_constraining_param ( 
683-                             self . tcx , 
684-                             self . body_id , 
685-                             & mut  err, 
686-                             * ty, 
687-                             operand_ty, 
688-                             missing_trait, 
689-                             p, 
690-                             true , 
691-                         ) ; 
676+                     if  let  [ _]  = & visitor. 0 [ ..]  && let  ty:: Param ( _)  = * operand_ty. kind ( )  { 
677+                         let  predicates = errors
678+                             . iter ( ) 
679+                             . filter_map ( |error| { 
680+                                 error. obligation . predicate . clone ( ) . to_opt_poly_trait_pred ( ) 
681+                             } ) ; 
682+                         for  pred in  predicates { 
683+                             self . infcx . suggest_restricting_param_bound ( 
684+                                 & mut  err, 
685+                                 pred, 
686+                                 self . body_id , 
687+                             ) ; 
688+                         } 
692689                    } 
693690
694691                    let  sp = self . tcx . sess . source_map ( ) . start_point ( ex. span ) ; 
@@ -973,46 +970,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
973970    } 
974971} 
975972
976- fn  suggest_constraining_param ( 
977-     tcx :  TyCtxt < ' _ > , 
978-     body_id :  hir:: HirId , 
979-     mut  err :  & mut  Diagnostic , 
980-     lhs_ty :  Ty < ' _ > , 
981-     rhs_ty :  Ty < ' _ > , 
982-     missing_trait :  & str , 
983-     p :  ty:: ParamTy , 
984-     set_output :  bool , 
985- )  { 
986-     let  hir = tcx. hir ( ) ; 
987-     let  msg = & format ! ( "`{lhs_ty}` might need a bound for `{missing_trait}`" ) ; 
988-     // Try to find the def-id and details for the parameter p. We have only the index, 
989-     // so we have to find the enclosing function's def-id, then look through its declared 
990-     // generic parameters to get the declaration. 
991-     let  def_id = hir. body_owner_def_id ( hir:: BodyId  {  hir_id :  body_id } ) ; 
992-     let  generics = tcx. generics_of ( def_id) ; 
993-     let  param_def_id = generics. type_param ( & p,  tcx) . def_id ; 
994-     if  let  Some ( generics)  = param_def_id
995-         . as_local ( ) 
996-         . map ( |id| hir. local_def_id_to_hir_id ( id) ) 
997-         . and_then ( |id| hir. find_by_def_id ( hir. get_parent_item ( id) ) ) 
998-         . as_ref ( ) 
999-         . and_then ( |node| node. generics ( ) ) 
1000-     { 
1001-         let  output = if  set_output {  format ! ( "<Output = {rhs_ty}>" )  }  else  {  String :: new ( )  } ; 
1002-         suggest_constraining_type_param ( 
1003-             tcx, 
1004-             generics, 
1005-             & mut  err, 
1006-             & lhs_ty. to_string ( ) , 
1007-             & format ! ( "{missing_trait}{output}" ) , 
1008-             None , 
1009-         ) ; 
1010-     }  else  { 
1011-         let  span = tcx. def_span ( param_def_id) ; 
1012-         err. span_label ( span,  msg) ; 
1013-     } 
1014- } 
1015- 
1016973struct  TypeParamVisitor < ' tcx > ( Vec < Ty < ' tcx > > ) ; 
1017974
1018975impl < ' tcx >  TypeVisitor < ' tcx >  for  TypeParamVisitor < ' tcx >  { 
0 commit comments