@@ -1900,39 +1900,6 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1900
1900
///
1901
1901
/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
1902
1902
fn 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
-
1936
1903
let [ param] = func. params else {
1937
1904
return false ;
1938
1905
} ;
@@ -1965,11 +1932,56 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
1965
1932
return false ;
1966
1933
}
1967
1934
} ,
1968
- _ => return check_pat ( cx, param. pat , expr) ,
1935
+ _ => return is_expr_identity_of_pat ( cx, param. pat , expr, true ) ,
1969
1936
}
1970
1937
}
1971
1938
}
1972
1939
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
+
1973
1985
/// This is the same as [`is_expr_identity_function`], but does not consider closures
1974
1986
/// with type annotations for its bindings (or similar) as identity functions:
1975
1987
/// * `|x: u8| x`
0 commit comments