@@ -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;
@@ -1008,6 +1008,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1008
1008
return ;
1009
1009
}
1010
1010
let self_ty = trait_ref. self_ty ( ) ;
1011
+ let found_ty = trait_ref. args . get ( 1 ) . and_then ( |a| a. as_type ( ) ) ;
1011
1012
1012
1013
let mut prev_ty = self . resolve_vars_if_possible (
1013
1014
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
@@ -1033,17 +1034,76 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1033
1034
1034
1035
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
1035
1036
let mut expr = expr;
1036
- while let hir:: ExprKind :: MethodCall ( _path_segment , rcvr_expr, _args , span) = expr. kind {
1037
+ while let hir:: ExprKind :: MethodCall ( path_segment , rcvr_expr, args , span) = expr. kind {
1037
1038
// Point at every method call in the chain with the `Result` type.
1038
1039
// let foo = bar.iter().map(mapper)?;
1039
1040
// ------ -----------
1040
1041
expr = rcvr_expr;
1041
1042
chain. push ( ( span, prev_ty) ) ;
1042
1043
1043
- prev_ty = self . resolve_vars_if_possible (
1044
+ let next_ty = self . resolve_vars_if_possible (
1044
1045
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1045
1046
) ;
1046
1047
1048
+ let is_diagnostic_item = |symbol : Symbol , ty : Ty < ' tcx > | {
1049
+ let ty:: Adt ( def, _) = ty. kind ( ) else {
1050
+ return false ;
1051
+ } ;
1052
+ self . tcx . is_diagnostic_item ( symbol, def. did ( ) )
1053
+ } ;
1054
+ // For each method in the chain, see if this is `Result::map_err` or
1055
+ // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect
1056
+ // trailing `;`.
1057
+ // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%
1058
+ // accurate check, but we are in the wrong stage to do that and looking for
1059
+ // `Result::map_err` by checking the Self type and the path segment is enough.
1060
+ // sym::ok_or_else
1061
+ if let Some ( ty) = get_e_type ( prev_ty)
1062
+ && let Some ( found_ty) = found_ty
1063
+ && (
1064
+ (
1065
+ path_segment. ident . name == sym:: map_err
1066
+ && is_diagnostic_item ( sym:: Result , next_ty)
1067
+ ) || (
1068
+ path_segment. ident . name == sym:: ok_or_else
1069
+ && is_diagnostic_item ( sym:: Option , next_ty)
1070
+ )
1071
+ )
1072
+ && [ sym:: map_err, sym:: ok_or_else] . contains ( & path_segment. ident . name )
1073
+ && let ty:: Tuple ( tys) = found_ty. kind ( )
1074
+ && tys. is_empty ( )
1075
+ && self . can_eq ( obligation. param_env , ty, found_ty)
1076
+ && args. len ( ) == 1
1077
+ && let Some ( arg) = args. get ( 0 )
1078
+ && let hir:: ExprKind :: Closure ( closure) = arg. kind
1079
+ && let body = self . tcx . hir ( ) . body ( closure. body )
1080
+ && let hir:: ExprKind :: Block ( block, _) = body. value . kind
1081
+ && let None = block. expr
1082
+ && let [ .., stmt] = block. stmts
1083
+ && let hir:: StmtKind :: Semi ( expr) = stmt. kind
1084
+ && let expr_ty = self . resolve_vars_if_possible (
1085
+ typeck. expr_ty_adjusted_opt ( expr)
1086
+ . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1087
+ )
1088
+ && self
1089
+ . infcx
1090
+ . type_implements_trait (
1091
+ self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1092
+ [ self_ty, expr_ty] ,
1093
+ obligation. param_env ,
1094
+ )
1095
+ . must_apply_modulo_regions ( )
1096
+ {
1097
+ err. span_suggestion_short (
1098
+ stmt. span . with_lo ( expr. span . hi ( ) ) ,
1099
+ "remove this semicolon" ,
1100
+ String :: new ( ) ,
1101
+ Applicability :: MachineApplicable ,
1102
+ ) ;
1103
+ }
1104
+
1105
+ prev_ty = next_ty;
1106
+
1047
1107
if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
1048
1108
&& let hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } = path
1049
1109
&& let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( * hir_id)
0 commit comments