@@ -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
@@ -594,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
594
594
let pos = sp. lo ( ) + BytePos ( 1 ) ;
595
595
return Some ( (
596
596
sp. with_hi ( pos) ,
597
- "consider removing the leading `b`" ,
597
+ "consider removing the leading `b`" . to_string ( ) ,
598
598
String :: new ( ) ,
599
599
Applicability :: MachineApplicable ,
600
600
true ,
@@ -608,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
608
608
{
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 ,
@@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
668
668
if let Some ( sugg) = self . can_use_as_ref ( expr) {
669
669
return Some ( (
670
670
sugg. 0 ,
671
- sugg. 1 ,
671
+ sugg. 1 . to_string ( ) ,
672
672
sugg. 2 ,
673
673
Applicability :: MachineApplicable ,
674
674
false ,
@@ -696,7 +696,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
696
696
return Some ( (
697
697
left_expr. span . shrink_to_lo ( ) ,
698
698
"consider dereferencing here to assign to the mutable \
699
- borrowed piece of memory",
699
+ borrowed piece of memory"
700
+ . to_string ( ) ,
700
701
"*" . to_string ( ) ,
701
702
Applicability :: MachineApplicable ,
702
703
true ,
@@ -708,14 +709,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
708
709
return Some ( match mutability {
709
710
hir:: Mutability :: Mut => (
710
711
sp,
711
- "consider mutably borrowing here" ,
712
+ "consider mutably borrowing here" . to_string ( ) ,
712
713
format ! ( "{}&mut {}" , prefix, sugg_expr) ,
713
714
Applicability :: MachineApplicable ,
714
715
false ,
715
716
) ,
716
717
hir:: Mutability :: Not => (
717
718
sp,
718
- "consider borrowing here" ,
719
+ "consider borrowing here" . to_string ( ) ,
719
720
format ! ( "{}&{}" , prefix, sugg_expr) ,
720
721
Applicability :: MachineApplicable ,
721
722
false ,
@@ -744,7 +745,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
744
745
if sm. span_to_snippet ( call_span) . is_ok ( ) {
745
746
return Some ( (
746
747
sp. with_hi ( call_span. lo ( ) ) ,
747
- "consider removing the borrow" ,
748
+ "consider removing the borrow" . to_string ( ) ,
748
749
String :: new ( ) ,
749
750
Applicability :: MachineApplicable ,
750
751
true ,
@@ -757,7 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
757
758
if sm. span_to_snippet ( expr. span ) . is_ok ( ) {
758
759
return Some ( (
759
760
sp. with_hi ( expr. span . lo ( ) ) ,
760
- "consider removing the borrow" ,
761
+ "consider removing the borrow" . to_string ( ) ,
761
762
String :: new ( ) ,
762
763
Applicability :: MachineApplicable ,
763
764
true ,
@@ -823,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
823
824
} {
824
825
return Some ( (
825
826
span,
826
- "consider dereferencing" ,
827
+ "consider dereferencing" . to_string ( ) ,
827
828
src,
828
829
applicability,
829
830
true ,
@@ -834,60 +835,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
834
835
}
835
836
}
836
837
_ 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 ( ) ;
839
842
840
- if steps == 1 {
843
+ // Try peeling off any existing `&` and `&mut` to reach our target type
844
+ while steps > 0 {
841
845
if let hir:: ExprKind :: AddrOf ( _, mutbl, inner) = expr. kind {
842
846
// 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 " ,
847
852
} ;
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 ;
856
856
}
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
880
869
} 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
+ ) ) ;
891
925
}
892
926
}
893
927
}
0 commit comments