@@ -2027,32 +2027,31 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
2027
2027
did. map_or ( false , |did| cx. tcx . has_attr ( did, sym:: must_use) )
2028
2028
}
2029
2029
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
+ } ;
2048
2047
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]
2053
2052
ExprKind :: Block ( & Block { stmts : [ ] , expr : Some ( e) , .. } , _, )
2054
2053
| ExprKind :: Ret ( Some ( e) ) => expr = e,
2055
- #[ rustfmt:: skip]
2054
+ #[ rustfmt:: skip]
2056
2055
ExprKind :: Block ( & Block { stmts : [ stmt] , expr : None , .. } , _) => {
2057
2056
if_chain ! {
2058
2057
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
2064
2063
}
2065
2064
}
2066
2065
} ,
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 ( ) ,
2069
2067
}
2070
2068
}
2069
+ }
2071
2070
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 {
2072
2101
match expr. kind {
2073
2102
ExprKind :: Closure ( & Closure { body, .. } ) => is_body_identity_function ( cx, cx. tcx . hir ( ) . body ( body) ) ,
2074
2103
_ => path_def_id ( cx, expr) . map_or ( false , |id| match_def_path ( cx, id, & paths:: CONVERT_IDENTITY ) ) ,
0 commit comments