@@ -324,8 +324,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
324
324
sp,
325
325
) ;
326
326
327
- match ( & expected. sty , & checked_ty. sty ) {
328
- ( & ty:: Ref ( _, exp, _) , & ty:: Ref ( _, check, _) ) => match ( & exp. sty , & check. sty ) {
327
+ // Check the `expn_info()` to see if this is a macro; if so, it's hard to
328
+ // extract the text and make a good suggestion, so don't bother.
329
+ let is_macro = sp. ctxt ( ) . outer ( ) . expn_info ( ) . is_some ( ) ;
330
+
331
+ match ( & expr. node , & expected. sty , & checked_ty. sty ) {
332
+ ( _, & ty:: Ref ( _, exp, _) , & ty:: Ref ( _, check, _) ) => match ( & exp. sty , & check. sty ) {
329
333
( & ty:: Str , & ty:: Array ( arr, _) ) |
330
334
( & ty:: Str , & ty:: Slice ( arr) ) if arr == self . tcx . types . u8 => {
331
335
if let hir:: ExprKind :: Lit ( _) = expr. node {
@@ -352,7 +356,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
352
356
}
353
357
_ => { }
354
358
} ,
355
- ( & ty:: Ref ( _, _, mutability) , _) => {
359
+ ( _ , & ty:: Ref ( _, _, mutability) , _) => {
356
360
// Check if it can work when put into a ref. For example:
357
361
//
358
362
// ```
@@ -407,65 +411,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
407
411
} ) ;
408
412
}
409
413
}
410
- }
411
- ( _, & ty:: Ref ( _, checked, _) ) => {
414
+ } ,
415
+ ( hir:: ExprKind :: AddrOf ( _, ref expr) , _, & ty:: Ref ( _, checked, _) ) if {
416
+ self . infcx . can_sub ( self . param_env , checked, & expected) . is_ok ( ) && !is_macro
417
+ } => {
412
418
// We have `&T`, check if what was expected was `T`. If so,
413
- // we may want to suggest adding a `*`, or removing
414
- // a `&`.
415
- //
416
- // (But, also check the `expn_info()` to see if this is
417
- // a macro; if so, it's hard to extract the text and make a good
418
- // suggestion, so don't bother.)
419
- if self . infcx . can_sub ( self . param_env , checked, & expected) . is_ok ( ) &&
420
- sp. ctxt ( ) . outer ( ) . expn_info ( ) . is_none ( ) {
421
- match expr. node {
422
- // Maybe remove `&`?
423
- hir:: ExprKind :: AddrOf ( _, ref expr) => {
424
- if !cm. span_to_filename ( expr. span ) . is_real ( ) {
425
- if let Ok ( code) = cm. span_to_snippet ( sp) {
426
- if code. chars ( ) . next ( ) == Some ( '&' ) {
427
- return Some ( (
428
- sp,
429
- "consider removing the borrow" ,
430
- code[ 1 ..] . to_string ( ) ) ,
431
- ) ;
432
- }
433
- }
434
- return None ;
435
- }
436
- if let Ok ( code) = cm. span_to_snippet ( expr. span ) {
437
- return Some ( ( sp, "consider removing the borrow" , code) ) ;
438
- }
439
- }
440
-
441
- // Maybe add `*`? Only if `T: Copy`.
442
- _ => {
443
- if self . infcx . type_is_copy_modulo_regions ( self . param_env ,
444
- checked,
445
- sp) {
446
- // do not suggest if the span comes from a macro (#52783)
447
- if let ( Ok ( code) , true ) = (
448
- cm. span_to_snippet ( sp) ,
449
- sp == expr. span ,
450
- ) {
451
- return Some ( (
452
- sp,
453
- "consider dereferencing the borrow" ,
454
- if is_struct_pat_shorthand_field {
455
- format ! ( "{}: *{}" , code, code)
456
- } else {
457
- format ! ( "*{}" , code)
458
- } ,
459
- ) ) ;
460
- }
461
- }
419
+ // we may want to suggest removing a `&`.
420
+ if !cm. span_to_filename ( expr. span ) . is_real ( ) {
421
+ if let Ok ( code) = cm. span_to_snippet ( sp) {
422
+ if code. chars ( ) . next ( ) == Some ( '&' ) {
423
+ return Some ( (
424
+ sp,
425
+ "consider removing the borrow" ,
426
+ code[ 1 ..] . to_string ( ) ,
427
+ ) ) ;
462
428
}
463
429
}
430
+ return None ;
464
431
}
465
- }
466
- _ => {
467
- // If neither type is a reference, then check for `Deref` implementations by
468
- // constructing a predicate to prove: `<T as Deref>::Output == U`
432
+ if let Ok ( code) = cm. span_to_snippet ( expr. span ) {
433
+ return Some ( ( sp, "consider removing the borrow" , code) ) ;
434
+ }
435
+ } ,
436
+ _ if sp == expr. span && !is_macro => {
437
+ // Check for `Deref` implementations by constructing a predicate to
438
+ // prove: `<T as Deref>::Output == U`
469
439
let deref_trait = self . tcx . lang_items ( ) . deref_trait ( ) . unwrap ( ) ;
470
440
let item_def_id = self . tcx . associated_items ( deref_trait) . next ( ) . unwrap ( ) . def_id ;
471
441
let predicate = ty:: Predicate :: Projection ( ty:: Binder :: bind ( ty:: ProjectionPredicate {
@@ -483,17 +453,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
483
453
ty : expected,
484
454
} ) ) ;
485
455
let obligation = traits:: Obligation :: new ( self . misc ( sp) , self . param_env , predicate) ;
486
- if self . infcx . predicate_may_hold ( & obligation) {
487
- if let ( Ok ( code) , true ) = ( cm. span_to_snippet ( sp) , sp == expr. span ) {
488
- let msg = if is_struct_pat_shorthand_field {
456
+ let impls_deref = self . infcx . predicate_may_hold ( & obligation) ;
457
+
458
+ // For a suggestion to make sense, the type would need to be `Copy`.
459
+ let is_copy = self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp) ;
460
+
461
+ if is_copy && impls_deref {
462
+ if let Ok ( code) = cm. span_to_snippet ( sp) {
463
+ let message = if checked_ty. is_region_ptr ( ) {
464
+ "consider dereferencing the borrow"
465
+ } else {
466
+ "consider dereferencing the type"
467
+ } ;
468
+ let suggestion = if is_struct_pat_shorthand_field {
489
469
format ! ( "{}: *{}" , code, code)
490
470
} else {
491
471
format ! ( "*{}" , code)
492
472
} ;
493
- return Some ( ( sp, "consider dereferencing the type" , msg ) ) ;
473
+ return Some ( ( sp, message , suggestion ) ) ;
494
474
}
495
475
}
496
476
}
477
+ _ => { }
497
478
}
498
479
None
499
480
}
0 commit comments