@@ -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
@@ -593,7 +593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
593593 let pos = sp. lo ( ) + BytePos ( 1 ) ;
594594 return Some ( (
595595 sp. with_hi ( pos) ,
596- "consider removing the leading `b`" ,
596+ "consider removing the leading `b`" . to_string ( ) ,
597597 String :: new ( ) ,
598598 Applicability :: MachineApplicable ,
599599 true ,
@@ -608,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
608608 if replace_prefix ( & src, "\" " , "b\" " ) . is_some ( ) {
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 ,
@@ -669,7 +669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
669669 if let Some ( sugg) = self . can_use_as_ref ( expr) {
670670 return Some ( (
671671 sugg. 0 ,
672- sugg. 1 ,
672+ sugg. 1 . to_string ( ) ,
673673 sugg. 2 ,
674674 Applicability :: MachineApplicable ,
675675 false ,
@@ -697,7 +697,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
697697 return Some ( (
698698 left_expr. span . shrink_to_lo ( ) ,
699699 "consider dereferencing here to assign to the mutable \
700- borrowed piece of memory",
700+ borrowed piece of memory"
701+ . to_string ( ) ,
701702 "*" . to_string ( ) ,
702703 Applicability :: MachineApplicable ,
703704 true ,
@@ -709,14 +710,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
709710 return Some ( match mutability {
710711 hir:: Mutability :: Mut => (
711712 sp,
712- "consider mutably borrowing here" ,
713+ "consider mutably borrowing here" . to_string ( ) ,
713714 format ! ( "{}&mut {}" , prefix, sugg_expr) ,
714715 Applicability :: MachineApplicable ,
715716 false ,
716717 ) ,
717718 hir:: Mutability :: Not => (
718719 sp,
719- "consider borrowing here" ,
720+ "consider borrowing here" . to_string ( ) ,
720721 format ! ( "{}&{}" , prefix, sugg_expr) ,
721722 Applicability :: MachineApplicable ,
722723 false ,
@@ -745,7 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
745746 if sm. span_to_snippet ( call_span) . is_ok ( ) {
746747 return Some ( (
747748 sp. with_hi ( call_span. lo ( ) ) ,
748- "consider removing the borrow" ,
749+ "consider removing the borrow" . to_string ( ) ,
749750 String :: new ( ) ,
750751 Applicability :: MachineApplicable ,
751752 true ,
@@ -758,7 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
758759 if sm. span_to_snippet ( expr. span ) . is_ok ( ) {
759760 return Some ( (
760761 sp. with_hi ( expr. span . lo ( ) ) ,
761- "consider removing the borrow" ,
762+ "consider removing the borrow" . to_string ( ) ,
762763 String :: new ( ) ,
763764 Applicability :: MachineApplicable ,
764765 true ,
@@ -824,7 +825,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
824825 } {
825826 return Some ( (
826827 span,
827- "consider dereferencing" ,
828+ "consider dereferencing" . to_string ( ) ,
828829 src,
829830 applicability,
830831 true ,
@@ -835,60 +836,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
835836 }
836837 }
837838 _ if sp == expr. span => {
838- if let Some ( steps) = self . deref_steps ( checked_ty, expected) {
839- let expr = expr. peel_blocks ( ) ;
839+ if let Some ( mut steps) = self . deref_steps ( checked_ty, expected) {
840+ let mut expr = expr. peel_blocks ( ) ;
841+ let mut prefix_span = expr. span . shrink_to_lo ( ) ;
842+ let mut remove = String :: new ( ) ;
840843
841- if steps == 1 {
844+ // Try peeling off any existing `&` and `&mut` to reach our target type
845+ while steps > 0 {
842846 if let hir:: ExprKind :: AddrOf ( _, mutbl, inner) = expr. kind {
843847 // If the expression has `&`, removing it would fix the error
844- let prefix_span = expr. span . with_hi ( inner. span . lo ( ) ) ;
845- let message = match mutbl {
846- hir:: Mutability :: Not => "consider removing the `&`" ,
847- hir:: Mutability :: Mut => "consider removing the `&mut`" ,
848+ prefix_span = prefix_span. with_hi ( inner. span . lo ( ) ) ;
849+ expr = inner;
850+ remove += match mutbl {
851+ hir:: Mutability :: Not => "&" ,
852+ hir:: Mutability :: Mut => "&mut " ,
848853 } ;
849- let suggestion = String :: new ( ) ;
850- return Some ( (
851- prefix_span,
852- message,
853- suggestion,
854- Applicability :: MachineApplicable ,
855- false ,
856- ) ) ;
854+ steps -= 1 ;
855+ } else {
856+ break ;
857857 }
858-
859- // For this suggestion to make sense, the type would need to be `Copy`,
860- // or we have to be moving out of a `Box<T>`
861- if self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp)
862- || checked_ty. is_box ( )
863- {
864- let message = if checked_ty. is_box ( ) {
865- "consider unboxing the value"
866- } else if checked_ty. is_region_ptr ( ) {
867- "consider dereferencing the borrow"
868- } else {
869- "consider dereferencing the type"
870- } ;
871- let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
872- Some ( ident) => format ! ( "{}: " , ident) ,
873- None => String :: new ( ) ,
874- } ;
875- let ( span, suggestion) = if self . is_else_if_block ( expr) {
876- // Don't suggest nonsense like `else *if`
877- return None ;
878- } else if let Some ( expr) = self . maybe_get_block_expr ( expr) {
879- // prefix should be empty here..
880- ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
858+ }
859+ // If we've reached our target type with just removing `&`, then just print now.
860+ if steps == 0 {
861+ return Some ( (
862+ prefix_span,
863+ format ! ( "consider removing the `{}`" , remove. trim( ) ) ,
864+ String :: new ( ) ,
865+ // Do not remove `&&` to get to bool, because it might be something like
866+ // { a } && b, which we have a separate fixup suggestion that is more
867+ // likely correct...
868+ if remove. trim ( ) == "&&" && expected == self . tcx . types . bool {
869+ Applicability :: MaybeIncorrect
881870 } else {
882- ( expr. span . shrink_to_lo ( ) , format ! ( "{}*" , prefix) )
883- } ;
884- return Some ( (
885- span,
886- message,
887- suggestion,
888- Applicability :: MachineApplicable ,
889- true ,
890- ) ) ;
891- }
871+ Applicability :: MachineApplicable
872+ } ,
873+ true ,
874+ ) ) ;
875+ }
876+
877+ // For this suggestion to make sense, the type would need to be `Copy`,
878+ // or we have to be moving out of a `Box<T>`
879+ if self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp)
880+ // FIXME(compiler-errors): We can actually do this if the checked_ty is
881+ // `steps` layers of boxes, not just one, but this is easier and most likely.
882+ || ( checked_ty. is_box ( ) && steps == 1 )
883+ {
884+ let deref_kind = if checked_ty. is_box ( ) {
885+ "unboxing the value"
886+ } else if checked_ty. is_region_ptr ( ) {
887+ "dereferencing the borrow"
888+ } else {
889+ "dereferencing the type"
890+ } ;
891+
892+ // Suggest removing `&` if we have removed any, otherwise suggest just
893+ // dereferencing the remaining number of steps.
894+ let message = if remove. is_empty ( ) {
895+ format ! ( "consider {}" , deref_kind)
896+ } else {
897+ format ! (
898+ "consider removing the `{}` and {} instead" ,
899+ remove. trim( ) ,
900+ deref_kind
901+ )
902+ } ;
903+
904+ let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
905+ Some ( ident) => format ! ( "{}: " , ident) ,
906+ None => String :: new ( ) ,
907+ } ;
908+
909+ let ( span, suggestion) = if self . is_else_if_block ( expr) {
910+ // Don't suggest nonsense like `else *if`
911+ return None ;
912+ } else if let Some ( expr) = self . maybe_get_block_expr ( expr) {
913+ // prefix should be empty here..
914+ ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
915+ } else {
916+ ( prefix_span, format ! ( "{}{}" , prefix, "*" . repeat( steps) ) )
917+ } ;
918+
919+ return Some ( (
920+ span,
921+ message,
922+ suggestion,
923+ Applicability :: MachineApplicable ,
924+ true ,
925+ ) ) ;
892926 }
893927 }
894928 }
0 commit comments