@@ -103,11 +103,11 @@ use rustc_hir::definitions::{DefPath, DefPathData};
103103use rustc_hir:: hir_id:: { HirIdMap , HirIdSet } ;
104104use rustc_hir:: intravisit:: { Visitor , walk_expr} ;
105105use rustc_hir:: {
106- self as hir, Arm , BindingMode , Block , BlockCheckMode , Body , ByRef , Closure , ConstArgKind , CoroutineDesugaring ,
107- CoroutineKind , CoroutineSource , Destination , Expr , ExprField , ExprKind , FnDecl , FnRetTy , GenericArg , GenericArgs ,
108- HirId , Impl , ImplItem , ImplItemKind , Item , ItemKind , LangItem , LetStmt , MatchSource , Mutability , Node , OwnerId ,
109- OwnerNode , Param , Pat , PatExpr , PatExprKind , PatKind , Path , PathSegment , QPath , Stmt , StmtKind , TraitFn , TraitItem ,
110- TraitItemKind , TraitRef , TyKind , UnOp , def, find_attr,
106+ self as hir, Arm , BindingMode , Block , BlockCheckMode , Body , BodyId , ByRef , Closure , ConstArgKind ,
107+ CoroutineDesugaring , CoroutineKind , CoroutineSource , Destination , Expr , ExprField , ExprKind , FnDecl , FnRetTy ,
108+ GenericArg , GenericArgs , HirId , Impl , ImplItem , ImplItemKind , Item , ItemKind , LangItem , LetStmt , MatchSource ,
109+ Mutability , Node , OwnerId , OwnerNode , Param , Pat , PatExpr , PatExprKind , PatKind , Path , PathSegment , QPath , Stmt ,
110+ StmtKind , TraitFn , TraitItem , TraitItemKind , TraitRef , TyKind , UnOp , def, find_attr,
111111} ;
112112use rustc_lexer:: { FrontmatterAllowed , TokenKind , tokenize} ;
113113use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
@@ -1824,7 +1824,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
18241824 for stmt in stmts {
18251825 if let StmtKind :: Let ( local) = stmt. kind
18261826 && let Some ( init) = local. init
1827- && is_expr_identity_of_pat ( cx, param_pat, init, true )
1827+ && is_expr_identity_of_pat ( cx, param_pat, init, func . id ( ) , true )
18281828 {
18291829 param_pat = local. pat ;
18301830 } else {
@@ -1833,7 +1833,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
18331833 }
18341834 expr = e;
18351835 } ,
1836- _ => return is_expr_identity_of_pat ( cx, param_pat, expr, true ) ,
1836+ _ => return is_expr_identity_of_pat ( cx, param_pat, expr, func . id ( ) , true ) ,
18371837 }
18381838 }
18391839}
@@ -1847,9 +1847,16 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
18471847///
18481848/// Note that `by_hir` is used to determine bindings are checked by their `HirId` or by their name.
18491849/// This can be useful when checking patterns in `let` bindings or `match` arms.
1850- pub fn is_expr_identity_of_pat ( cx : & LateContext < ' _ > , pat : & Pat < ' _ > , expr : & Expr < ' _ > , by_hir : bool ) -> bool {
1850+ pub fn is_expr_identity_of_pat (
1851+ cx : & LateContext < ' _ > ,
1852+ pat : & Pat < ' _ > ,
1853+ expr : & Expr < ' _ > ,
1854+ func_id : BodyId ,
1855+ by_hir : bool ,
1856+ ) -> bool {
18511857 if cx
1852- . typeck_results ( )
1858+ . tcx
1859+ . typeck_body ( func_id)
18531860 . pat_binding_modes ( )
18541861 . get ( pat. hir_id )
18551862 . is_some_and ( |mode| matches ! ( mode. 0 , ByRef :: Yes ( _) ) )
@@ -1861,22 +1868,25 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
18611868 }
18621869
18631870 // NOTE: we're inside a (function) body, so this won't ICE
1864- let qpath_res = |qpath, hir| cx. typeck_results ( ) . qpath_res ( qpath, hir) ;
1871+ let qpath_res = |qpath, hir| cx. tcx . typeck_body ( func_id ) . qpath_res ( qpath, hir) ;
18651872
18661873 match ( pat. kind , expr. kind ) {
18671874 ( PatKind :: Binding ( _, id, _, _) , _) if by_hir => {
1868- expr. res_local_id ( ) == Some ( id) && cx. typeck_results ( ) . expr_adjustments ( expr) . is_empty ( )
1875+ expr. res_local_id ( ) == Some ( id) && cx. tcx . typeck_body ( func_id ) . expr_adjustments ( expr) . is_empty ( )
18691876 } ,
18701877 ( PatKind :: Binding ( _, _, ident, _) , ExprKind :: Path ( QPath :: Resolved ( _, path) ) ) => {
18711878 matches ! ( path. segments, [ segment] if segment. ident. name == ident. name)
18721879 } ,
18731880 ( PatKind :: Tuple ( pats, dotdot) , ExprKind :: Tup ( tup) )
18741881 if dotdot. as_opt_usize ( ) . is_none ( ) && pats. len ( ) == tup. len ( ) =>
18751882 {
1876- over ( pats, tup, |pat, expr| is_expr_identity_of_pat ( cx, pat, expr, by_hir) )
1883+ over ( pats, tup, |pat, expr| {
1884+ is_expr_identity_of_pat ( cx, pat, expr, func_id, by_hir)
1885+ } )
18771886 } ,
18781887 ( PatKind :: Slice ( before, None , after) , ExprKind :: Array ( arr) ) if before. len ( ) + after. len ( ) == arr. len ( ) => {
1879- zip ( before. iter ( ) . chain ( after) , arr) . all ( |( pat, expr) | is_expr_identity_of_pat ( cx, pat, expr, by_hir) )
1888+ zip ( before. iter ( ) . chain ( after) , arr)
1889+ . all ( |( pat, expr) | is_expr_identity_of_pat ( cx, pat, expr, func_id, by_hir) )
18801890 } ,
18811891 ( PatKind :: TupleStruct ( pat_ident, field_pats, dotdot) , ExprKind :: Call ( ident, fields) )
18821892 if dotdot. as_opt_usize ( ) . is_none ( ) && field_pats. len ( ) == fields. len ( ) =>
@@ -1885,7 +1895,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
18851895 if let ExprKind :: Path ( ident) = & ident. kind
18861896 && qpath_res ( & pat_ident, pat. hir_id ) == qpath_res ( ident, expr. hir_id )
18871897 // check fields
1888- && over ( field_pats, fields, |pat, expr| is_expr_identity_of_pat ( cx, pat, expr, by_hir) )
1898+ && over ( field_pats, fields, |pat, expr| is_expr_identity_of_pat ( cx, pat, expr, func_id , by_hir) )
18891899 {
18901900 true
18911901 } else {
@@ -1899,7 +1909,8 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
18991909 qpath_res ( & pat_ident, pat. hir_id ) == qpath_res ( ident, expr. hir_id )
19001910 // check fields
19011911 && unordered_over ( field_pats, fields, |field_pat, field| {
1902- field_pat. ident == field. ident && is_expr_identity_of_pat ( cx, field_pat. pat , field. expr , by_hir)
1912+ field_pat. ident == field. ident &&
1913+ is_expr_identity_of_pat ( cx, field_pat. pat , field. expr , func_id, by_hir)
19031914 } )
19041915 } ,
19051916 _ => false ,
@@ -1938,7 +1949,38 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>)
19381949pub fn is_expr_identity_function ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
19391950 match expr. kind {
19401951 ExprKind :: Closure ( & Closure { body, .. } ) => is_body_identity_function ( cx, cx. tcx . hir_body ( body) ) ,
1941- _ => expr. basic_res ( ) . is_diag_item ( cx, sym:: convert_identity) ,
1952+ _ if expr. basic_res ( ) . is_diag_item ( cx, sym:: convert_identity) => true ,
1953+
1954+ ExprKind :: Path ( qpath) => {
1955+ let res = cx. qpath_res ( & qpath, expr. hir_id ) ;
1956+ match res {
1957+ // Case 1: Local variable (could be a closure)
1958+ Res :: Local ( hir_id) => {
1959+ if let Some ( init_expr) = find_binding_init ( cx, hir_id) {
1960+ let origin = expr_or_init ( cx, init_expr) ;
1961+ if let ExprKind :: Closure ( & Closure { body, .. } ) = origin. kind {
1962+ is_body_identity_function ( cx, cx. tcx . hir_body ( body) )
1963+ } else {
1964+ false
1965+ }
1966+ } else {
1967+ false
1968+ }
1969+ } ,
1970+ // Case 2: Function definition
1971+ Res :: Def ( DefKind :: Fn , def_id) => {
1972+ if let Some ( local_def_id) = def_id. as_local ( )
1973+ && let Some ( body) = cx. tcx . hir_maybe_body_owned_by ( local_def_id)
1974+ {
1975+ is_body_identity_function ( cx, body)
1976+ } else {
1977+ false
1978+ }
1979+ } ,
1980+ _ => false ,
1981+ }
1982+ } ,
1983+ _ => false ,
19421984 }
19431985}
19441986
0 commit comments