@@ -1900,39 +1900,6 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
19001900///
19011901/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
19021902fn is_body_identity_function ( cx : & LateContext < ' _ > , func : & Body < ' _ > ) -> bool {
1903- fn check_pat ( cx : & LateContext < ' _ > , pat : & Pat < ' _ > , expr : & Expr < ' _ > ) -> bool {
1904- if cx
1905- . typeck_results ( )
1906- . pat_binding_modes ( )
1907- . get ( pat. hir_id )
1908- . is_some_and ( |mode| matches ! ( mode. 0 , ByRef :: Yes ( _) ) )
1909- {
1910- // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
1911- // due to match ergonomics, the inner patterns become references. Don't consider this
1912- // the identity function as that changes types.
1913- return false ;
1914- }
1915-
1916- match ( pat. kind , expr. kind ) {
1917- ( PatKind :: Binding ( _, id, _, _) , _) => {
1918- path_to_local_id ( expr, id) && cx. typeck_results ( ) . expr_adjustments ( expr) . is_empty ( )
1919- } ,
1920- ( PatKind :: Tuple ( pats, dotdot) , ExprKind :: Tup ( tup) )
1921- if dotdot. as_opt_usize ( ) . is_none ( ) && pats. len ( ) == tup. len ( ) =>
1922- {
1923- pats. iter ( ) . zip ( tup) . all ( |( pat, expr) | check_pat ( cx, pat, expr) )
1924- } ,
1925- ( PatKind :: Slice ( before, slice, after) , ExprKind :: Array ( arr) )
1926- if slice. is_none ( ) && before. len ( ) + after. len ( ) == arr. len ( ) =>
1927- {
1928- ( before. iter ( ) . chain ( after) )
1929- . zip ( arr)
1930- . all ( |( pat, expr) | check_pat ( cx, pat, expr) )
1931- } ,
1932- _ => false ,
1933- }
1934- }
1935-
19361903 let [ param] = func. params else {
19371904 return false ;
19381905 } ;
@@ -1965,11 +1932,56 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
19651932 return false ;
19661933 }
19671934 } ,
1968- _ => return check_pat ( cx, param. pat , expr) ,
1935+ _ => return is_expr_identity_of_pat ( cx, param. pat , expr, true ) ,
19691936 }
19701937 }
19711938}
19721939
1940+ /// Checks if the given expression is an identity representation of the given pattern:
1941+ /// * `x` is the identity representation of `x`
1942+ /// * `(x, y)` is the identity representation of `(x, y)`
1943+ /// * `[x, y]` is the identity representation of `[x, y]`
1944+ ///
1945+ /// Note that `by_hir` is used to determine bindings are checked by their `HirId` or by their name.
1946+ /// This can be useful when checking patterns in `let` bindings or `match` arms.
1947+ pub fn is_expr_identity_of_pat ( cx : & LateContext < ' _ > , pat : & Pat < ' _ > , expr : & Expr < ' _ > , by_hir : bool ) -> bool {
1948+ if cx
1949+ . typeck_results ( )
1950+ . pat_binding_modes ( )
1951+ . get ( pat. hir_id )
1952+ . is_some_and ( |mode| matches ! ( mode. 0 , ByRef :: Yes ( _) ) )
1953+ {
1954+ // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
1955+ // due to match ergonomics, the inner patterns become references. Don't consider this
1956+ // the identity function as that changes types.
1957+ return false ;
1958+ }
1959+
1960+ match ( pat. kind , expr. kind ) {
1961+ ( PatKind :: Binding ( _, id, _, _) , _) if by_hir => {
1962+ path_to_local_id ( expr, id) && cx. typeck_results ( ) . expr_adjustments ( expr) . is_empty ( )
1963+ } ,
1964+ ( PatKind :: Binding ( _, _, ident, _) , ExprKind :: Path ( QPath :: Resolved ( _, path) ) ) => {
1965+ matches ! ( path. segments, [ segment] if segment. ident. name == ident. name)
1966+ } ,
1967+ ( PatKind :: Tuple ( pats, dotdot) , ExprKind :: Tup ( tup) )
1968+ if dotdot. as_opt_usize ( ) . is_none ( ) && pats. len ( ) == tup. len ( ) =>
1969+ {
1970+ pats. iter ( )
1971+ . zip ( tup)
1972+ . all ( |( pat, expr) | is_expr_identity_of_pat ( cx, pat, expr, by_hir) )
1973+ } ,
1974+ ( PatKind :: Slice ( before, slice, after) , ExprKind :: Array ( arr) )
1975+ if slice. is_none ( ) && before. len ( ) + after. len ( ) == arr. len ( ) =>
1976+ {
1977+ ( before. iter ( ) . chain ( after) )
1978+ . zip ( arr)
1979+ . all ( |( pat, expr) | is_expr_identity_of_pat ( cx, pat, expr, by_hir) )
1980+ } ,
1981+ _ => false ,
1982+ }
1983+ }
1984+
19731985/// This is the same as [`is_expr_identity_function`], but does not consider closures
19741986/// with type annotations for its bindings (or similar) as identity functions:
19751987/// * `|x: u8| x`
0 commit comments