@@ -11,13 +11,12 @@ use rustc_middle::ty::adjustment::{
11
11
} ;
12
12
use rustc_middle:: ty:: fold:: TypeFolder ;
13
13
use 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 } ;
17
15
use rustc_span:: source_map:: Spanned ;
18
16
use rustc_span:: symbol:: { sym, Ident } ;
19
17
use rustc_span:: Span ;
20
18
use rustc_trait_selection:: infer:: InferCtxtExt ;
19
+ use rustc_trait_selection:: traits:: error_reporting:: suggestions:: InferCtxtExt as _;
21
20
use rustc_trait_selection:: traits:: { FulfillmentError , TraitEngine , TraitEngineExt } ;
22
21
23
22
use std:: ops:: ControlFlow ;
@@ -266,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
266
265
Err ( _) if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) => self . tcx . ty_error ( ) ,
267
266
Err ( errors) => {
268
267
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 {
270
269
IsAssign :: Yes => {
271
270
let mut err = struct_span_err ! (
272
271
self . tcx. sess,
@@ -449,39 +448,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
449
448
// concatenation (e.g., "Hello " + "World!"). This means
450
449
// we don't want the note in the else clause to be emitted
451
450
} 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 (
469
473
& mut err,
470
- * ty,
471
- rhs_ty,
472
- missing_trait,
473
- p,
474
- use_output,
474
+ pred,
475
+ self . body_id ,
475
476
) ;
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
- ) ) ;
482
477
}
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
+ ) ) ;
485
484
}
486
485
}
487
486
}
@@ -671,24 +670,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
671
670
ex. span ,
672
671
format ! ( "cannot apply unary operator `{}`" , op. as_str( ) ) ,
673
672
) ;
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
+
679
674
let mut visitor = TypeParamVisitor ( vec ! [ ] ) ;
680
675
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
+ }
692
689
}
693
690
694
691
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
973
970
}
974
971
}
975
972
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
-
1016
973
struct TypeParamVisitor < ' tcx > ( Vec < Ty < ' tcx > > ) ;
1017
974
1018
975
impl < ' tcx > TypeVisitor < ' tcx > for TypeParamVisitor < ' tcx > {
0 commit comments