Skip to content

Commit 9e9621e

Browse files
committed
always fail fast
1 parent df3b42f commit 9e9621e

2 files changed

Lines changed: 10 additions & 160 deletions

File tree

src/build/mod.rs

Lines changed: 10 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ pub struct BuildOptions {
4242
/// If true, typecheck modules sequentially (one at a time) instead of in
4343
/// parallel. Useful for debugging memory issues or non-deterministic bugs.
4444
pub sequential: bool,
45-
46-
/// If true, stop building as soon as the first error is encountered
47-
/// (build error or type error). Useful for quick iteration.
48-
pub fail_fast: bool,
4945
}
5046

5147
// ===== Public types =====
@@ -283,8 +279,6 @@ fn build_from_sources_impl(
283279
) -> (BuildResult, ModuleRegistry) {
284280
let pipeline_start = Instant::now();
285281
let mut build_errors = Vec::new();
286-
let fail_fast = options.fail_fast;
287-
288282
// Phase 2: Parse all sources (parallel)
289283
log::debug!("Phase 2c: Parsing {} source files", sources.len());
290284
let phase_start = Instant::now();
@@ -402,7 +396,7 @@ fn build_from_sources_impl(
402396
phase_start.elapsed()
403397
);
404398

405-
if fail_fast && !build_errors.is_empty() {
399+
if !build_errors.is_empty() {
406400
let registry = match start_registry {
407401
Some(base) => ModuleRegistry::with_base(base),
408402
None => ModuleRegistry::default(),
@@ -484,7 +478,7 @@ fn build_from_sources_impl(
484478
phase_start.elapsed()
485479
);
486480

487-
if fail_fast && !build_errors.is_empty() {
481+
if !build_errors.is_empty() {
488482
log::debug!("Phase 3 failed");
489483
return (BuildResult { modules: Vec::new(), build_errors }, registry);
490484
}
@@ -601,13 +595,10 @@ fn build_from_sources_impl(
601595
);
602596
}
603597
}
604-
// In sequential mode, check fail_fast after each module
605-
if fail_fast {
606-
let has_errors = module_results.last().map_or(false, |r| !r.type_errors.is_empty()) || !build_errors.is_empty();
607-
if has_errors {
608-
log::debug!("Phase 4: fail_fast triggered after module, stopping");
609-
break;
610-
}
598+
let has_errors = module_results.last().map_or(false, |r| !r.type_errors.is_empty()) || !build_errors.is_empty();
599+
if has_errors {
600+
log::debug!("Phase 4: error after module, stopping");
601+
break;
611602
}
612603
}
613604
} else {
@@ -694,13 +685,10 @@ fn build_from_sources_impl(
694685
}
695686
}
696687
}
697-
// After each dependency level, check if fail_fast should stop
698-
if fail_fast {
699-
let err_count = module_results.iter().filter(|r| !r.type_errors.is_empty()).count();
700-
if !build_errors.is_empty() || err_count > 0 {
701-
log::debug!("Phase 4: fail_fast triggered after level ({} done, {} with errors), stopping", done, err_count);
702-
break;
703-
}
688+
let err_count = module_results.iter().filter(|r| !r.type_errors.is_empty()).count();
689+
if !build_errors.is_empty() || err_count > 0 {
690+
log::debug!("Phase 4: error after level ({} done, {} with errors), stopping", done, err_count);
691+
break;
704692
}
705693
}
706694
log::debug!(
@@ -1213,26 +1201,6 @@ mod tests {
12131201
);
12141202
}
12151203

1216-
#[test]
1217-
fn parse_error_resilience() {
1218-
let result = build_from_sources(&[
1219-
("src/A.purs", "module A where\nx :: Int\nx = 42"),
1220-
("src/Bad.purs", "this is not valid purescript"),
1221-
("src/B.purs", "module B where\nimport A\ny = x"),
1222-
]);
1223-
// Should have a parse error for Bad.purs
1224-
assert!(
1225-
result
1226-
.build_errors
1227-
.iter()
1228-
.any(|e| matches!(e, BuildError::CompileError { .. })),
1229-
"expected CompileError"
1230-
);
1231-
// A and B should still compile successfully
1232-
assert_eq!(result.modules.len(), 2);
1233-
assert!(result.modules.iter().all(|m| m.type_errors.is_empty()));
1234-
}
1235-
12361204
#[test]
12371205
fn prim_import_not_missing() {
12381206
let result = build_from_sources(&[(
@@ -1383,121 +1351,6 @@ roundtrip x = useExceptT (mkExcept x)
13831351
assert!(result.modules[0].type_errors.is_empty());
13841352
}
13851353

1386-
#[test]
1387-
fn export_despite_type_error() {
1388-
let result = build_from_sources(&[
1389-
(
1390-
"src/A.purs",
1391-
"\
1392-
module A where
1393-
1394-
f :: Int -> Int
1395-
f x = x
1396-
1397-
g :: String
1398-
g = 42
1399-
",
1400-
),
1401-
(
1402-
"src/B.purs",
1403-
"\
1404-
module B where
1405-
import A
1406-
1407-
y :: Int
1408-
y = f 1
1409-
",
1410-
),
1411-
]);
1412-
assert!(
1413-
result.build_errors.is_empty(),
1414-
"build errors: {:?}",
1415-
result
1416-
.build_errors
1417-
.iter()
1418-
.map(|e| format!("{}", e))
1419-
.collect::<Vec<_>>()
1420-
);
1421-
let a = result
1422-
.modules
1423-
.iter()
1424-
.find(|m| m.module_name == "A")
1425-
.unwrap();
1426-
assert!(
1427-
!a.type_errors.is_empty(),
1428-
"A should have type errors from g"
1429-
);
1430-
let b = result
1431-
.modules
1432-
.iter()
1433-
.find(|m| m.module_name == "B")
1434-
.unwrap();
1435-
assert!(
1436-
b.type_errors.is_empty(),
1437-
"B should compile cleanly, got: {:?}",
1438-
b.type_errors
1439-
.iter()
1440-
.map(|e| e.to_string())
1441-
.collect::<Vec<_>>()
1442-
);
1443-
}
1444-
1445-
#[test]
1446-
fn signature_exported_on_body_error() {
1447-
let result = build_from_sources(&[
1448-
(
1449-
"src/A.purs",
1450-
"\
1451-
module A where
1452-
1453-
h :: Int -> Int
1454-
h x = \"not an int\"
1455-
",
1456-
),
1457-
(
1458-
"src/B.purs",
1459-
"\
1460-
module B where
1461-
import A
1462-
1463-
y :: Int -> Int
1464-
y = h
1465-
",
1466-
),
1467-
]);
1468-
assert!(
1469-
result.build_errors.is_empty(),
1470-
"build errors: {:?}",
1471-
result
1472-
.build_errors
1473-
.iter()
1474-
.map(|e| format!("{}", e))
1475-
.collect::<Vec<_>>()
1476-
);
1477-
let a = result
1478-
.modules
1479-
.iter()
1480-
.find(|m| m.module_name == "A")
1481-
.unwrap();
1482-
assert!(
1483-
!a.type_errors.is_empty(),
1484-
"A should have type errors from h"
1485-
);
1486-
let b = result
1487-
.modules
1488-
.iter()
1489-
.find(|m| m.module_name == "B")
1490-
.unwrap();
1491-
assert!(
1492-
b.type_errors.is_empty(),
1493-
"B should compile cleanly using h's declared signature, got: {:?}",
1494-
b.type_errors
1495-
.iter()
1496-
.map(|e| e.to_string())
1497-
.collect::<Vec<_>>()
1498-
);
1499-
}
1500-
15011354
#[test]
15021355
fn instance_head_record_in_type_app() {
15031356
let result = build_from_sources(&[(

tests/build.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,6 @@ fn build_all_packages() {
728728
module_timeout: Some(std::time::Duration::from_secs(timeout_secs)),
729729
output_dir: None,
730730
sequential: false,
731-
fail_fast: false,
732731
};
733732

734733
// Discover all packages with src/ directories
@@ -924,13 +923,11 @@ fn build_from_sources() {
924923
.unwrap_or(60);
925924

926925
let sequential = std::env::var("SEQUENTIAL").is_ok();
927-
let fail_fast = std::env::var("FAIL_FAST").is_ok();
928926

929927
let options = BuildOptions {
930928
module_timeout: Some(std::time::Duration::from_secs(timeout_secs)),
931929
output_dir: None,
932930
sequential,
933-
fail_fast,
934931
};
935932

936933
// Step 1: Glob all patterns to collect file paths

0 commit comments

Comments
 (0)