@@ -288,22 +288,32 @@ impl LibraryCache {
288288 func_safety_by_module : & mut HashMap < ModuleName , HashMap < String , FunctionSafetyInfo > > ,
289289 globally_safe_funcs : & mut AHashSet < String > ,
290290 ) -> bool {
291- let mut to_promote: Vec < ( ModuleName , String ) > = Vec :: new ( ) ;
292- for module in & self . modules {
293- let Some ( fs) = func_safety_by_module. get ( & module. name ) else {
294- continue ;
295- } ;
296- for ( func_name, info) in fs {
297- if can_promote_missing_dep_function (
298- info,
299- module_names,
300- func_safety_by_module,
301- globally_safe_funcs,
302- ) {
303- to_promote. push ( ( module. name , func_name. clone ( ) ) ) ;
304- }
305- }
306- }
291+ let to_promote: Vec < ( ModuleName , String ) > = {
292+ // Reborrow as shared for parallel access.
293+ let func_safety_by_module = & * func_safety_by_module;
294+ let globally_safe_funcs = & * globally_safe_funcs;
295+
296+ self . modules
297+ . par_iter ( )
298+ . filter_map ( |module| {
299+ func_safety_by_module
300+ . get ( & module. name )
301+ . map ( |fs| ( module. name , fs) )
302+ } )
303+ . flat_map_iter ( |( name, fs) | {
304+ fs. iter ( )
305+ . filter ( move |( _, info) | {
306+ can_promote_missing_dep_function (
307+ info,
308+ module_names,
309+ func_safety_by_module,
310+ globally_safe_funcs,
311+ )
312+ } )
313+ . map ( move |( func_name, _) | ( name, func_name. clone ( ) ) )
314+ } )
315+ . collect ( )
316+ } ;
307317
308318 let promoted = !to_promote. is_empty ( ) ;
309319 for ( module_name, func_name) in to_promote {
@@ -327,27 +337,29 @@ impl LibraryCache {
327337 func_safety_by_module : & HashMap < ModuleName , HashMap < String , FunctionSafetyInfo > > ,
328338 globally_safe_funcs : & AHashSet < String > ,
329339 ) -> bool {
330- let mut cleared = false ;
331- for module in & mut self . modules {
332- if let CachedSafety :: Ok ( ref mut safety) = module. safety {
333- cleared |= retain_unverified_errors ( safety, |func_name| {
340+ self . modules
341+ . par_iter_mut ( )
342+ . map ( |module| {
343+ let CachedSafety :: Ok ( ref mut safety) = module. safety else {
344+ return false ;
345+ } ;
346+ retain_unverified_errors ( safety, |func_name| {
334347 is_call_verified_safe_indexed (
335348 func_name,
336349 module_names,
337350 func_safety_by_module,
338351 globally_safe_funcs,
339352 )
340- } ) ;
341- }
342- }
343- cleared
353+ } )
354+ } )
355+ . reduce ( || false , |any_cleared, cleared| any_cleared || cleared)
344356 }
345357
346358 /// Resolve missing imports against the merged cache and selectively clear
347359 /// false errors using per-function safety verdicts.
348360 pub fn resolve_cross_library_errors ( & mut self ) {
349361 let module_names: AHashSet < ModuleName > = self . modules . iter ( ) . map ( |m| m. name ) . collect ( ) ;
350- let mut ambiguous_resolved = self . resolve_ambiguous_imports ( & module_names) ;
362+ let ambiguous_resolved = self . resolve_ambiguous_imports ( & module_names) ;
351363
352364 self . propagate_re_export_safety ( ) ;
353365
@@ -357,15 +369,15 @@ impl LibraryCache {
357369 . map ( |m| ( m. name , std:: mem:: take ( & mut m. function_safety ) ) )
358370 . collect ( ) ;
359371
360- for module in & mut self . modules {
372+ self . modules . par_iter_mut ( ) . for_each ( |module| {
361373 if let CachedSafety :: Ok ( ref mut safety) = module. safety {
362374 resolve_implicit_imports ( & mut safety. implicit_imports , & module_names) ;
363375 }
364376
365- let from_ambiguous = ambiguous_resolved. remove ( & module. name ) ;
377+ let from_ambiguous = ambiguous_resolved. get ( & module. name ) ;
366378
367379 if module. missing_imports . is_empty ( ) && from_ambiguous. is_none ( ) {
368- continue ;
380+ return ;
369381 }
370382
371383 let mut still_missing: AHashSet < ModuleName > =
@@ -374,7 +386,7 @@ impl LibraryCache {
374386 AHashSet :: with_capacity ( module. missing_imports . len ( ) ) ;
375387
376388 if let Some ( from_ambiguous) = from_ambiguous {
377- resolved_modules. extend ( from_ambiguous) ;
389+ resolved_modules. extend ( from_ambiguous. iter ( ) . copied ( ) ) ;
378390 }
379391
380392 for missing in module. missing_imports . drain ( ) {
@@ -393,7 +405,7 @@ impl LibraryCache {
393405 is_call_verified_safe ( func_name, & resolved_modules, & func_safety_by_module)
394406 } ) ;
395407 }
396- }
408+ } ) ;
397409
398410 self . upgrade_missing_dep_functions ( & module_names, & mut func_safety_by_module) ;
399411
@@ -804,3 +816,99 @@ impl CachedExports {
804816 self . return_types . extend ( other. return_types ) ;
805817 }
806818}
819+
820+ #[ cfg( test) ]
821+ mod tests {
822+ use rayon:: ThreadPoolBuilder ;
823+
824+ use super :: * ;
825+
826+ #[ test]
827+ fn clear_verified_errors_processes_every_module ( ) {
828+ let module_a = ModuleName :: from_str ( "test.module_a" ) ;
829+ let module_b = ModuleName :: from_str ( "test.module_b" ) ;
830+
831+ let mut cache = LibraryCache {
832+ modules : vec ! [
833+ CachedModule {
834+ name: module_a,
835+ safety: CachedSafety :: Ok ( CachedModuleSafety {
836+ errors: vec![ CachedError {
837+ kind: ErrorKind :: UnknownFunctionCall ,
838+ metadata: "helper()" . to_owned( ) ,
839+ } ] ,
840+ force_imports_eager_overrides: Vec :: new( ) ,
841+ implicit_imports: Vec :: new( ) ,
842+ } ) ,
843+ imports: AHashSet :: new( ) ,
844+ missing_imports: AHashSet :: new( ) ,
845+ ambiguous_imports: AHashSet :: new( ) ,
846+ side_effect_imports: AHashSet :: new( ) ,
847+ function_safety: HashMap :: new( ) ,
848+ } ,
849+ CachedModule {
850+ name: module_b,
851+ safety: CachedSafety :: Ok ( CachedModuleSafety {
852+ errors: vec![ CachedError {
853+ kind: ErrorKind :: UnknownFunctionCall ,
854+ metadata: "helper()" . to_owned( ) ,
855+ } ] ,
856+ force_imports_eager_overrides: Vec :: new( ) ,
857+ implicit_imports: Vec :: new( ) ,
858+ } ) ,
859+ imports: AHashSet :: new( ) ,
860+ missing_imports: AHashSet :: new( ) ,
861+ ambiguous_imports: AHashSet :: new( ) ,
862+ side_effect_imports: AHashSet :: new( ) ,
863+ function_safety: HashMap :: new( ) ,
864+ } ,
865+ ] ,
866+ exports : CachedExports {
867+ definitions : Vec :: new ( ) ,
868+ re_exports : Vec :: new ( ) ,
869+ all : Vec :: new ( ) ,
870+ return_types : Vec :: new ( ) ,
871+ } ,
872+ } ;
873+
874+ let module_names: AHashSet < ModuleName > = [ module_a, module_b] . into_iter ( ) . collect ( ) ;
875+ let func_safety_by_module = HashMap :: from ( [
876+ (
877+ module_a,
878+ HashMap :: from ( [ (
879+ "helper" . to_owned ( ) ,
880+ FunctionSafetyInfo :: new ( FunctionSafety :: Safe ) ,
881+ ) ] ) ,
882+ ) ,
883+ (
884+ module_b,
885+ HashMap :: from ( [ (
886+ "helper" . to_owned ( ) ,
887+ FunctionSafetyInfo :: new ( FunctionSafety :: Safe ) ,
888+ ) ] ) ,
889+ ) ,
890+ ] ) ;
891+ let globally_safe_funcs: AHashSet < String > = [ "helper" . to_owned ( ) ] . into_iter ( ) . collect ( ) ;
892+
893+ let cleared = ThreadPoolBuilder :: new ( )
894+ . num_threads ( 1 )
895+ . build ( )
896+ . expect ( "should build test thread pool" )
897+ . install ( || {
898+ cache. clear_verified_errors (
899+ & module_names,
900+ & func_safety_by_module,
901+ & globally_safe_funcs,
902+ )
903+ } ) ;
904+
905+ assert ! (
906+ cleared,
907+ "expected at least one verified error to be removed"
908+ ) ;
909+ assert ! (
910+ cache. modules. iter( ) . all( CachedModule :: is_safe) ,
911+ "all modules should have their verified errors cleared" ,
912+ ) ;
913+ }
914+ }
0 commit comments