@@ -41,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver};
41
41
use rustc_session:: Limit ;
42
42
use rustc_span:: def_id:: LOCAL_CRATE ;
43
43
use rustc_span:: symbol:: sym;
44
- use rustc_span:: { BytePos , ExpnKind , Span , DUMMY_SP } ;
44
+ use rustc_span:: { BytePos , ExpnKind , Span , Symbol , DUMMY_SP } ;
45
45
use std:: borrow:: Cow ;
46
46
use std:: fmt;
47
47
use std:: iter;
@@ -1045,6 +1045,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1045
1045
return ;
1046
1046
}
1047
1047
let self_ty = trait_ref. self_ty ( ) ;
1048
+ let found_ty = trait_ref. args . get ( 1 ) . and_then ( |a| a. as_type ( ) ) ;
1048
1049
1049
1050
let mut prev_ty = self . resolve_vars_if_possible (
1050
1051
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> {
1070
1071
1071
1072
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
1072
1073
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 {
1074
1075
// Point at every method call in the chain with the `Result` type.
1075
1076
// let foo = bar.iter().map(mapper)?;
1076
1077
// ------ -----------
1077
1078
expr = rcvr_expr;
1078
1079
chain. push ( ( span, prev_ty) ) ;
1079
1080
1080
- prev_ty = self . resolve_vars_if_possible (
1081
+ let next_ty = self . resolve_vars_if_possible (
1081
1082
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1082
1083
) ;
1083
1084
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
+
1084
1148
if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
1085
1149
&& let hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } = path
1086
1150
&& let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( * hir_id)
0 commit comments