@@ -24,10 +24,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2424 expr : & hir:: Expr < ' _ > ,
2525 expr_ty : Ty < ' tcx > ,
2626 expected : Ty < ' tcx > ,
27+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
2728 ) {
2829 self . annotate_expected_due_to_let_ty ( err, expr) ;
2930 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 ) ;
3132 if self . suggest_calling_boxed_future_when_appropriate ( err, expr, expected, expr_ty) {
3233 return ;
3334 }
@@ -102,9 +103,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
102103 expr : & hir:: Expr < ' _ > ,
103104 checked_ty : Ty < ' tcx > ,
104105 expected : Ty < ' tcx > ,
106+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
105107 allow_two_phase : AllowTwoPhase ,
106108 ) -> 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) ;
108111 if let Some ( mut err) = err {
109112 err. emit ( ) ;
110113 }
@@ -121,6 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
121124 expr : & hir:: Expr < ' _ > ,
122125 checked_ty : Ty < ' tcx > ,
123126 expected : Ty < ' tcx > ,
127+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
124128 allow_two_phase : AllowTwoPhase ,
125129 ) -> ( Ty < ' tcx > , Option < DiagnosticBuilder < ' tcx > > ) {
126130 let expected = self . resolve_vars_with_obligations ( expected) ;
@@ -141,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
141145 return ( expected, None ) ;
142146 }
143147
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 ) ;
145149
146150 ( expected, Some ( err) )
147151 }
@@ -671,6 +675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
671675 expr : & hir:: Expr < ' _ > ,
672676 checked_ty : Ty < ' tcx > ,
673677 expected_ty : Ty < ' tcx > ,
678+ expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
674679 ) -> bool {
675680 if self . tcx . sess . source_map ( ) . is_imported ( expr. span ) {
676681 // Ignore if span is from within a macro.
@@ -747,7 +752,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
747752
748753 let msg = format ! ( "you can convert an `{}` to `{}`" , checked_ty, expected_ty) ;
749754 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) ;
751755 let lit_msg = format ! (
752756 "change the type of the numeric literal from `{}` to `{}`" ,
753757 checked_ty, expected_ty,
@@ -761,7 +765,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
761765 } ;
762766
763767 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) ) ;
765768 let into_suggestion = format ! ( "{}{}.into()" , prefix, with_opt_paren( & src) ) ;
766769 let suffix_suggestion = with_opt_paren ( & format_args ! (
767770 "{}{}" ,
@@ -782,22 +785,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
782785 } ;
783786
784787 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+
785821 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 | {
787825 let msg = if literal_is_ty_suffixed ( expr) {
788826 & lit_msg
789827 } else if in_const_context {
790828 // Do not recommend `into` or `try_into` in const contexts.
791829 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 ) ;
794832 } else {
795833 & msg
796834 } ;
797835 let suggestion = if literal_is_ty_suffixed ( expr) {
798836 suffix_suggestion. clone ( )
799- } else if is_fallible {
800- try_into_suggestion
801837 } else {
802838 into_suggestion. clone ( )
803839 } ;
@@ -806,41 +842,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
806842
807843 match ( & expected_ty. kind , & checked_ty. kind ) {
808844 ( & 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 ) ,
814853 } ;
815- suggest_to_change_suffix_or_into ( err, is_fallible ) ;
854+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible , e2f_is_fallible ) ;
816855 true
817856 }
818857 ( & 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 ) ,
824866 } ;
825- suggest_to_change_suffix_or_into ( err, is_fallible ) ;
867+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible , e2f_is_fallible ) ;
826868 true
827869 }
828870 ( & 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 ) ,
833876 } ;
834- suggest_to_change_suffix_or_into ( err, is_fallible ) ;
877+ suggest_to_change_suffix_or_into ( err, f2e_is_fallible , e2f_is_fallible ) ;
835878 true
836879 }
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) ;
839888 true
840889 }
841890 ( & ty:: Float ( ref exp) , & ty:: Float ( ref found) ) => {
842891 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 ) ;
844893 } else if literal_is_ty_suffixed ( expr) {
845894 err. span_suggestion (
846895 expr. span ,
0 commit comments