@@ -549,27 +549,30 @@ impl LifeGuardAnalysis {
549549 /// and B is a passing module with non-empty failing deps, add B to A's failing
550550 /// deps so B is eagerly imported.
551551 pub fn propagate_side_effect_imports ( & mut self , side_effect_imports : & SideEffectMap ) {
552+ let has_failing_deps: AHashSet < ModuleName > = self
553+ . output
554+ . lazy_eligible
555+ . iter ( )
556+ . filter ( |entry| !entry. value ( ) . is_empty ( ) )
557+ . map ( |entry| * entry. key ( ) )
558+ . collect ( ) ;
559+
552560 side_effect_imports
553561 . par_iter ( )
554562 . for_each ( |( module_name, se_imports) | {
555563 if !self . passing_modules . contains ( module_name) {
556564 return ;
557565 }
558- let mut new_deps: SmallSet < ModuleName > = SmallSet :: new ( ) ;
559- for se_import in se_imports {
560- if let Some ( deps) = self . output . lazy_eligible . get ( se_import) {
561- if !deps. is_empty ( ) {
562- new_deps. insert ( * se_import) ;
563- }
564- }
565- }
566- if !new_deps. is_empty ( ) {
567- self . output
568- . lazy_eligible
569- . entry ( * module_name)
570- . or_default ( )
571- . extend ( new_deps) ;
572- }
566+ self . output
567+ . lazy_eligible
568+ . entry ( * module_name)
569+ . or_default ( )
570+ . extend (
571+ se_imports
572+ . iter ( )
573+ . filter ( |se_import| has_failing_deps. contains ( * se_import) )
574+ . copied ( ) ,
575+ ) ;
573576 } ) ;
574577 }
575578
@@ -1055,6 +1058,71 @@ mod tests {
10551058 assert ! ( child_deps. contains( & b) ) ;
10561059 }
10571060
1061+ #[ test]
1062+ fn test_side_effect_imports_do_not_observe_same_pass_updates ( ) {
1063+ let options = Options {
1064+ verbose_output_path : None ,
1065+ sorted_output : true ,
1066+ main_module : None ,
1067+ } ;
1068+ let exports = Exports :: empty ( ) ;
1069+
1070+ for iteration in 0 ..64 {
1071+ let safety_map = SafetyMap :: new ( ) ;
1072+ let mut import_graph = ImportGraph :: new ( ) ;
1073+ let mut side_effect_imports: SideEffectMap = AHashMap :: new ( ) ;
1074+ let mut chains = Vec :: new ( ) ;
1075+
1076+ for chain_idx in 0 ..16 {
1077+ let outer = mn ( & format ! ( "outer_{iteration}_{chain_idx}" ) ) ;
1078+ let middle = mn ( & format ! ( "middle_{iteration}_{chain_idx}" ) ) ;
1079+ let inner = mn ( & format ! ( "inner_{iteration}_{chain_idx}" ) ) ;
1080+ let leaf = mn ( & format ! ( "leaf_{iteration}_{chain_idx}" ) ) ;
1081+
1082+ import_graph. graph . add_node ( & outer) ;
1083+ import_graph. graph . add_node ( & middle) ;
1084+ import_graph. graph . add_node ( & inner) ;
1085+ import_graph. graph . add_node ( & leaf) ;
1086+ import_graph. graph . add_edge ( & outer, & middle) ;
1087+ import_graph. graph . add_edge ( & middle, & inner) ;
1088+ import_graph. graph . add_edge ( & inner, & leaf) ;
1089+
1090+ safety_map. insert ( outer, SafetyResult :: Ok ( ModuleSafety :: new ( ) ) ) ;
1091+ safety_map. insert ( middle, SafetyResult :: Ok ( ModuleSafety :: new ( ) ) ) ;
1092+ safety_map. insert ( inner, SafetyResult :: Ok ( ModuleSafety :: new ( ) ) ) ;
1093+
1094+ let mut failing = ModuleSafety :: new ( ) ;
1095+ failing. add_error ( make_error (
1096+ ErrorKind :: UnknownDecoratorCall ,
1097+ "unknown-decorator-call" ,
1098+ chain_idx,
1099+ ) ) ;
1100+ safety_map. insert ( leaf, SafetyResult :: Ok ( failing) ) ;
1101+
1102+ side_effect_imports. insert ( middle, [ inner] . into_iter ( ) . collect ( ) ) ;
1103+ side_effect_imports. insert ( outer, [ middle] . into_iter ( ) . collect ( ) ) ;
1104+ chains. push ( ( outer, middle, inner) ) ;
1105+ }
1106+
1107+ let mut analysis = LifeGuardAnalysis :: new ( safety_map, import_graph, & exports, & options) ;
1108+ analysis. propagate_side_effect_imports ( & side_effect_imports) ;
1109+
1110+ for ( outer, middle, inner) in chains {
1111+ let middle_deps = analysis. output . lazy_eligible . get ( & middle) . unwrap ( ) ;
1112+ assert ! (
1113+ middle_deps. contains( & inner) ,
1114+ "{middle} should be guarded by {inner}" ,
1115+ ) ;
1116+
1117+ let outer_deps = analysis. output . lazy_eligible . get ( & outer) . unwrap ( ) ;
1118+ assert ! (
1119+ !outer_deps. contains( & middle) ,
1120+ "{outer} should not observe side-effect deps added to {middle} during the same propagation pass" ,
1121+ ) ;
1122+ }
1123+ }
1124+ }
1125+
10581126 // ---- build_re_export_map tests ----
10591127
10601128 fn attr ( module : & str , name : & str ) -> Attribute {
0 commit comments