@@ -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,40 +448,33 @@ 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 ,
469
- & mut err,
470
- * ty,
471
- rhs_ty,
472
- missing_trait,
473
- p,
474
- use_output,
475
- ) ;
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
- }
483
- } else {
484
- bug ! ( "type param visitor stored a non type param: {:?}" , ty. kind( ) ) ;
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 ( lhs_ty, & [ rhs_ty] , Op :: Binary ( op, is_assign) )
460
+ . unwrap_err ( ) ;
461
+ let predicates = errors
462
+ . into_iter ( )
463
+ . filter_map ( |error| error. obligation . predicate . to_opt_poly_trait_pred ( ) )
464
+ . collect :: < Vec < _ > > ( ) ;
465
+ if !predicates. is_empty ( ) {
466
+ for pred in predicates {
467
+ self . infcx . suggest_restricting_param_bound ( & mut err,
468
+ pred,
469
+ self . body_id ,
470
+ ) ;
485
471
}
472
+ } else if * ty != lhs_ty {
473
+ // When we know that a missing bound is responsible, we don't show
474
+ // this note as it is redundant.
475
+ err. note ( & format ! (
476
+ "the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
477
+ ) ) ;
486
478
}
487
479
}
488
480
err. emit ( ) ;
@@ -973,46 +965,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
973
965
}
974
966
}
975
967
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
968
struct TypeParamVisitor < ' tcx > ( Vec < Ty < ' tcx > > ) ;
1017
969
1018
970
impl < ' tcx > TypeVisitor < ' tcx > for TypeParamVisitor < ' tcx > {
0 commit comments