@@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5858 || self . suggest_into ( err, expr, expr_ty, expected)
5959 || self . suggest_floating_point_literal ( err, expr, expected)
6060 || 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) ;
6263
6364 if !suggested {
6465 self . note_source_of_type_mismatch_constraint (
@@ -954,6 +955,85 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
954955 ) ;
955956 }
956957
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+
9571037 pub ( crate ) fn suggest_coercing_result_via_try_operator (
9581038 & self ,
9591039 err : & mut Diagnostic ,
0 commit comments