@@ -13,6 +13,7 @@ use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple,
13
13
use rustc_middle:: ty:: { self , Ty , TypeFoldable } ;
14
14
use rustc_span:: Span ;
15
15
use rustc_trait_selection:: infer:: InferCtxtExt ;
16
+ use rustc_trait_selection:: traits:: error_reporting:: suggest_constraining_type_param;
16
17
17
18
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
18
19
/// Checks a `a <op>= b`
@@ -253,6 +254,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
253
254
// error types are considered "builtin"
254
255
if !lhs_ty. references_error ( ) {
255
256
let source_map = self . tcx . sess . source_map ( ) ;
257
+
258
+ let suggest_constraining_param =
259
+ |mut err : & mut DiagnosticBuilder < ' _ > ,
260
+ missing_trait : & str ,
261
+ p : ty:: ParamTy ,
262
+ set_output : bool | {
263
+ let hir = self . tcx . hir ( ) ;
264
+ let msg =
265
+ & format ! ( "`{}` might need a bound for `{}`" , lhs_ty, missing_trait) ;
266
+ if let Some ( def_id) = hir
267
+ . find ( hir. get_parent_item ( expr. hir_id ) )
268
+ . and_then ( |node| node. hir_id ( ) )
269
+ . and_then ( |hir_id| hir. opt_local_def_id ( hir_id) )
270
+ {
271
+ let generics = self . tcx . generics_of ( def_id) ;
272
+ let param_def_id = generics. type_param ( & p, self . tcx ) . def_id ;
273
+ if let Some ( generics) = hir
274
+ . as_local_hir_id ( param_def_id)
275
+ . and_then ( |id| hir. find ( hir. get_parent_item ( id) ) )
276
+ . as_ref ( )
277
+ . and_then ( |node| node. generics ( ) )
278
+ {
279
+ let output = if set_output {
280
+ format ! ( "<Output = {}>" , rhs_ty)
281
+ } else {
282
+ String :: new ( )
283
+ } ;
284
+ suggest_constraining_type_param (
285
+ self . tcx ,
286
+ generics,
287
+ & mut err,
288
+ & format ! ( "{}" , lhs_ty) ,
289
+ & format ! ( "{}{}" , missing_trait, output) ,
290
+ None ,
291
+ ) ;
292
+ } else {
293
+ let span = self . tcx . def_span ( param_def_id) ;
294
+ err. span_label ( span, msg) ;
295
+ }
296
+ } else {
297
+ err. note ( & msg) ;
298
+ }
299
+ } ;
300
+
256
301
match is_assign {
257
302
IsAssign :: Yes => {
258
303
let mut err = struct_span_err ! (
@@ -317,59 +362,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
317
362
// This has nothing here because it means we did string
318
363
// concatenation (e.g., "Hello " += "World!"). This means
319
364
// we don't want the note in the else clause to be emitted
320
- } else if let ty:: Param ( _) = lhs_ty. kind {
321
- // FIXME: point to span of param
322
- err. note ( & format ! (
323
- "`{}` might need a bound for `{}`" ,
324
- lhs_ty, missing_trait
325
- ) ) ;
365
+ } else if let ty:: Param ( p) = lhs_ty. kind {
366
+ suggest_constraining_param ( & mut err, missing_trait, p, false ) ;
326
367
} else if !suggested_deref {
327
368
suggest_impl_missing ( & mut err, lhs_ty, & missing_trait) ;
328
369
}
329
370
}
330
371
err. emit ( ) ;
331
372
}
332
373
IsAssign :: No => {
333
- let ( message, missing_trait) = match op. node {
374
+ let ( message, missing_trait, use_output ) = match op. node {
334
375
hir:: BinOpKind :: Add => (
335
376
format ! ( "cannot add `{}` to `{}`" , rhs_ty, lhs_ty) ,
336
377
Some ( "std::ops::Add" ) ,
378
+ true ,
337
379
) ,
338
380
hir:: BinOpKind :: Sub => (
339
381
format ! ( "cannot subtract `{}` from `{}`" , rhs_ty, lhs_ty) ,
340
382
Some ( "std::ops::Sub" ) ,
383
+ true ,
341
384
) ,
342
385
hir:: BinOpKind :: Mul => (
343
386
format ! ( "cannot multiply `{}` to `{}`" , rhs_ty, lhs_ty) ,
344
387
Some ( "std::ops::Mul" ) ,
388
+ true ,
345
389
) ,
346
390
hir:: BinOpKind :: Div => (
347
391
format ! ( "cannot divide `{}` by `{}`" , lhs_ty, rhs_ty) ,
348
392
Some ( "std::ops::Div" ) ,
393
+ true ,
349
394
) ,
350
395
hir:: BinOpKind :: Rem => (
351
396
format ! ( "cannot mod `{}` by `{}`" , lhs_ty, rhs_ty) ,
352
397
Some ( "std::ops::Rem" ) ,
398
+ true ,
353
399
) ,
354
400
hir:: BinOpKind :: BitAnd => (
355
401
format ! ( "no implementation for `{} & {}`" , lhs_ty, rhs_ty) ,
356
402
Some ( "std::ops::BitAnd" ) ,
403
+ true ,
357
404
) ,
358
405
hir:: BinOpKind :: BitXor => (
359
406
format ! ( "no implementation for `{} ^ {}`" , lhs_ty, rhs_ty) ,
360
407
Some ( "std::ops::BitXor" ) ,
408
+ true ,
361
409
) ,
362
410
hir:: BinOpKind :: BitOr => (
363
411
format ! ( "no implementation for `{} | {}`" , lhs_ty, rhs_ty) ,
364
412
Some ( "std::ops::BitOr" ) ,
413
+ true ,
365
414
) ,
366
415
hir:: BinOpKind :: Shl => (
367
416
format ! ( "no implementation for `{} << {}`" , lhs_ty, rhs_ty) ,
368
417
Some ( "std::ops::Shl" ) ,
418
+ true ,
369
419
) ,
370
420
hir:: BinOpKind :: Shr => (
371
421
format ! ( "no implementation for `{} >> {}`" , lhs_ty, rhs_ty) ,
372
422
Some ( "std::ops::Shr" ) ,
423
+ true ,
373
424
) ,
374
425
hir:: BinOpKind :: Eq | hir:: BinOpKind :: Ne => (
375
426
format ! (
@@ -378,6 +429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
378
429
lhs_ty
379
430
) ,
380
431
Some ( "std::cmp::PartialEq" ) ,
432
+ false ,
381
433
) ,
382
434
hir:: BinOpKind :: Lt
383
435
| hir:: BinOpKind :: Le
@@ -389,6 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
389
441
lhs_ty
390
442
) ,
391
443
Some ( "std::cmp::PartialOrd" ) ,
444
+ false ,
392
445
) ,
393
446
_ => (
394
447
format ! (
@@ -397,6 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
397
450
lhs_ty
398
451
) ,
399
452
None ,
453
+ false ,
400
454
) ,
401
455
} ;
402
456
let mut err = struct_span_err ! (
@@ -459,12 +513,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
459
513
// This has nothing here because it means we did string
460
514
// concatenation (e.g., "Hello " + "World!"). This means
461
515
// we don't want the note in the else clause to be emitted
462
- } else if let ty:: Param ( _) = lhs_ty. kind {
463
- // FIXME: point to span of param
464
- err. note ( & format ! (
465
- "`{}` might need a bound for `{}`" ,
466
- lhs_ty, missing_trait
467
- ) ) ;
516
+ } else if let ty:: Param ( p) = lhs_ty. kind {
517
+ suggest_constraining_param (
518
+ & mut err,
519
+ missing_trait,
520
+ p,
521
+ use_output,
522
+ ) ;
468
523
} else if !suggested_deref && !involves_fn {
469
524
suggest_impl_missing ( & mut err, lhs_ty, & missing_trait) ;
470
525
}
0 commit comments