@@ -2,10 +2,14 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin
2
2
use clippy_utils:: source:: { snippet_opt, snippet_with_context} ;
3
3
use clippy_utils:: sugg:: has_enclosing_paren;
4
4
use clippy_utils:: visitors:: { for_each_expr_with_closures, Descend } ;
5
- use clippy_utils:: { fn_def_id, is_from_proc_macro, is_inside_let_else, path_to_local_id, span_find_starting_semi} ;
5
+ use clippy_utils:: {
6
+ fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id,
7
+ span_find_starting_semi,
8
+ } ;
6
9
use core:: ops:: ControlFlow ;
7
10
use rustc_errors:: Applicability ;
8
11
use rustc_hir:: intravisit:: FnKind ;
12
+ use rustc_hir:: LangItem :: ResultErr ;
9
13
use rustc_hir:: {
10
14
Block , Body , Expr , ExprKind , FnDecl , HirId , ItemKind , LangItem , MatchSource , Node , OwnerNode , PatKind , QPath , Stmt ,
11
15
StmtKind ,
@@ -176,37 +180,20 @@ fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
176
180
} )
177
181
}
178
182
179
- ///
180
- /// The expression of the desugared `try` operator is a match over an expression with type:
181
- /// `ControlFlow<A:Result<Infallible, E>, B:Result<_, E'>>`, with final type `B`.
182
- /// If E and E' are the same type, then there is no error conversion happening.
183
- /// Error conversion happens when E can be transformed into E' via a `From` or `Into` conversion.
184
- fn desugar_expr_performs_error_conversion ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
185
- let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
186
-
187
- if let ty:: Adt ( _, generics) = ty. kind ( )
188
- && let Some ( brk) = generics. first ( )
189
- && let Some ( cont) = generics. get ( 1 )
190
- && let Some ( brk_type) = brk. as_type ( )
191
- && let Some ( cont_type) = cont. as_type ( )
192
- && let ty:: Adt ( _, brk_generics) = brk_type. kind ( )
193
- && let ty:: Adt ( _, cont_generics) = cont_type. kind ( )
194
- && let Some ( brk_err) = brk_generics. get ( 1 )
195
- && let Some ( cont_err) = cont_generics. get ( 1 )
196
- && let Some ( brk_err_type) = brk_err. as_type ( )
197
- && let Some ( cont_err_type) = cont_err. as_type ( )
198
- {
199
- return brk_err_type != cont_err_type;
200
- }
201
- false
202
- }
203
-
204
183
impl < ' tcx > LateLintPass < ' tcx > for Return {
205
184
fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
206
185
if !in_external_macro ( cx. sess ( ) , stmt. span )
207
186
&& let StmtKind :: Semi ( expr) = stmt. kind
208
187
&& let ExprKind :: Ret ( Some ( ret) ) = expr. kind
209
- && let ExprKind :: Match ( match_expr, _, MatchSource :: TryDesugar ( ..) ) = ret. kind
188
+ // return Err(...)? desugars to a match
189
+ // over a Err(...).branch()
190
+ // which breaks down to a branch call, with the callee being
191
+ // the constructor of the Err variant
192
+ && let ExprKind :: Match ( maybe_cons, _, MatchSource :: TryDesugar ( _) ) = ret. kind
193
+ && let ExprKind :: Call ( _, [ maybe_result_err] ) = maybe_cons. kind
194
+ && let ExprKind :: Call ( maybe_constr, _) = maybe_result_err. kind
195
+ && is_res_lang_ctor ( cx, path_res ( cx, maybe_constr) , ResultErr )
196
+
210
197
// Ensure this is not the final stmt, otherwise removing it would cause a compile error
211
198
&& let OwnerNode :: Item ( item) = cx. tcx . hir ( ) . owner ( cx. tcx . hir ( ) . get_parent_item ( expr. hir_id ) )
212
199
&& let ItemKind :: Fn ( _, _, body) = item. kind
@@ -217,7 +204,6 @@ impl<'tcx> LateLintPass<'tcx> for Return {
217
204
&& final_stmt. hir_id != stmt. hir_id
218
205
&& !is_from_proc_macro ( cx, expr)
219
206
&& !stmt_needs_never_type ( cx, stmt. hir_id )
220
- && !desugar_expr_performs_error_conversion ( cx, match_expr)
221
207
{
222
208
span_lint_and_sugg (
223
209
cx,
0 commit comments