44//! overview of how lints are implemented.
55
66use std:: cell:: Cell ;
7+ use std:: ops:: ControlFlow ;
78use std:: slice;
89
10+ use rustc_ast:: BindingMode ;
911use rustc_data_structures:: fx:: FxIndexMap ;
1012use rustc_data_structures:: sync;
1113use rustc_data_structures:: unord:: UnordMap ;
@@ -14,6 +16,8 @@ use rustc_feature::Features;
1416use rustc_hir:: def:: Res ;
1517use rustc_hir:: def_id:: { CrateNum , DefId } ;
1618use rustc_hir:: definitions:: { DefPathData , DisambiguatedDefPathData } ;
19+ use rustc_hir:: intravisit:: Visitor ;
20+ use rustc_hir:: { HirId , Pat , PatKind } ;
1721use rustc_middle:: bug;
1822use rustc_middle:: middle:: privacy:: EffectiveVisibilities ;
1923use rustc_middle:: ty:: layout:: { LayoutError , LayoutOfHelpers , TyAndLayout } ;
@@ -890,7 +894,18 @@ impl<'tcx> LateContext<'tcx> {
890894 }
891895 && let Some ( init) = match parent_node {
892896 hir:: Node :: Expr ( expr) => Some ( expr) ,
893- hir:: Node :: LetStmt ( hir:: LetStmt { init, .. } ) => * init,
897+ hir:: Node :: LetStmt ( hir:: LetStmt {
898+ init,
899+ // Bindigng is immutable, init cannot be re-assigned
900+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: NONE , ..) , .. } ,
901+ ..
902+ } ) => * init,
903+ hir:: Node :: LetStmt ( hir:: LetStmt {
904+ init,
905+ // Bindigng is mutable, init can be re-assigned to, if it is bail-out
906+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: MUT , binding_id, ..) , .. } ,
907+ ..
908+ } ) if !ReassignBindingFinder :: is_binding_reassigned ( self , * binding_id) => * init,
894909 _ => None ,
895910 }
896911 {
@@ -935,7 +950,18 @@ impl<'tcx> LateContext<'tcx> {
935950 }
936951 && let Some ( init) = match parent_node {
937952 hir:: Node :: Expr ( expr) => Some ( expr) ,
938- hir:: Node :: LetStmt ( hir:: LetStmt { init, .. } ) => * init,
953+ hir:: Node :: LetStmt ( hir:: LetStmt {
954+ init,
955+ // Bindigng is immutable, init cannot be re-assigned
956+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: NONE , ..) , .. } ,
957+ ..
958+ } ) => * init,
959+ hir:: Node :: LetStmt ( hir:: LetStmt {
960+ init,
961+ // Bindigng is mutable, init can be re-assigned to, if it is bail-out
962+ pat : Pat { kind : PatKind :: Binding ( BindingMode :: MUT , binding_id, ..) , .. } ,
963+ ..
964+ } ) if !ReassignBindingFinder :: is_binding_reassigned ( self , * binding_id) => * init,
939965 hir:: Node :: Item ( item) => match item. kind {
940966 hir:: ItemKind :: Const ( .., body_id) | hir:: ItemKind :: Static ( .., body_id) => {
941967 Some ( self . tcx . hir_body ( body_id) . value )
@@ -980,3 +1006,40 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
9801006 err
9811007 }
9821008}
1009+
1010+ struct ReassignBindingFinder < ' a , ' tcx > {
1011+ cx : & ' a LateContext < ' tcx > ,
1012+ binding_id : HirId ,
1013+ }
1014+
1015+ impl < ' a , ' tcx > ReassignBindingFinder < ' a , ' tcx > {
1016+ fn is_binding_reassigned ( cx : & ' a LateContext < ' tcx > , binding_id : HirId ) -> bool {
1017+ if let Some ( enclosing_scope_id) = cx. tcx . hir_get_enclosing_scope ( binding_id)
1018+ && let hir:: Node :: Block ( block) = cx. tcx . hir_node ( enclosing_scope_id)
1019+ {
1020+ let mut finder = ReassignBindingFinder { cx, binding_id } ;
1021+ finder. visit_block ( block) . is_break ( )
1022+ } else {
1023+ false
1024+ }
1025+ }
1026+ }
1027+
1028+ impl < ' tcx > Visitor < ' tcx > for ReassignBindingFinder < ' _ , ' tcx > {
1029+ type Result = ControlFlow < ( ) > ;
1030+ type NestedFilter = rustc_middle:: hir:: nested_filter:: OnlyBodies ;
1031+
1032+ fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , hir_id : HirId ) -> Self :: Result {
1033+ if let Res :: Local ( id) = path. res {
1034+ if self . binding_id == id && self . cx . tcx . hir_is_lhs ( hir_id) {
1035+ return ControlFlow :: Break ( ( ) ) ;
1036+ }
1037+ }
1038+
1039+ ControlFlow :: Continue ( ( ) )
1040+ }
1041+
1042+ fn maybe_tcx ( & mut self ) -> Self :: MaybeTyCtxt {
1043+ self . cx . tcx
1044+ }
1045+ }
0 commit comments