@@ -41,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver};
4141use rustc_session:: Limit ;
4242use rustc_span:: def_id:: LOCAL_CRATE ;
4343use rustc_span:: symbol:: sym;
44- use rustc_span:: { BytePos , ExpnKind , Span , DUMMY_SP } ;
44+ use rustc_span:: { BytePos , ExpnKind , Span , Symbol , DUMMY_SP } ;
4545use std:: borrow:: Cow ;
4646use std:: fmt;
4747use std:: iter;
@@ -1045,6 +1045,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
10451045 return ;
10461046 }
10471047 let self_ty = trait_ref. self_ty ( ) ;
1048+ let found_ty = trait_ref. args . get ( 1 ) . and_then ( |a| a. as_type ( ) ) ;
10481049
10491050 let mut prev_ty = self . resolve_vars_if_possible (
10501051 typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
@@ -1070,17 +1071,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
10701071
10711072 // The following logic is simlar to `point_at_chain`, but that's focused on associated types
10721073 let mut expr = expr;
1073- while let hir:: ExprKind :: MethodCall ( _path_segment , rcvr_expr, _args , span) = expr. kind {
1074+ while let hir:: ExprKind :: MethodCall ( path_segment , rcvr_expr, args , span) = expr. kind {
10741075 // Point at every method call in the chain with the `Result` type.
10751076 // let foo = bar.iter().map(mapper)?;
10761077 // ------ -----------
10771078 expr = rcvr_expr;
10781079 chain. push ( ( span, prev_ty) ) ;
10791080
1080- prev_ty = self . resolve_vars_if_possible (
1081+ let next_ty = self . resolve_vars_if_possible (
10811082 typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
10821083 ) ;
10831084
1085+ let is_diagnostic_item = |symbol : Symbol , ty : Ty < ' tcx > | {
1086+ let ty:: Adt ( def, _) = ty. kind ( ) else {
1087+ return false ;
1088+ } ;
1089+ self . tcx . is_diagnostic_item ( symbol, def. did ( ) )
1090+ } ;
1091+ // For each method in the chain, see if this is `Result::map_err` or
1092+ // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect
1093+ // trailing `;`.
1094+ if let Some ( ty) = get_e_type ( prev_ty)
1095+ && let Some ( found_ty) = found_ty
1096+ // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%
1097+ // accurate check, but we are in the wrong stage to do that and looking for
1098+ // `Result::map_err` by checking the Self type and the path segment is enough.
1099+ // sym::ok_or_else
1100+ && (
1101+ ( // Result::map_err
1102+ path_segment. ident . name == sym:: map_err
1103+ && is_diagnostic_item ( sym:: Result , next_ty)
1104+ ) || ( // Option::ok_or_else
1105+ path_segment. ident . name == sym:: ok_or_else
1106+ && is_diagnostic_item ( sym:: Option , next_ty)
1107+ )
1108+ )
1109+ // Found `Result<_, ()>?`
1110+ && let ty:: Tuple ( tys) = found_ty. kind ( )
1111+ && tys. is_empty ( )
1112+ // The current method call returns `Result<_, ()>`
1113+ && self . can_eq ( obligation. param_env , ty, found_ty)
1114+ // There's a single argument in the method call and it is a closure
1115+ && args. len ( ) == 1
1116+ && let Some ( arg) = args. get ( 0 )
1117+ && let hir:: ExprKind :: Closure ( closure) = arg. kind
1118+ // The closure has a block for its body with no tail expression
1119+ && let body = self . tcx . hir ( ) . body ( closure. body )
1120+ && let hir:: ExprKind :: Block ( block, _) = body. value . kind
1121+ && let None = block. expr
1122+ // The last statement is of a type that can be converted to the return error type
1123+ && let [ .., stmt] = block. stmts
1124+ && let hir:: StmtKind :: Semi ( expr) = stmt. kind
1125+ && let expr_ty = self . resolve_vars_if_possible (
1126+ typeck. expr_ty_adjusted_opt ( expr)
1127+ . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1128+ )
1129+ && self
1130+ . infcx
1131+ . type_implements_trait (
1132+ self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1133+ [ self_ty, expr_ty] ,
1134+ obligation. param_env ,
1135+ )
1136+ . must_apply_modulo_regions ( )
1137+ {
1138+ err. span_suggestion_short (
1139+ stmt. span . with_lo ( expr. span . hi ( ) ) ,
1140+ "remove this semicolon" ,
1141+ String :: new ( ) ,
1142+ Applicability :: MachineApplicable ,
1143+ ) ;
1144+ }
1145+
1146+ prev_ty = next_ty;
1147+
10841148 if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
10851149 && let hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } = path
10861150 && let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( * hir_id)
0 commit comments