@@ -566,7 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
566
566
expr : & hir:: Expr < ' tcx > ,
567
567
checked_ty : Ty < ' tcx > ,
568
568
expected : Ty < ' tcx > ,
569
- ) -> Option < ( Span , & ' static str , String , Applicability , bool /* verbose */ ) > {
569
+ ) -> Option < ( Span , String , String , Applicability , bool /* verbose */ ) > {
570
570
let sess = self . sess ( ) ;
571
571
let sp = expr. span ;
572
572
@@ -593,7 +593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
593
593
let pos = sp. lo ( ) + BytePos ( 1 ) ;
594
594
return Some ( (
595
595
sp. with_hi ( pos) ,
596
- "consider removing the leading `b`" ,
596
+ "consider removing the leading `b`" . to_string ( ) ,
597
597
String :: new ( ) ,
598
598
Applicability :: MachineApplicable ,
599
599
true ,
@@ -608,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
608
608
if replace_prefix ( & src, "\" " , "b\" " ) . is_some ( ) {
609
609
return Some ( (
610
610
sp. shrink_to_lo ( ) ,
611
- "consider adding a leading `b`" ,
611
+ "consider adding a leading `b`" . to_string ( ) ,
612
612
"b" . to_string ( ) ,
613
613
Applicability :: MachineApplicable ,
614
614
true ,
@@ -669,7 +669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
669
669
if let Some ( sugg) = self . can_use_as_ref ( expr) {
670
670
return Some ( (
671
671
sugg. 0 ,
672
- sugg. 1 ,
672
+ sugg. 1 . to_string ( ) ,
673
673
sugg. 2 ,
674
674
Applicability :: MachineApplicable ,
675
675
false ,
@@ -697,7 +697,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
697
697
return Some ( (
698
698
left_expr. span . shrink_to_lo ( ) ,
699
699
"consider dereferencing here to assign to the mutable \
700
- borrowed piece of memory",
700
+ borrowed piece of memory"
701
+ . to_string ( ) ,
701
702
"*" . to_string ( ) ,
702
703
Applicability :: MachineApplicable ,
703
704
true ,
@@ -709,14 +710,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
709
710
return Some ( match mutability {
710
711
hir:: Mutability :: Mut => (
711
712
sp,
712
- "consider mutably borrowing here" ,
713
+ "consider mutably borrowing here" . to_string ( ) ,
713
714
format ! ( "{}&mut {}" , prefix, sugg_expr) ,
714
715
Applicability :: MachineApplicable ,
715
716
false ,
716
717
) ,
717
718
hir:: Mutability :: Not => (
718
719
sp,
719
- "consider borrowing here" ,
720
+ "consider borrowing here" . to_string ( ) ,
720
721
format ! ( "{}&{}" , prefix, sugg_expr) ,
721
722
Applicability :: MachineApplicable ,
722
723
false ,
@@ -745,7 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
745
746
if sm. span_to_snippet ( call_span) . is_ok ( ) {
746
747
return Some ( (
747
748
sp. with_hi ( call_span. lo ( ) ) ,
748
- "consider removing the borrow" ,
749
+ "consider removing the borrow" . to_string ( ) ,
749
750
String :: new ( ) ,
750
751
Applicability :: MachineApplicable ,
751
752
true ,
@@ -758,7 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
758
759
if sm. span_to_snippet ( expr. span ) . is_ok ( ) {
759
760
return Some ( (
760
761
sp. with_hi ( expr. span . lo ( ) ) ,
761
- "consider removing the borrow" ,
762
+ "consider removing the borrow" . to_string ( ) ,
762
763
String :: new ( ) ,
763
764
Applicability :: MachineApplicable ,
764
765
true ,
@@ -824,7 +825,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
824
825
} {
825
826
return Some ( (
826
827
span,
827
- "consider dereferencing" ,
828
+ "consider dereferencing" . to_string ( ) ,
828
829
src,
829
830
applicability,
830
831
true ,
@@ -835,60 +836,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
835
836
}
836
837
}
837
838
_ 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 ( ) ;
840
843
841
- if steps == 1 {
844
+ // Try peeling off any existing `&` and `&mut` to reach our target type
845
+ while steps > 0 {
842
846
if let hir:: ExprKind :: AddrOf ( _, mutbl, inner) = expr. kind {
843
847
// 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 " ,
848
853
} ;
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 ;
857
857
}
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
881
870
} 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
+ ) ) ;
892
926
}
893
927
}
894
928
}
0 commit comments