@@ -324,8 +324,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
324324 sp,
325325 ) ;
326326
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 ) {
329333 ( & ty:: Str , & ty:: Array ( arr, _) ) |
330334 ( & ty:: Str , & ty:: Slice ( arr) ) if arr == self . tcx . types . u8 => {
331335 if let hir:: ExprKind :: Lit ( _) = expr. node {
@@ -352,7 +356,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
352356 }
353357 _ => { }
354358 } ,
355- ( & ty:: Ref ( _, _, mutability) , _) => {
359+ ( _ , & ty:: Ref ( _, _, mutability) , _) => {
356360 // Check if it can work when put into a ref. For example:
357361 //
358362 // ```
@@ -407,65 +411,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
407411 } ) ;
408412 }
409413 }
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+ } => {
412418 // 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+ ) ) ;
462428 }
463429 }
430+ return None ;
464431 }
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`
469439 let deref_trait = self . tcx . lang_items ( ) . deref_trait ( ) . unwrap ( ) ;
470440 let item_def_id = self . tcx . associated_items ( deref_trait) . next ( ) . unwrap ( ) . def_id ;
471441 let predicate = ty:: Predicate :: Projection ( ty:: Binder :: bind ( ty:: ProjectionPredicate {
@@ -483,17 +453,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
483453 ty : expected,
484454 } ) ) ;
485455 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 {
489469 format ! ( "{}: *{}" , code, code)
490470 } else {
491471 format ! ( "*{}" , code)
492472 } ;
493- return Some ( ( sp, "consider dereferencing the type" , msg ) ) ;
473+ return Some ( ( sp, message , suggestion ) ) ;
494474 }
495475 }
496476 }
477+ _ => { }
497478 }
498479 None
499480 }
0 commit comments