@@ -211,6 +211,7 @@ struct DefinitionsBuilder<'a> {
211211 module_name : ModuleName ,
212212 is_init : bool ,
213213 sys_info : & ' a SysInfo ,
214+ include_unreachable : bool ,
214215 reachability : Reachability ,
215216 inner : Definitions ,
216217}
@@ -238,11 +239,18 @@ fn is_overload_decorator(decorator: &Decorator) -> bool {
238239}
239240
240241impl Definitions {
241- pub fn new ( x : & [ Stmt ] , module_name : ModuleName , is_init : bool , sys_info : & SysInfo ) -> Self {
242+ pub fn new (
243+ x : & [ Stmt ] ,
244+ module_name : ModuleName ,
245+ is_init : bool ,
246+ sys_info : & SysInfo ,
247+ include_unreachable : bool ,
248+ ) -> Self {
242249 let mut builder = DefinitionsBuilder {
243250 module_name,
244251 sys_info,
245252 is_init,
253+ include_unreachable,
246254 reachability : Reachability :: Reachable ,
247255 inner : Definitions :: default ( ) ,
248256 } ;
@@ -663,20 +671,24 @@ impl<'a> DefinitionsBuilder<'a> {
663671 }
664672 }
665673 Stmt :: If ( x) => {
666- self . named_in_expr ( & x. test ) ;
667- let mut seen_definitely_true = false ;
668674 for ( test, body) in Ast :: if_branches ( x) {
675+ if let Some ( test_expr) = test {
676+ self . named_in_expr ( test_expr) ;
677+ }
669678 let evaluation = test
670679 . map ( |expr| self . sys_info . evaluate_bool ( expr) )
671680 . unwrap_or ( Some ( true ) ) ;
672- let branch_reachability = if seen_definitely_true || evaluation == Some ( false ) {
681+ if evaluation == Some ( false ) && !self . include_unreachable {
682+ continue ;
683+ }
684+ let branch_reachability = if evaluation == Some ( false ) {
673685 Reachability :: Unreachable
674686 } else {
675687 Reachability :: Reachable
676688 } ;
677689 self . with_reachability ( branch_reachability, |builder| builder. stmts ( body) ) ;
678690 if evaluation == Some ( true ) {
679- seen_definitely_true = true ;
691+ break ; // Later branches are not evaluated in this configuration
680692 }
681693 }
682694 return ; // We went through the relevant branches already
@@ -775,25 +787,44 @@ mod tests {
775787 }
776788 }
777789
778- fn calculate_unranged_definitions (
790+ fn calculate_unranged_definitions_with_config (
779791 contents : & str ,
780792 module_name : ModuleName ,
781793 is_init : bool ,
794+ include_unreachable : bool ,
782795 ) -> Definitions {
783796 let mut res = Definitions :: new (
784797 & Ast :: parse ( contents, PySourceType :: Python ) . 0 . body ,
785798 module_name,
786799 is_init,
787800 & SysInfo :: default ( ) ,
801+ include_unreachable,
788802 ) ;
789803 res. dunder_all . iter_mut ( ) . for_each ( unrange) ;
790804 res
791805 }
792806
807+ fn calculate_unranged_definitions (
808+ contents : & str ,
809+ module_name : ModuleName ,
810+ is_init : bool ,
811+ ) -> Definitions {
812+ calculate_unranged_definitions_with_config ( contents, module_name, is_init, false )
813+ }
814+
793815 fn calculate_unranged_definitions_with_defaults ( contents : & str ) -> Definitions {
794816 calculate_unranged_definitions ( contents, ModuleName :: from_str ( "main" ) , false )
795817 }
796818
819+ fn calculate_unranged_definitions_with_unreachable ( contents : & str ) -> Definitions {
820+ calculate_unranged_definitions_with_config (
821+ contents,
822+ ModuleName :: from_str ( "main" ) ,
823+ false ,
824+ true ,
825+ )
826+ }
827+
797828 fn assert_import_all ( defs : & Definitions , expected_import_all : & [ & str ] ) {
798829 assert_eq ! (
799830 expected_import_all,
@@ -824,6 +855,25 @@ mod tests {
824855 ) ;
825856 }
826857
858+ #[ test]
859+ fn test_unreachable_if_defs_respected ( ) {
860+ let contents = r#"
861+ if False:
862+ foo: TypeIs[int]
863+ else:
864+ bar = 1
865+ "# ;
866+ let defs = calculate_unranged_definitions_with_unreachable ( contents) ;
867+ let foo = defs. definitions . get ( & Name :: new ( "foo" ) ) . unwrap ( ) ;
868+ assert ! ( matches!( foo. reachability, Reachability :: Unreachable ) ) ;
869+ let bar = defs. definitions . get ( & Name :: new ( "bar" ) ) . unwrap ( ) ;
870+ assert ! ( matches!( bar. reachability, Reachability :: Reachable ) ) ;
871+
872+ let defs_pruned = calculate_unranged_definitions_with_defaults ( contents) ;
873+ assert ! ( defs_pruned. definitions. get( & Name :: new( "foo" ) ) . is_none( ) ) ;
874+ assert ! ( defs_pruned. definitions. get( & Name :: new( "bar" ) ) . is_some( ) ) ;
875+ }
876+
827877 #[ test]
828878 fn test_definitions ( ) {
829879 let defs = calculate_unranged_definitions_with_defaults (
0 commit comments