@@ -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