@@ -9,7 +9,9 @@ use rustc_middle::ty::adjustment::{
9
9
Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability ,
10
10
} ;
11
11
use rustc_middle:: ty:: TyKind :: { Adt , Array , Char , FnDef , Never , Ref , Str , Tuple , Uint } ;
12
- use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty , TyCtxt , TypeFoldable } ;
12
+ use rustc_middle:: ty:: {
13
+ self , suggest_constraining_type_param, Ty , TyCtxt , TypeFoldable , TypeVisitor ,
14
+ } ;
13
15
use rustc_span:: symbol:: Ident ;
14
16
use rustc_span:: Span ;
15
17
use rustc_trait_selection:: infer:: InferCtxtExt ;
@@ -254,6 +256,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
254
256
if !lhs_ty. references_error ( ) && !rhs_ty. references_error ( ) {
255
257
let source_map = self . tcx . sess . source_map ( ) ;
256
258
259
+ let note = |err : & mut DiagnosticBuilder < ' _ > , missing_trait| {
260
+ err. note ( & format ! (
261
+ "the trait `{}` is not implemented for `{}`" ,
262
+ missing_trait, lhs_ty
263
+ ) ) ;
264
+ } ;
257
265
match is_assign {
258
266
IsAssign :: Yes => {
259
267
let mut err = struct_span_err ! (
@@ -286,10 +294,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
286
294
rty. peel_refs( ) ,
287
295
lstring,
288
296
) ;
289
- err. span_suggestion (
290
- lhs_expr. span ,
297
+ err. span_suggestion_verbose (
298
+ lhs_expr. span . shrink_to_lo ( ) ,
291
299
msg,
292
- format ! ( "*{}" , lstring ) ,
300
+ "*" . to_string ( ) ,
293
301
rustc_errors:: Applicability :: MachineApplicable ,
294
302
) ;
295
303
suggested_deref = true ;
@@ -310,6 +318,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
310
318
_ => None ,
311
319
} ;
312
320
if let Some ( missing_trait) = missing_trait {
321
+ let mut visitor = TypeParamVisitor ( vec ! [ ] ) ;
322
+ visitor. visit_ty ( lhs_ty) ;
323
+
324
+ let mut sugg = false ;
313
325
if op. node == hir:: BinOpKind :: Add
314
326
&& self . check_str_addition (
315
327
lhs_expr, rhs_expr, lhs_ty, rhs_ty, & mut err, true , op,
@@ -318,18 +330,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
318
330
// This has nothing here because it means we did string
319
331
// concatenation (e.g., "Hello " += "World!"). This means
320
332
// we don't want the note in the else clause to be emitted
321
- } else if let ty:: Param ( p) = lhs_ty. kind {
322
- suggest_constraining_param (
323
- self . tcx ,
324
- self . body_id ,
325
- & mut err,
326
- lhs_ty,
327
- rhs_ty,
328
- missing_trait,
329
- p,
330
- false ,
331
- ) ;
332
- } else if !suggested_deref {
333
+ sugg = true ;
334
+ } else if let [ ty] = & visitor. 0 [ ..] {
335
+ if let ty:: Param ( p) = ty. kind {
336
+ // FIXME: This *guesses* that constraining the type param
337
+ // will make the operation available, but this is only true
338
+ // when the corresponding trait has a blanked
339
+ // implementation, like the following:
340
+ // `impl<'a> PartialEq for &'a [T] where T: PartialEq {}`
341
+ // The correct thing to do would be to verify this
342
+ // projection would hold.
343
+ if * ty != lhs_ty {
344
+ note ( & mut err, missing_trait) ;
345
+ }
346
+ suggest_constraining_param (
347
+ self . tcx ,
348
+ self . body_id ,
349
+ & mut err,
350
+ ty,
351
+ rhs_ty,
352
+ missing_trait,
353
+ p,
354
+ false ,
355
+ ) ;
356
+ sugg = true ;
357
+ }
358
+ }
359
+ if !sugg && !suggested_deref {
333
360
suggest_impl_missing ( & mut err, lhs_ty, & missing_trait) ;
334
361
}
335
362
}
@@ -458,18 +485,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458
485
. is_ok ( )
459
486
} {
460
487
if let Ok ( lstring) = source_map. span_to_snippet ( lhs_expr. span ) {
461
- err. help ( & format ! (
462
- "`{}` can be used on '{}', you can \
463
- dereference `{2}`: `*{2}`",
464
- op. node. as_str( ) ,
465
- rty. peel_refs( ) ,
466
- lstring
467
- ) ) ;
488
+ err. span_suggestion_verbose (
489
+ lhs_expr. span . shrink_to_lo ( ) ,
490
+ & format ! (
491
+ "`{}` can be used on `{}`, you can dereference \
492
+ `{}`",
493
+ op. node. as_str( ) ,
494
+ rty. peel_refs( ) ,
495
+ lstring,
496
+ ) ,
497
+ "*" . to_string ( ) ,
498
+ Applicability :: MachineApplicable ,
499
+ ) ;
468
500
suggested_deref = true ;
469
501
}
470
502
}
471
503
}
472
504
if let Some ( missing_trait) = missing_trait {
505
+ let mut visitor = TypeParamVisitor ( vec ! [ ] ) ;
506
+ visitor. visit_ty ( lhs_ty) ;
507
+
508
+ let mut sugg = false ;
473
509
if op. node == hir:: BinOpKind :: Add
474
510
&& self . check_str_addition (
475
511
lhs_expr, rhs_expr, lhs_ty, rhs_ty, & mut err, false , op,
@@ -478,18 +514,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
478
514
// This has nothing here because it means we did string
479
515
// concatenation (e.g., "Hello " + "World!"). This means
480
516
// we don't want the note in the else clause to be emitted
481
- } else if let ty:: Param ( p) = lhs_ty. kind {
482
- suggest_constraining_param (
483
- self . tcx ,
484
- self . body_id ,
485
- & mut err,
486
- lhs_ty,
487
- rhs_ty,
488
- missing_trait,
489
- p,
490
- use_output,
491
- ) ;
492
- } else if !suggested_deref && !involves_fn {
517
+ sugg = true ;
518
+ } else if let [ ty] = & visitor. 0 [ ..] {
519
+ if let ty:: Param ( p) = ty. kind {
520
+ // FIXME: This *guesses* that constraining the type param
521
+ // will make the operation available, but this is only true
522
+ // when the corresponding trait has a blanked
523
+ // implementation, like the following:
524
+ // `impl<'a> PartialEq for &'a [T] where T: PartialEq {}`
525
+ // The correct thing to do would be to verify this
526
+ // projection would hold.
527
+ if * ty != lhs_ty {
528
+ note ( & mut err, missing_trait) ;
529
+ }
530
+ suggest_constraining_param (
531
+ self . tcx ,
532
+ self . body_id ,
533
+ & mut err,
534
+ ty,
535
+ rhs_ty,
536
+ missing_trait,
537
+ p,
538
+ use_output,
539
+ ) ;
540
+ sugg = true ;
541
+ }
542
+ }
543
+ if !sugg && !suggested_deref && !involves_fn {
493
544
suggest_impl_missing ( & mut err, lhs_ty, & missing_trait) ;
494
545
}
495
546
}
@@ -928,8 +979,7 @@ fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_tra
928
979
if let Adt ( def, _) = ty. peel_refs ( ) . kind {
929
980
if def. did . is_local ( ) {
930
981
err. note ( & format ! (
931
- "an implementation of `{}` might \
932
- be missing for `{}`",
982
+ "an implementation of `{}` might be missing for `{}`" ,
933
983
missing_trait, ty
934
984
) ) ;
935
985
}
@@ -975,3 +1025,14 @@ fn suggest_constraining_param(
975
1025
err. span_label ( span, msg) ;
976
1026
}
977
1027
}
1028
+
1029
+ struct TypeParamVisitor < ' tcx > ( Vec < Ty < ' tcx > > ) ;
1030
+
1031
+ impl < ' tcx > TypeVisitor < ' tcx > for TypeParamVisitor < ' tcx > {
1032
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
1033
+ if let ty:: Param ( _) = ty. kind {
1034
+ self . 0 . push ( ty) ;
1035
+ }
1036
+ ty. super_visit_with ( self )
1037
+ }
1038
+ }
0 commit comments