@@ -2027,32 +2027,31 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
20272027 did. map_or ( false , |did| cx. tcx . has_attr ( did, sym:: must_use) )
20282028}
20292029
2030- /// Checks if an expression represents the identity function
2031- /// Only examines closures and `std::convert::identity`
2032- pub fn is_expr_identity_function ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
2033- /// Checks if a function's body represents the identity function. Looks for bodies of the form:
2034- /// * `|x| x`
2035- /// * `|x| return x`
2036- /// * `|x| { return x }`
2037- /// * `|x| { return x; }`
2038- fn is_body_identity_function ( cx : & LateContext < ' _ > , func : & Body < ' _ > ) -> bool {
2039- let id = if_chain ! {
2040- if let [ param] = func. params;
2041- if let PatKind :: Binding ( _, id, _, _) = param. pat. kind;
2042- then {
2043- id
2044- } else {
2045- return false ;
2046- }
2047- } ;
2030+ /// Checks if a function's body represents the identity function. Looks for bodies of the form:
2031+ /// * `|x| x`
2032+ /// * `|x| return x`
2033+ /// * `|x| { return x }`
2034+ /// * `|x| { return x; }`
2035+ ///
2036+ /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
2037+ fn is_body_identity_function ( cx : & LateContext < ' _ > , func : & Body < ' _ > ) -> bool {
2038+ let id = if_chain ! {
2039+ if let [ param] = func. params;
2040+ if let PatKind :: Binding ( _, id, _, _) = param. pat. kind;
2041+ then {
2042+ id
2043+ } else {
2044+ return false ;
2045+ }
2046+ } ;
20482047
2049- let mut expr = func. value ;
2050- loop {
2051- match expr. kind {
2052- #[ rustfmt:: skip]
2048+ let mut expr = func. value ;
2049+ loop {
2050+ match expr. kind {
2051+ #[ rustfmt:: skip]
20532052 ExprKind :: Block ( & Block { stmts : [ ] , expr : Some ( e) , .. } , _, )
20542053 | ExprKind :: Ret ( Some ( e) ) => expr = e,
2055- #[ rustfmt:: skip]
2054+ #[ rustfmt:: skip]
20562055 ExprKind :: Block ( & Block { stmts : [ stmt] , expr : None , .. } , _) => {
20572056 if_chain ! {
20582057 if let StmtKind :: Semi ( e) | StmtKind :: Expr ( e) = stmt. kind;
@@ -2064,11 +2063,41 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
20642063 }
20652064 }
20662065 } ,
2067- _ => return path_to_local_id ( expr, id) && cx. typeck_results ( ) . expr_adjustments ( expr) . is_empty ( ) ,
2068- }
2066+ _ => return path_to_local_id ( expr, id) && cx. typeck_results ( ) . expr_adjustments ( expr) . is_empty ( ) ,
20692067 }
20702068 }
2069+ }
20712070
2071+ /// This is the same as [`is_expr_identity_function`], but does not consider closures
2072+ /// with type annotations for its bindings (or similar) as identity functions:
2073+ /// * `|x: u8| x`
2074+ /// * `std::convert::identity::<u8>`
2075+ pub fn is_expr_untyped_identity_function ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
2076+ match expr. kind {
2077+ ExprKind :: Closure ( & Closure { body, fn_decl, .. } )
2078+ if fn_decl. inputs . iter ( ) . all ( |ty| matches ! ( ty. kind, TyKind :: Infer ) ) =>
2079+ {
2080+ is_body_identity_function ( cx, cx. tcx . hir ( ) . body ( body) )
2081+ } ,
2082+ ExprKind :: Path ( QPath :: Resolved ( _, path) )
2083+ if path. segments . iter ( ) . all ( |seg| seg. infer_args )
2084+ && let Some ( did) = path. res . opt_def_id ( ) =>
2085+ {
2086+ match_def_path ( cx, did, & paths:: CONVERT_IDENTITY )
2087+ } ,
2088+ _ => false ,
2089+ }
2090+ }
2091+
2092+ /// Checks if an expression represents the identity function
2093+ /// Only examines closures and `std::convert::identity`
2094+ ///
2095+ /// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want
2096+ /// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't
2097+ /// have type annotations. This is important because removing a closure with bindings can
2098+ /// remove type information that helped type inference before, which can then lead to compile
2099+ /// errors.
2100+ pub fn is_expr_identity_function ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
20722101 match expr. kind {
20732102 ExprKind :: Closure ( & Closure { body, .. } ) => is_body_identity_function ( cx, cx. tcx . hir ( ) . body ( body) ) ,
20742103 _ => path_def_id ( cx, expr) . map_or ( false , |id| match_def_path ( cx, id, & paths:: CONVERT_IDENTITY ) ) ,
0 commit comments