@@ -2,10 +2,14 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin
22use clippy_utils:: source:: { snippet_opt, snippet_with_context} ;
33use clippy_utils:: sugg:: has_enclosing_paren;
44use 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+ } ;
69use core:: ops:: ControlFlow ;
710use rustc_errors:: Applicability ;
811use rustc_hir:: intravisit:: FnKind ;
12+ use rustc_hir:: LangItem :: ResultErr ;
913use rustc_hir:: {
1014 Block , Body , Expr , ExprKind , FnDecl , HirId , ItemKind , LangItem , MatchSource , Node , OwnerNode , PatKind , QPath , Stmt ,
1115 StmtKind ,
@@ -176,37 +180,20 @@ fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
176180 } )
177181}
178182
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-
204183impl < ' tcx > LateLintPass < ' tcx > for Return {
205184 fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
206185 if !in_external_macro ( cx. sess ( ) , stmt. span )
207186 && let StmtKind :: Semi ( expr) = stmt. kind
208187 && 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+
210197 // Ensure this is not the final stmt, otherwise removing it would cause a compile error
211198 && let OwnerNode :: Item ( item) = cx. tcx . hir ( ) . owner ( cx. tcx . hir ( ) . get_parent_item ( expr. hir_id ) )
212199 && let ItemKind :: Fn ( _, _, body) = item. kind
@@ -217,7 +204,6 @@ impl<'tcx> LateLintPass<'tcx> for Return {
217204 && final_stmt. hir_id != stmt. hir_id
218205 && !is_from_proc_macro ( cx, expr)
219206 && !stmt_needs_never_type ( cx, stmt. hir_id )
220- && !desugar_expr_performs_error_conversion ( cx, match_expr)
221207 {
222208 span_lint_and_sugg (
223209 cx,
0 commit comments