@@ -379,7 +379,7 @@ fn generate_asts(version: &str, build_state: &mut BuildState, pb: &ProgressBar)
379379 SourceType :: SourceFile ( source_file) => {
380380 let root_package = build_state. get_package ( & build_state. root_config_name ) . unwrap ( ) ;
381381
382- let ( ast_path, iast_path) = if source_file. implementation . dirty
382+ let ( ast_path, iast_path, dirty ) = if source_file. implementation . dirty
383383 || source_file. interface . as_ref ( ) . map ( |i| i. dirty ) . unwrap_or ( false )
384384 {
385385 pb. inc ( 1 ) ;
@@ -403,7 +403,7 @@ fn generate_asts(version: &str, build_state: &mut BuildState, pb: &ProgressBar)
403403 _ => Ok ( None ) ,
404404 } ;
405405
406- ( ast_result, iast_result)
406+ ( ast_result, iast_result, true )
407407 } else {
408408 (
409409 Ok ( (
@@ -414,10 +414,11 @@ fn generate_asts(version: &str, build_state: &mut BuildState, pb: &ProgressBar)
414414 . interface
415415 . as_ref ( )
416416 . map ( |i| ( helpers:: get_basename ( & i. path ) . to_string ( ) + ".iast" , None ) ) ) ,
417+ false ,
417418 )
418419 } ;
419420
420- ( module_name. to_owned ( ) , ast_path, iast_path, true )
421+ ( module_name. to_owned ( ) , ast_path, iast_path, dirty )
421422 }
422423 }
423424 } )
@@ -441,6 +442,7 @@ fn generate_asts(version: &str, build_state: &mut BuildState, pb: &ProgressBar)
441442 SourceType :: MlMap ( _) => module. compile_dirty = true ,
442443 _ => ( ) ,
443444 }
445+ module. compile_dirty = true
444446 }
445447 match ast_path {
446448 Ok ( ( _path, err) ) => {
@@ -671,6 +673,8 @@ pub fn parse_packages(build_state: &mut BuildState) {
671673 dependents : AHashSet :: new ( ) ,
672674 package_name : package. name . to_owned ( ) ,
673675 compile_dirty : false ,
676+ last_compiled_cmt : None ,
677+ last_compiled_cmi : None ,
674678 } ,
675679 ) ;
676680 } ) ;
@@ -719,6 +723,8 @@ pub fn parse_packages(build_state: &mut BuildState) {
719723 dependents : AHashSet :: new ( ) ,
720724 package_name : package. name . to_owned ( ) ,
721725 compile_dirty : true ,
726+ last_compiled_cmt : None ,
727+ last_compiled_cmi : None ,
722728 } ) ;
723729 } else {
724730 // remove last character of string: resi -> res, rei -> re, mli -> ml
@@ -769,6 +775,8 @@ pub fn parse_packages(build_state: &mut BuildState) {
769775 dependents : AHashSet :: new ( ) ,
770776 package_name : package. name . to_owned ( ) ,
771777 compile_dirty : true ,
778+ last_compiled_cmt : None ,
779+ last_compiled_cmi : None ,
772780 } ) ;
773781 }
774782 }
@@ -1223,6 +1231,60 @@ fn format_dependency_cycle(cycle: &Vec<String>) -> String {
12231231 . join ( " -> " )
12241232}
12251233
1234+ pub fn mark_modules_with_deleted_deps_dirty (
1235+ build_state : & mut BuildState ,
1236+ deleted_modules : & AHashSet < String > ,
1237+ ) {
1238+ build_state. modules . iter_mut ( ) . for_each ( |( _, module) | {
1239+ if !module. deps . is_disjoint ( deleted_modules) {
1240+ module. compile_dirty = true ;
1241+ }
1242+ } ) ;
1243+ }
1244+
1245+ pub fn mark_modules_with_expired_deps_dirty ( build_state : & mut BuildState ) {
1246+ let mut modules_with_expired_deps: AHashSet < String > = AHashSet :: new ( ) ;
1247+ build_state
1248+ . modules
1249+ . iter ( )
1250+ . filter ( |m| !m. 1 . is_mlmap ( ) )
1251+ . for_each ( |( module_name, module) | {
1252+ for dependent in module. dependents . iter ( ) {
1253+ let dependent_module = build_state. modules . get ( dependent) . unwrap ( ) ;
1254+ match dependent_module. source_type {
1255+ SourceType :: SourceFile ( _) => {
1256+ match ( module. last_compiled_cmt , module. last_compiled_cmi ) {
1257+ ( None , None ) | ( Some ( _) , None ) | ( None , Some ( _) ) => {
1258+ modules_with_expired_deps. insert ( module_name. to_string ( ) ) ;
1259+ }
1260+ ( Some ( _) , Some ( _) ) => ( ) ,
1261+ }
1262+
1263+ // we compare the last compiled time of the dependent module with the last
1264+ // compile of the interface of the module it depends on, if the interface
1265+ // didn't change it doesn't matter
1266+ match ( dependent_module. last_compiled_cmt , module. last_compiled_cmi ) {
1267+ ( Some ( last_compiled_dependent) , Some ( last_compiled) ) => {
1268+ if last_compiled_dependent < last_compiled {
1269+ modules_with_expired_deps. insert ( dependent. to_string ( ) ) ;
1270+ }
1271+ }
1272+ _ => ( ) ,
1273+ }
1274+ }
1275+ // a namespace is never a dependent of a module (it can be a dependency, but not the other
1276+ // way around)
1277+ SourceType :: MlMap ( _) => ( ) ,
1278+ }
1279+ }
1280+ } ) ;
1281+ build_state. modules . iter_mut ( ) . for_each ( |( module_name, module) | {
1282+ if modules_with_expired_deps. contains ( module_name) {
1283+ module. compile_dirty = true ;
1284+ }
1285+ } ) ;
1286+ }
1287+
12261288pub fn build ( filter : & Option < regex:: Regex > , path : & str , no_timing : bool ) -> Result < BuildState , ( ) > {
12271289 let timing_total = Instant :: now ( ) ;
12281290 let project_root = helpers:: get_abs_path ( path) ;
@@ -1351,21 +1413,29 @@ pub fn build(filter: &Option<regex::Regex>, path: &str, no_timing: bool) -> Resu
13511413 let start_compiling = Instant :: now ( ) ;
13521414
13531415 let mut compiled_modules = AHashSet :: < String > :: new ( ) ;
1416+
1417+ mark_modules_with_deleted_deps_dirty ( & mut build_state, & deleted_module_names) ;
1418+ mark_modules_with_expired_deps_dirty ( & mut build_state) ;
1419+
13541420 let dirty_modules = build_state
13551421 . modules
1356- . iter_mut ( )
1422+ . iter ( )
13571423 . filter_map ( |( module_name, module) | {
13581424 if module. compile_dirty {
13591425 Some ( module_name. to_owned ( ) )
1360- } else if !module. deps . is_disjoint ( & deleted_module_names) {
1361- module. compile_dirty = true ;
1362- Some ( module_name. to_owned ( ) )
13631426 } else {
13641427 None
13651428 }
13661429 } )
13671430 . collect :: < AHashSet < String > > ( ) ;
13681431
1432+ // println!("{} dirty modules", dirty_modules.len());
1433+ // let mut sorted_dirty_modules = dirty_modules.iter().collect::<Vec<&String>>();
1434+ // sorted_dirty_modules.sort();
1435+ // sorted_dirty_modules
1436+ // .iter()
1437+ // .for_each(|m| println!("dirty module: {}", m));
1438+
13691439 // for sure clean modules -- after checking the hash of the cmi
13701440 let mut clean_modules = AHashSet :: < String > :: new ( ) ;
13711441
@@ -1382,10 +1452,6 @@ pub fn build(filter: &Option<regex::Regex>, path: &str, no_timing: bool) -> Resu
13821452 let mut sorted_modules = build_state. module_names . iter ( ) . collect :: < Vec < & String > > ( ) ;
13831453 sorted_modules. sort ( ) ;
13841454
1385- // for module in dirty_modules.clone() {
1386- // println!("dirty module: {}", module);
1387- // }
1388-
13891455 // this is the whole "compile universe" all modules that might be dirty
13901456 // we get this by traversing from the dirty modules to all the modules that
13911457 // are dependent on them
@@ -1406,6 +1472,7 @@ pub fn build(filter: &Option<regex::Regex>, path: &str, no_timing: bool) -> Resu
14061472 break ;
14071473 }
14081474 }
1475+
14091476 let pb = ProgressBar :: new ( compile_universe. len ( ) . try_into ( ) . unwrap ( ) ) ;
14101477 pb. set_style (
14111478 ProgressStyle :: with_template ( & format ! (
@@ -1591,9 +1658,10 @@ pub fn build(filter: &Option<regex::Regex>, path: &str, no_timing: bool) -> Resu
15911658
15921659 // if not clean -- compile modules that depend on this module
15931660 for dep in module_dependents. iter ( ) {
1594- let dep_module = build_state. modules . get_mut ( dep) . unwrap ( ) ;
15951661 // mark the reverse dep as dirty when the source is not clean
15961662 if !* is_clean {
1663+ let dep_module = build_state. modules . get_mut ( dep) . unwrap ( ) ;
1664+ // mark the reverse dep as dirty when the source is not clean
15971665 dep_module. compile_dirty = true ;
15981666 }
15991667 if !compiled_modules. contains ( dep) {
0 commit comments