@@ -566,7 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
566566 expr : & hir:: Expr < ' tcx > ,
567567 checked_ty : Ty < ' tcx > ,
568568 expected : Ty < ' tcx > ,
569- ) -> Option < ( Span , & ' static str , String , Applicability , bool /* verbose */ ) > {
569+ ) -> Option < ( Span , String , String , Applicability , bool /* verbose */ ) > {
570570 let sess = self . sess ( ) ;
571571 let sp = expr. span ;
572572
@@ -594,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
594594 let pos = sp. lo ( ) + BytePos ( 1 ) ;
595595 return Some ( (
596596 sp. with_hi ( pos) ,
597- "consider removing the leading `b`" ,
597+ "consider removing the leading `b`" . to_string ( ) ,
598598 String :: new ( ) ,
599599 Applicability :: MachineApplicable ,
600600 true ,
@@ -608,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
608608 {
609609 return Some ( (
610610 sp. shrink_to_lo ( ) ,
611- "consider adding a leading `b`" ,
611+ "consider adding a leading `b`" . to_string ( ) ,
612612 "b" . to_string ( ) ,
613613 Applicability :: MachineApplicable ,
614614 true ,
@@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
668668 if let Some ( sugg) = self . can_use_as_ref ( expr) {
669669 return Some ( (
670670 sugg. 0 ,
671- sugg. 1 ,
671+ sugg. 1 . to_string ( ) ,
672672 sugg. 2 ,
673673 Applicability :: MachineApplicable ,
674674 false ,
@@ -696,7 +696,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
696696 return Some ( (
697697 left_expr. span . shrink_to_lo ( ) ,
698698 "consider dereferencing here to assign to the mutable \
699- borrowed piece of memory",
699+ borrowed piece of memory"
700+ . to_string ( ) ,
700701 "*" . to_string ( ) ,
701702 Applicability :: MachineApplicable ,
702703 true ,
@@ -708,14 +709,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
708709 return Some ( match mutability {
709710 hir:: Mutability :: Mut => (
710711 sp,
711- "consider mutably borrowing here" ,
712+ "consider mutably borrowing here" . to_string ( ) ,
712713 format ! ( "{}&mut {}" , prefix, sugg_expr) ,
713714 Applicability :: MachineApplicable ,
714715 false ,
715716 ) ,
716717 hir:: Mutability :: Not => (
717718 sp,
718- "consider borrowing here" ,
719+ "consider borrowing here" . to_string ( ) ,
719720 format ! ( "{}&{}" , prefix, sugg_expr) ,
720721 Applicability :: MachineApplicable ,
721722 false ,
@@ -744,7 +745,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
744745 if sm. span_to_snippet ( call_span) . is_ok ( ) {
745746 return Some ( (
746747 sp. with_hi ( call_span. lo ( ) ) ,
747- "consider removing the borrow" ,
748+ "consider removing the borrow" . to_string ( ) ,
748749 String :: new ( ) ,
749750 Applicability :: MachineApplicable ,
750751 true ,
@@ -757,7 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
757758 if sm. span_to_snippet ( expr. span ) . is_ok ( ) {
758759 return Some ( (
759760 sp. with_hi ( expr. span . lo ( ) ) ,
760- "consider removing the borrow" ,
761+ "consider removing the borrow" . to_string ( ) ,
761762 String :: new ( ) ,
762763 Applicability :: MachineApplicable ,
763764 true ,
@@ -823,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
823824 } {
824825 return Some ( (
825826 span,
826- "consider dereferencing" ,
827+ "consider dereferencing" . to_string ( ) ,
827828 src,
828829 applicability,
829830 true ,
@@ -834,60 +835,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
834835 }
835836 }
836837 _ if sp == expr. span => {
837- if let Some ( steps) = self . deref_steps ( checked_ty, expected) {
838- let expr = expr. peel_blocks ( ) ;
838+ if let Some ( mut steps) = self . deref_steps ( checked_ty, expected) {
839+ let mut expr = expr. peel_blocks ( ) ;
840+ let mut prefix_span = expr. span . shrink_to_lo ( ) ;
841+ let mut remove = String :: new ( ) ;
839842
840- if steps == 1 {
843+ // Try peeling off any existing `&` and `&mut` to reach our target type
844+ while steps > 0 {
841845 if let hir:: ExprKind :: AddrOf ( _, mutbl, inner) = expr. kind {
842846 // If the expression has `&`, removing it would fix the error
843- let prefix_span = expr. span . with_hi ( inner. span . lo ( ) ) ;
844- let message = match mutbl {
845- hir:: Mutability :: Not => "consider removing the `&`" ,
846- hir:: Mutability :: Mut => "consider removing the `&mut`" ,
847+ prefix_span = prefix_span. with_hi ( inner. span . lo ( ) ) ;
848+ expr = inner;
849+ remove += match mutbl {
850+ hir:: Mutability :: Not => "&" ,
851+ hir:: Mutability :: Mut => "&mut " ,
847852 } ;
848- let suggestion = String :: new ( ) ;
849- return Some ( (
850- prefix_span,
851- message,
852- suggestion,
853- Applicability :: MachineApplicable ,
854- false ,
855- ) ) ;
853+ steps -= 1 ;
854+ } else {
855+ break ;
856856 }
857-
858- // For this suggestion to make sense, the type would need to be `Copy`,
859- // or we have to be moving out of a `Box<T>`
860- if self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp)
861- || checked_ty. is_box ( )
862- {
863- let message = if checked_ty. is_box ( ) {
864- "consider unboxing the value"
865- } else if checked_ty. is_region_ptr ( ) {
866- "consider dereferencing the borrow"
867- } else {
868- "consider dereferencing the type"
869- } ;
870- let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
871- Some ( ident) => format ! ( "{}: " , ident) ,
872- None => String :: new ( ) ,
873- } ;
874- let ( span, suggestion) = if self . is_else_if_block ( expr) {
875- // Don't suggest nonsense like `else *if`
876- return None ;
877- } else if let Some ( expr) = self . maybe_get_block_expr ( expr) {
878- // prefix should be empty here..
879- ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
857+ }
858+ // If we've reached our target type with just removing `&`, then just print now.
859+ if steps == 0 {
860+ return Some ( (
861+ prefix_span,
862+ format ! ( "consider removing the `{}`" , remove. trim( ) ) ,
863+ String :: new ( ) ,
864+ // Do not remove `&&` to get to bool, because it might be something like
865+ // { a } && b, which we have a separate fixup suggestion that is more
866+ // likely correct...
867+ if remove. trim ( ) == "&&" && expected == self . tcx . types . bool {
868+ Applicability :: MaybeIncorrect
880869 } else {
881- ( expr. span . shrink_to_lo ( ) , format ! ( "{}*" , prefix) )
882- } ;
883- return Some ( (
884- span,
885- message,
886- suggestion,
887- Applicability :: MachineApplicable ,
888- true ,
889- ) ) ;
890- }
870+ Applicability :: MachineApplicable
871+ } ,
872+ true ,
873+ ) ) ;
874+ }
875+
876+ // For this suggestion to make sense, the type would need to be `Copy`,
877+ // or we have to be moving out of a `Box<T>`
878+ if self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp)
879+ // FIXME(compiler-errors): We can actually do this if the checked_ty is
880+ // `steps` layers of boxes, not just one, but this is easier and most likely.
881+ || ( checked_ty. is_box ( ) && steps == 1 )
882+ {
883+ let deref_kind = if checked_ty. is_box ( ) {
884+ "unboxing the value"
885+ } else if checked_ty. is_region_ptr ( ) {
886+ "dereferencing the borrow"
887+ } else {
888+ "dereferencing the type"
889+ } ;
890+
891+ // Suggest removing `&` if we have removed any, otherwise suggest just
892+ // dereferencing the remaining number of steps.
893+ let message = if remove. is_empty ( ) {
894+ format ! ( "consider {}" , deref_kind)
895+ } else {
896+ format ! (
897+ "consider removing the `{}` and {} instead" ,
898+ remove. trim( ) ,
899+ deref_kind
900+ )
901+ } ;
902+
903+ let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
904+ Some ( ident) => format ! ( "{}: " , ident) ,
905+ None => String :: new ( ) ,
906+ } ;
907+
908+ let ( span, suggestion) = if self . is_else_if_block ( expr) {
909+ // Don't suggest nonsense like `else *if`
910+ return None ;
911+ } else if let Some ( expr) = self . maybe_get_block_expr ( expr) {
912+ // prefix should be empty here..
913+ ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
914+ } else {
915+ ( prefix_span, format ! ( "{}{}" , prefix, "*" . repeat( steps) ) )
916+ } ;
917+
918+ return Some ( (
919+ span,
920+ message,
921+ suggestion,
922+ Applicability :: MachineApplicable ,
923+ true ,
924+ ) ) ;
891925 }
892926 }
893927 }
0 commit comments