@@ -24,10 +24,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24
24
expr : & hir:: Expr < ' _ > ,
25
25
expr_ty : Ty < ' tcx > ,
26
26
expected : Ty < ' tcx > ,
27
+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
27
28
) {
28
29
self . annotate_expected_due_to_let_ty ( err, expr) ;
29
30
self . suggest_compatible_variants ( err, expr, expected, expr_ty) ;
30
- self . suggest_deref_ref_or_into ( err, expr, expected, expr_ty) ;
31
+ self . suggest_deref_ref_or_into ( err, expr, expected, expr_ty, expected_ty_expr ) ;
31
32
if self . suggest_calling_boxed_future_when_appropriate ( err, expr, expected, expr_ty) {
32
33
return ;
33
34
}
@@ -102,9 +103,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
102
103
expr : & hir:: Expr < ' _ > ,
103
104
checked_ty : Ty < ' tcx > ,
104
105
expected : Ty < ' tcx > ,
106
+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
105
107
allow_two_phase : AllowTwoPhase ,
106
108
) -> Ty < ' tcx > {
107
- let ( ty, err) = self . demand_coerce_diag ( expr, checked_ty, expected, allow_two_phase) ;
109
+ let ( ty, err) =
110
+ self . demand_coerce_diag ( expr, checked_ty, expected, expected_ty_expr, allow_two_phase) ;
108
111
if let Some ( mut err) = err {
109
112
err. emit ( ) ;
110
113
}
@@ -121,6 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
121
124
expr : & hir:: Expr < ' _ > ,
122
125
checked_ty : Ty < ' tcx > ,
123
126
expected : Ty < ' tcx > ,
127
+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
124
128
allow_two_phase : AllowTwoPhase ,
125
129
) -> ( Ty < ' tcx > , Option < DiagnosticBuilder < ' tcx > > ) {
126
130
let expected = self . resolve_vars_with_obligations ( expected) ;
@@ -141,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
141
145
return ( expected, None ) ;
142
146
}
143
147
144
- self . emit_coerce_suggestions ( & mut err, expr, expr_ty, expected) ;
148
+ self . emit_coerce_suggestions ( & mut err, expr, expr_ty, expected, expected_ty_expr ) ;
145
149
146
150
( expected, Some ( err) )
147
151
}
@@ -671,6 +675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
671
675
expr : & hir:: Expr < ' _ > ,
672
676
checked_ty : Ty < ' tcx > ,
673
677
expected_ty : Ty < ' tcx > ,
678
+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
674
679
) -> bool {
675
680
if self . tcx . sess . source_map ( ) . is_imported ( expr. span ) {
676
681
// Ignore if span is from within a macro.
@@ -747,7 +752,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
747
752
748
753
let msg = format ! ( "you can convert an `{}` to `{}`" , checked_ty, expected_ty) ;
749
754
let cast_msg = format ! ( "you can cast an `{} to `{}`" , checked_ty, expected_ty) ;
750
- let try_msg = format ! ( "{} and panic if the converted value wouldn't fit" , msg) ;
751
755
let lit_msg = format ! (
752
756
"change the type of the numeric literal from `{}` to `{}`" ,
753
757
checked_ty, expected_ty,
@@ -761,7 +765,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
761
765
} ;
762
766
763
767
let cast_suggestion = format ! ( "{}{} as {}" , prefix, with_opt_paren( & src) , expected_ty) ;
764
- let try_into_suggestion = format ! ( "{}{}.try_into().unwrap()" , prefix, with_opt_paren( & src) ) ;
765
768
let into_suggestion = format ! ( "{}{}.into()" , prefix, with_opt_paren( & src) ) ;
766
769
let suffix_suggestion = with_opt_paren ( & format_args ! (
767
770
"{}{}" ,
@@ -782,22 +785,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
782
785
} ;
783
786
784
787
let in_const_context = self . tcx . hir ( ) . is_inside_const_context ( expr. hir_id ) ;
788
+
789
+ let suggest_fallible_into_or_lhs_from =
790
+ |err : & mut DiagnosticBuilder < ' _ > , exp_to_found_is_fallible : bool | {
791
+ // If we know the expression the expected type is derived from, we might be able
792
+ // to suggest a widening conversion rather than a narrowing one (which may
793
+ // panic). For example, given x: u8 and y: u32, if we know the span of "x",
794
+ // x > y
795
+ // can be given the suggestion "u32::from(x) > y" rather than
796
+ // "x > y.try_into().unwrap()".
797
+ let lhs_expr_and_src = expected_ty_expr. and_then ( |expr| {
798
+ match self . tcx . sess . source_map ( ) . span_to_snippet ( expr. span ) . ok ( ) {
799
+ Some ( src) => Some ( ( expr, src) ) ,
800
+ None => None ,
801
+ }
802
+ } ) ;
803
+ let ( span, msg, suggestion) = if let ( Some ( ( lhs_expr, lhs_src) ) , false ) =
804
+ ( lhs_expr_and_src, exp_to_found_is_fallible)
805
+ {
806
+ let msg = format ! (
807
+ "you can convert `{}` from `{}` to `{}`, matching the type of `{}`" ,
808
+ lhs_src, expected_ty, checked_ty, src
809
+ ) ;
810
+ let suggestion = format ! ( "{}::from({})" , checked_ty, lhs_src, ) ;
811
+ ( lhs_expr. span , msg, suggestion)
812
+ } else {
813
+ let msg = format ! ( "{} and panic if the converted value wouldn't fit" , msg) ;
814
+ let suggestion =
815
+ format ! ( "{}{}.try_into().unwrap()" , prefix, with_opt_paren( & src) ) ;
816
+ ( expr. span , msg, suggestion)
817
+ } ;
818
+ err. span_suggestion ( span, & msg, suggestion, Applicability :: MachineApplicable ) ;
819
+ } ;
820
+
785
821
let suggest_to_change_suffix_or_into =
786
- |err : & mut DiagnosticBuilder < ' _ > , is_fallible : bool | {
822
+ |err : & mut DiagnosticBuilder < ' _ > ,
823
+ found_to_exp_is_fallible : bool ,
824
+ exp_to_found_is_fallible : bool | {
787
825
let msg = if literal_is_ty_suffixed ( expr) {
788
826
& lit_msg
789
827
} else if in_const_context {
790
828
// Do not recommend `into` or `try_into` in const contexts.
791
829
return ;
792
- } else if is_fallible {
793
- & try_msg
830
+ } else if found_to_exp_is_fallible {
831
+ return suggest_fallible_into_or_lhs_from ( err , exp_to_found_is_fallible ) ;
794
832
} else {
795
833
& msg
796
834
} ;
797
835
let suggestion = if literal_is_ty_suffixed ( expr) {
798
836
suffix_suggestion. clone ( )
799
- } else if is_fallible {
800
- try_into_suggestion
801
837
} else {
802
838
into_suggestion. clone ( )
803
839
} ;
@@ -806,41 +842,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
806
842
807
843
match ( & expected_ty. kind , & checked_ty. kind ) {
808
844
( & ty:: Int ( ref exp) , & ty:: Int ( ref found) ) => {
809
- let is_fallible = match ( exp. bit_width ( ) , found. bit_width ( ) ) {
810
- ( Some ( exp) , Some ( found) ) if exp < found => true ,
811
- ( None , Some ( 8 | 16 ) ) => false ,
812
- ( None , _) | ( _, None ) => true ,
813
- _ => false ,
845
+ let ( f2e_is_fallible, e2f_is_fallible) = match ( exp. bit_width ( ) , found. bit_width ( ) )
846
+ {
847
+ ( Some ( exp) , Some ( found) ) if exp < found => ( true , false ) ,
848
+ ( Some ( exp) , Some ( found) ) if exp > found => ( false , true ) ,
849
+ ( None , Some ( 8 | 16 ) ) => ( false , true ) ,
850
+ ( Some ( 8 | 16 ) , None ) => ( true , false ) ,
851
+ ( None , _) | ( _, None ) => ( true , true ) ,
852
+ _ => ( false , false ) ,
814
853
} ;
815
- suggest_to_change_suffix_or_into ( err, is_fallible ) ;
854
+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible , e2f_is_fallible ) ;
816
855
true
817
856
}
818
857
( & ty:: Uint ( ref exp) , & ty:: Uint ( ref found) ) => {
819
- let is_fallible = match ( exp. bit_width ( ) , found. bit_width ( ) ) {
820
- ( Some ( exp) , Some ( found) ) if exp < found => true ,
821
- ( None , Some ( 8 | 16 ) ) => false ,
822
- ( None , _) | ( _, None ) => true ,
823
- _ => false ,
858
+ let ( f2e_is_fallible, e2f_is_fallible) = match ( exp. bit_width ( ) , found. bit_width ( ) )
859
+ {
860
+ ( Some ( exp) , Some ( found) ) if exp < found => ( true , false ) ,
861
+ ( Some ( exp) , Some ( found) ) if exp > found => ( false , true ) ,
862
+ ( None , Some ( 8 | 16 ) ) => ( false , true ) ,
863
+ ( Some ( 8 | 16 ) , None ) => ( true , false ) ,
864
+ ( None , _) | ( _, None ) => ( true , true ) ,
865
+ _ => ( false , false ) ,
824
866
} ;
825
- suggest_to_change_suffix_or_into ( err, is_fallible ) ;
867
+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible , e2f_is_fallible ) ;
826
868
true
827
869
}
828
870
( & ty:: Int ( exp) , & ty:: Uint ( found) ) => {
829
- let is_fallible = match ( exp. bit_width ( ) , found. bit_width ( ) ) {
830
- ( Some ( exp) , Some ( found) ) if found < exp => false ,
831
- ( None , Some ( 8 ) ) => false ,
832
- _ => true ,
871
+ let ( f2e_is_fallible, e2f_is_fallible) = match ( exp. bit_width ( ) , found. bit_width ( ) )
872
+ {
873
+ ( Some ( exp) , Some ( found) ) if found < exp => ( false , true ) ,
874
+ ( None , Some ( 8 ) ) => ( false , true ) ,
875
+ _ => ( true , true ) ,
833
876
} ;
834
- suggest_to_change_suffix_or_into ( err, is_fallible ) ;
877
+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible , e2f_is_fallible ) ;
835
878
true
836
879
}
837
- ( & ty:: Uint ( _) , & ty:: Int ( _) ) => {
838
- suggest_to_change_suffix_or_into ( err, true ) ;
880
+ ( & ty:: Uint ( exp) , & ty:: Int ( found) ) => {
881
+ let ( f2e_is_fallible, e2f_is_fallible) = match ( exp. bit_width ( ) , found. bit_width ( ) )
882
+ {
883
+ ( Some ( exp) , Some ( found) ) if found > exp => ( true , false ) ,
884
+ ( Some ( 8 ) , None ) => ( true , false ) ,
885
+ _ => ( true , true ) ,
886
+ } ;
887
+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible, e2f_is_fallible) ;
839
888
true
840
889
}
841
890
( & ty:: Float ( ref exp) , & ty:: Float ( ref found) ) => {
842
891
if found. bit_width ( ) < exp. bit_width ( ) {
843
- suggest_to_change_suffix_or_into ( err, false ) ;
892
+ suggest_to_change_suffix_or_into ( err, false , true ) ;
844
893
} else if literal_is_ty_suffixed ( expr) {
845
894
err. span_suggestion (
846
895
expr. span ,
0 commit comments