@@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
58
58
|| self . suggest_into ( err, expr, expr_ty, expected)
59
59
|| self . suggest_floating_point_literal ( err, expr, expected)
60
60
|| self . suggest_null_ptr_for_literal_zero_given_to_ptr_arg ( err, expr, expected)
61
- || self . suggest_coercing_result_via_try_operator ( err, expr, expected, expr_ty) ;
61
+ || self . suggest_coercing_result_via_try_operator ( err, expr, expected, expr_ty)
62
+ || self . suggest_missing_unwrap_expect ( err, expr, expected, expr_ty) ;
62
63
63
64
if !suggested {
64
65
self . note_source_of_type_mismatch_constraint (
@@ -954,6 +955,85 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
954
955
) ;
955
956
}
956
957
958
+ pub ( crate ) fn suggest_missing_unwrap_expect (
959
+ & self ,
960
+ err : & mut Diagnostic ,
961
+ expr : & hir:: Expr < ' tcx > ,
962
+ expected : Ty < ' tcx > ,
963
+ found : Ty < ' tcx > ,
964
+ ) -> bool {
965
+ let ty:: Adt ( adt, args) = found. kind ( ) else { return false } ;
966
+ let ret_ty_matches = |diagnostic_item| {
967
+ if let Some ( ret_ty) = self
968
+ . ret_coercion
969
+ . as_ref ( )
970
+ . map ( |c| self . resolve_vars_if_possible ( c. borrow ( ) . expected_ty ( ) ) )
971
+ && let ty:: Adt ( kind, _) = ret_ty. kind ( )
972
+ && self . tcx . get_diagnostic_item ( diagnostic_item) == Some ( kind. did ( ) )
973
+ {
974
+ true
975
+ } else {
976
+ false
977
+ }
978
+ } ;
979
+
980
+ // don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
981
+ // `None.unwrap()` etc.
982
+ let is_ctor = matches ! (
983
+ expr. kind,
984
+ hir:: ExprKind :: Call (
985
+ hir:: Expr {
986
+ kind: hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
987
+ None ,
988
+ hir:: Path { res: Res :: Def ( hir:: def:: DefKind :: Ctor ( _, _) , _) , .. } ,
989
+ ) ) ,
990
+ ..
991
+ } ,
992
+ ..,
993
+ ) | hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
994
+ None ,
995
+ hir:: Path { res: Res :: Def ( hir:: def:: DefKind :: Ctor ( _, _) , _) , .. } ,
996
+ ) ) ,
997
+ ) ;
998
+
999
+ let ( article, kind, variant, sugg_operator) =
1000
+ if self . tcx . is_diagnostic_item ( sym:: Result , adt. did ( ) ) {
1001
+ ( "a" , "Result" , "Err" , ret_ty_matches ( sym:: Result ) )
1002
+ } else if self . tcx . is_diagnostic_item ( sym:: Option , adt. did ( ) ) {
1003
+ ( "an" , "Option" , "None" , ret_ty_matches ( sym:: Option ) )
1004
+ } else {
1005
+ return false ;
1006
+ } ;
1007
+ if is_ctor || !self . can_coerce ( args. type_at ( 0 ) , expected) {
1008
+ return false ;
1009
+ }
1010
+
1011
+ let ( msg, sugg) = if sugg_operator {
1012
+ (
1013
+ format ! (
1014
+ "use the `?` operator to extract the `{found}` value, propagating \
1015
+ {article} `{kind}::{variant}` value to the caller"
1016
+ ) ,
1017
+ "?" ,
1018
+ )
1019
+ } else {
1020
+ (
1021
+ format ! (
1022
+ "consider using `{kind}::expect` to unwrap the `{found}` value, \
1023
+ panicking if the value is {article} `{kind}::{variant}`"
1024
+ ) ,
1025
+ ".expect(\" REASON\" )" ,
1026
+ )
1027
+ } ;
1028
+ err. span_suggestion_verbose (
1029
+ expr. span . shrink_to_hi ( ) ,
1030
+ msg,
1031
+ sugg,
1032
+ Applicability :: HasPlaceholders ,
1033
+ ) ;
1034
+ return true ;
1035
+ }
1036
+
957
1037
pub ( crate ) fn suggest_coercing_result_via_try_operator (
958
1038
& self ,
959
1039
err : & mut Diagnostic ,
0 commit comments