iter form-a.1 (Tasks 1-5): additive phase + relocation
First half of the form-a-default-authoring milestone-close iter (Boss-decided strategy C, big-bang). All five tasks DONE; cargo test --workspace green at every per-task boundary. T1 — Add three new tests: - parse_is_deterministic_over_every_ail_fixture (round_trip.rs) - cli_parse_then_render_then_parse_is_idempotent (roundtrip_cli.rs) - carve_out_inventory.rs (new file; #[ignore]'d until T8 deletion) T2 — Bulk-render the 99 missing examples/<stem>.ail files via `ail render`. Corpus 58 .ail (pre-iter) -> 157 .ail. Eight .ail.json carve-outs (7 §C4(a) subject-matter + 1 §C4(b) prelude) preserved. One re-loop triggered: load_workspace prefers .ail siblings since ext-cli.1, so the newly-rendered imports broke seven Group-A entries whose JSON entry-paths now resolved imports to fresh .ail. Repair: pre-emptive forward-pull of five T3 migrations + 4 transient #[ignore]s on workspace.rs mod tests (cleanly relocated in T5). T3 — 14 Group-A test files migrated from ailang_core::load_workspace to ailang_surface::load_workspace + .ail paths. Carve-out lines preserved verbatim (7 sites in typeclass_22b2.rs / typeclass_22b3.rs). T4 — 12 Group-B test files: bulk regex flip on build_and_run / build_and_run_with_alloc / build_and_run_with_rc_stats call sites (~70 e2e.rs invocations + 11 subprocess sites). Four files mis-classified Group-A as Group-B in plan recon (mono_hash_stability, prelude_free_fns, print_mono_body_shape, show_mono_synthesis); two files mis-classified Group-B as Group-A (mono_recursive_fn, mono_xmod_qualified_ref). Migrated per actual shape, not plan label. T5 — Relocated #[cfg(test)] mod tests from production source to integration test crates with ailang-surface dev-dependency: - crates/ailang-core/tests/hash_pin.rs (10 tests from hash.rs) - crates/ailang-core/tests/workspace_pin.rs (10 non-carve-out tests from workspace.rs) - crates/ailang-codegen/tests/eq_primitives_pin.rs (3 tests from codegen/src/lib.rs:3717-3799) - ailang-prose/tests/snapshot.rs migrated (helper + 8 fixtures) to .ail + ailang_surface::load_module Carve-out tests in workspace.rs mod tests preserved in-place (3× 22b2 + 3× ct1 = 6 tests). Tempdir-based loader-mechanism tests (3 sites) also preserved — they don't consume examples/. Tests: 560 passed, 0 failed, 4 ignored (was 558 + 3 T1 new - 1 transit carve_out_inventory #[ignore] = 560 active). Tasks 6-12 (bench-driver suffix flips, e2e diff-test rewrite + 4 additional raw-JSON-inspect handlers, .ail.json deletion, retiring obsolete roundtrip tests + schema_coverage corpus flip, §C3 DESIGN.md restatement, §A4 doctrine edits, WhatsNew + roadmap strike) ship in the next dispatch on this iter ID. Known debt inherited to T6-12: 4 raw-JSON-inspect tests in e2e.rs (borrow_own_demo / reuse_as_demo / render_parse_round_trip_canonical / ail_run_accepts_ail_source_with_same_stdout_as_ail_json dual-form smoke) need rewrite or #[ignore] before T8 deletion; recorded in journal Concerns + Known debt sections.
This commit is contained in:
@@ -19,13 +19,13 @@
|
||||
|
||||
use ailang_check::{check_workspace, monomorphise_workspace};
|
||||
use ailang_core::ast::{Def, Term};
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture_path() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../examples")
|
||||
.join("show_user_adt.ail.json")
|
||||
.join("show_user_adt.ail")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -166,7 +166,7 @@ fn check_human_mode_emits_actionable_message_to_stderr() {
|
||||
/// form used to succeed.
|
||||
#[test]
|
||||
fn check_ordering_match_post_migration_is_clean() {
|
||||
let fixture = examples_dir().join("ordering_match.ail.json");
|
||||
let fixture = examples_dir().join("ordering_match.ail");
|
||||
let output = Command::new(ail_bin())
|
||||
.args(["check", "--json", fixture.to_str().unwrap()])
|
||||
.output()
|
||||
|
||||
+69
-69
@@ -78,7 +78,7 @@ fn build_and_run_with_alloc(example: &str, alloc: &str) -> String {
|
||||
|
||||
#[test]
|
||||
fn sum_1_to_10_is_55() {
|
||||
let stdout = build_and_run("sum.ail.json");
|
||||
let stdout = build_and_run("sum.ail");
|
||||
assert_eq!(stdout.trim(), "55");
|
||||
}
|
||||
|
||||
@@ -86,20 +86,20 @@ fn sum_1_to_10_is_55() {
|
||||
/// phi block tracking would produce a wrong result here.
|
||||
#[test]
|
||||
fn max3_picks_largest() {
|
||||
let stdout = build_and_run("max3.ail.json");
|
||||
let stdout = build_and_run("max3.ail");
|
||||
assert_eq!(stdout.trim(), "17");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hello_world_str_lit() {
|
||||
let stdout = build_and_run("hello.ail.json");
|
||||
let stdout = build_and_run("hello.ail");
|
||||
assert_eq!(stdout.trim(), "Hello, AILang.");
|
||||
}
|
||||
|
||||
/// Guards ADT codegen + match: recursive list, sum_list via match on Cons/Nil.
|
||||
#[test]
|
||||
fn list_sum_via_match() {
|
||||
let stdout = build_and_run("list.ail.json");
|
||||
let stdout = build_and_run("list.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ fn list_sum_via_match() {
|
||||
/// produce 42, exercising fn-typed parameters and indirect call.
|
||||
#[test]
|
||||
fn higher_order_apply_inc() {
|
||||
let stdout = build_and_run("hof.ail.json");
|
||||
let stdout = build_and_run("hof.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ fn higher_order_apply_inc() {
|
||||
/// and apply's indirect call unpacks both halves.
|
||||
#[test]
|
||||
fn closure_captures_let_n() {
|
||||
let stdout = build_and_run("closure.ail.json");
|
||||
let stdout = build_and_run("closure.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ fn closure_captures_let_n() {
|
||||
/// `map (\x. x * 2)` over `[1, 2, 3]` then print each element.
|
||||
#[test]
|
||||
fn list_map_doubles_then_prints() {
|
||||
let stdout = build_and_run("list_map.ail.json");
|
||||
let stdout = build_and_run("list_map.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["2", "4", "6"]);
|
||||
}
|
||||
@@ -141,7 +141,7 @@ fn list_map_doubles_then_prints() {
|
||||
/// effectful tail call.
|
||||
#[test]
|
||||
fn list_map_poly_inc_then_prints() {
|
||||
let stdout = build_and_run("list_map_poly.ail.json");
|
||||
let stdout = build_and_run("list_map_poly.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["2", "3", "4"]);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ fn list_map_poly_inc_then_prints() {
|
||||
/// scrutinee with a wildcard fallback is not currently in the grammar.
|
||||
#[test]
|
||||
fn gc_handles_recursive_list_construction() {
|
||||
let stdout = build_and_run("gc_stress.ail.json");
|
||||
let stdout = build_and_run("gc_stress.ail");
|
||||
assert_eq!(
|
||||
stdout.trim(),
|
||||
"1275",
|
||||
@@ -177,7 +177,7 @@ fn gc_handles_recursive_list_construction() {
|
||||
/// for the Box and zero `@GC_malloc` calls inside `peek`/`count`.
|
||||
#[test]
|
||||
fn iter17a_local_box_alloca() {
|
||||
let stdout = build_and_run("escape_local_demo.ail.json");
|
||||
let stdout = build_and_run("escape_local_demo.ail");
|
||||
assert_eq!(
|
||||
stdout.lines().collect::<Vec<_>>(),
|
||||
vec!["42", "42", "5", "0"],
|
||||
@@ -190,7 +190,7 @@ fn iter17a_local_box_alloca() {
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src = workspace
|
||||
.join("examples")
|
||||
.join("escape_local_demo.ail.json");
|
||||
.join("escape_local_demo.ail");
|
||||
let tmp = std::env::temp_dir().join(format!(
|
||||
"ailang_iter17a_alloca_{}",
|
||||
std::process::id()
|
||||
@@ -237,7 +237,7 @@ fn iter17a_local_box_alloca() {
|
||||
fn iter14e_print_list_recursion_emits_musttail() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src = workspace.join("examples").join("list_map_poly.ail.json");
|
||||
let src = workspace.join("examples").join("list_map_poly.ail");
|
||||
let tmp = std::env::temp_dir().join(format!(
|
||||
"ailang_iter14e_musttail_{}",
|
||||
std::process::id()
|
||||
@@ -290,7 +290,7 @@ fn iter14e_print_list_recursion_emits_musttail() {
|
||||
/// recursion + branching without surprises.
|
||||
#[test]
|
||||
fn insertion_sort_orders_list() {
|
||||
let stdout = build_and_run("sort.ail.json");
|
||||
let stdout = build_and_run("sort.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(
|
||||
lines,
|
||||
@@ -303,7 +303,7 @@ fn insertion_sort_orders_list() {
|
||||
/// triggers a separate specialised LLVM fn. Output: 42, then "true".
|
||||
#[test]
|
||||
fn polymorphic_id_at_int_and_bool() {
|
||||
let stdout = build_and_run("poly_id.ail.json");
|
||||
let stdout = build_and_run("poly_id.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["42", "true"]);
|
||||
}
|
||||
@@ -314,7 +314,7 @@ fn polymorphic_id_at_int_and_bool() {
|
||||
/// monomorphised body (a fn-typed param survives substitution).
|
||||
#[test]
|
||||
fn polymorphic_apply_with_fn_param() {
|
||||
let stdout = build_and_run("poly_apply.ail.json");
|
||||
let stdout = build_and_run("poly_apply.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ fn polymorphic_apply_with_fn_param() {
|
||||
/// down into a polymorphic fn body.
|
||||
#[test]
|
||||
fn parameterised_box_round_trip() {
|
||||
let stdout = build_and_run("box.ail.json");
|
||||
let stdout = build_and_run("box.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ fn parameterised_box_round_trip() {
|
||||
/// `x : Int`, not `x : a`).
|
||||
#[test]
|
||||
fn parameterised_maybe_match() {
|
||||
let stdout = build_and_run("maybe_int.ail.json");
|
||||
let stdout = build_and_run("maybe_int.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["7", "99"]);
|
||||
}
|
||||
@@ -351,7 +351,7 @@ fn parameterised_maybe_match() {
|
||||
/// flows end-to-end through check, codegen, and runtime.
|
||||
#[test]
|
||||
fn cross_module_maybe_demo() {
|
||||
let stdout = build_and_run("std_maybe_demo.ail.json");
|
||||
let stdout = build_and_run("std_maybe_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["7", "99", "true", "true", "42"]);
|
||||
}
|
||||
@@ -365,7 +365,7 @@ fn cross_module_maybe_demo() {
|
||||
/// and fail to unify against the qualified scrutinee args.
|
||||
#[test]
|
||||
fn std_list_demo() {
|
||||
let stdout = build_and_run("std_list_demo.ail.json");
|
||||
let stdout = build_and_run("std_list_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(
|
||||
lines,
|
||||
@@ -395,7 +395,7 @@ fn std_list_demo() {
|
||||
/// happens at N=1000.
|
||||
#[test]
|
||||
fn std_list_stress_1000_element_folds() {
|
||||
let stdout = build_and_run("std_list_stress.ail.json");
|
||||
let stdout = build_and_run("std_list_stress.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(
|
||||
lines,
|
||||
@@ -457,7 +457,7 @@ fn render_parse_round_trip_canonical() {
|
||||
/// the inner binders would be silently dropped by the codegen.
|
||||
#[test]
|
||||
fn nested_ctor_pattern_first_two_sum() {
|
||||
let stdout = build_and_run("nested_pat.ail.json");
|
||||
let stdout = build_and_run("nested_pat.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["30"]);
|
||||
}
|
||||
@@ -471,7 +471,7 @@ fn nested_ctor_pattern_first_two_sum() {
|
||||
/// for the substituted MkPair output.
|
||||
#[test]
|
||||
fn std_pair_demo() {
|
||||
let stdout = build_and_run("std_pair_demo.ail.json");
|
||||
let stdout = build_and_run("std_pair_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["7", "9", "9", "7", "8", "18"]);
|
||||
}
|
||||
@@ -488,7 +488,7 @@ fn std_pair_demo() {
|
||||
/// another instantiation.
|
||||
#[test]
|
||||
fn std_either_demo() {
|
||||
let stdout = build_and_run("std_either_demo.ail.json");
|
||||
let stdout = build_and_run("std_either_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(
|
||||
lines,
|
||||
@@ -513,7 +513,7 @@ fn std_either_demo() {
|
||||
/// `[Left 1, Right 10, Left 2, Right 20, Right 30]`.
|
||||
#[test]
|
||||
fn std_either_list_demo() {
|
||||
let stdout = build_and_run("std_either_list_demo.ail.json");
|
||||
let stdout = build_and_run("std_either_list_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["2", "3", "2", "3"]);
|
||||
}
|
||||
@@ -528,7 +528,7 @@ fn std_either_list_demo() {
|
||||
/// n>length) on each combinator. Expected stdout: 0, 3, 5, 5, 3, 0.
|
||||
#[test]
|
||||
fn std_list_more_demo() {
|
||||
let stdout = build_and_run("std_list_more_demo.ail.json");
|
||||
let stdout = build_and_run("std_list_more_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["0", "3", "5", "5", "3", "0"]);
|
||||
}
|
||||
@@ -546,7 +546,7 @@ fn std_list_more_demo() {
|
||||
/// wrong values.
|
||||
#[test]
|
||||
fn local_rec_factorial_demo() {
|
||||
let stdout = build_and_run("local_rec_demo.ail.json");
|
||||
let stdout = build_and_run("local_rec_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["1", "6", "120"]);
|
||||
}
|
||||
@@ -563,7 +563,7 @@ fn local_rec_factorial_demo() {
|
||||
/// sum_below(10)=45.
|
||||
#[test]
|
||||
fn local_rec_capture_demo() {
|
||||
let stdout = build_and_run("local_rec_capture.ail.json");
|
||||
let stdout = build_and_run("local_rec_capture.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["0", "10", "45"]);
|
||||
}
|
||||
@@ -581,7 +581,7 @@ fn local_rec_capture_demo() {
|
||||
/// count_below(15)=9 (i in 1..9 are below threshold 10).
|
||||
#[test]
|
||||
fn local_rec_let_capture_demo() {
|
||||
let stdout = build_and_run("local_rec_let_capture.ail.json");
|
||||
let stdout = build_and_run("local_rec_let_capture.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["0", "5", "9"]);
|
||||
}
|
||||
@@ -601,7 +601,7 @@ fn local_rec_let_capture_demo() {
|
||||
/// count_below(MkPair 10 15)=9.
|
||||
#[test]
|
||||
fn local_rec_match_capture_demo() {
|
||||
let stdout = build_and_run("local_rec_match_capture.ail.json");
|
||||
let stdout = build_and_run("local_rec_match_capture.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["0", "5", "9"]);
|
||||
}
|
||||
@@ -617,7 +617,7 @@ fn local_rec_match_capture_demo() {
|
||||
/// Expected stdout: 120 (= apply5 factorial = factorial 5).
|
||||
#[test]
|
||||
fn local_rec_as_value_demo() {
|
||||
let stdout = build_and_run("local_rec_as_value.ail.json");
|
||||
let stdout = build_and_run("local_rec_as_value.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["120"]);
|
||||
}
|
||||
@@ -633,7 +633,7 @@ fn local_rec_as_value_demo() {
|
||||
/// Expected stdout: 1320 (= 5*4*3*2*(1+10)), 12120 (= 5*4*3*2*(1+100)).
|
||||
#[test]
|
||||
fn local_rec_as_value_capture_demo() {
|
||||
let stdout = build_and_run("local_rec_as_value_capture.ail.json");
|
||||
let stdout = build_and_run("local_rec_as_value_capture.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["1320", "12120"]);
|
||||
}
|
||||
@@ -661,7 +661,7 @@ fn local_rec_as_value_capture_demo() {
|
||||
/// applied 4 times to false — even count of flips ⇒ false).
|
||||
#[test]
|
||||
fn poly_rec_capture_demo() {
|
||||
let stdout = build_and_run("poly_rec_capture.ail.json");
|
||||
let stdout = build_and_run("poly_rec_capture.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["5", "false"]);
|
||||
}
|
||||
@@ -686,7 +686,7 @@ fn poly_rec_capture_demo() {
|
||||
/// 1..=n. Expected stdout: 1, 6, 15 for n in {1, 3, 5}.
|
||||
#[test]
|
||||
fn nested_let_rec_demo() {
|
||||
let stdout = build_and_run("nested_let_rec.ail.json");
|
||||
let stdout = build_and_run("nested_let_rec.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["1", "6", "15"]);
|
||||
}
|
||||
@@ -781,7 +781,7 @@ fn diff_detects_changed_def() {
|
||||
fn diff_no_changes_exit_zero() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src = workspace.join("examples").join("sum.ail.json");
|
||||
let src = workspace.join("examples").join("sum.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args([
|
||||
@@ -822,7 +822,7 @@ fn diff_no_changes_exit_zero() {
|
||||
fn workspace_lists_imported_modules() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let entry = workspace.join("examples").join("ws_main.ail.json");
|
||||
let entry = workspace.join("examples").join("ws_main.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args(["workspace", entry.to_str().unwrap(), "--json"])
|
||||
@@ -866,7 +866,7 @@ fn workspace_lists_imported_modules() {
|
||||
fn check_workspace_resolves_import() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let entry = workspace.join("examples").join("ws_main.ail.json");
|
||||
let entry = workspace.join("examples").join("ws_main.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args(["check", entry.to_str().unwrap(), "--json"])
|
||||
@@ -891,7 +891,7 @@ fn check_workspace_resolves_import() {
|
||||
/// `@ail_ws_main_main` must call `@ail_ws_lib_add(2,3)` and print `5`.
|
||||
#[test]
|
||||
fn workspace_build_runs_imported_fn() {
|
||||
let stdout = build_and_run("ws_main.ail.json");
|
||||
let stdout = build_and_run("ws_main.ail");
|
||||
assert_eq!(stdout.trim(), "5", "ws_lib.add(2,3) should print 5");
|
||||
}
|
||||
|
||||
@@ -904,7 +904,7 @@ fn workspace_build_runs_imported_fn() {
|
||||
/// `imports: ["prelude"]` entry in the source module.
|
||||
#[test]
|
||||
fn ordering_match_via_prelude_prints_1() {
|
||||
let stdout = build_and_run("ordering_match.ail.json");
|
||||
let stdout = build_and_run("ordering_match.ail");
|
||||
assert_eq!(stdout, "1\n");
|
||||
}
|
||||
|
||||
@@ -923,7 +923,7 @@ fn ordering_match_via_prelude_prints_1() {
|
||||
/// is type-driven, and the run completes cleanly.
|
||||
#[test]
|
||||
fn compare_primitives_smoke_prints_1_2_3_thrice() {
|
||||
let stdout = build_and_run("compare_primitives_smoke.ail.json");
|
||||
let stdout = build_and_run("compare_primitives_smoke.ail");
|
||||
assert_eq!(stdout, "1\n2\n3\n1\n2\n3\n1\n2\n3\n");
|
||||
}
|
||||
|
||||
@@ -935,7 +935,7 @@ fn compare_primitives_smoke_prints_1_2_3_thrice() {
|
||||
/// call. Equal-call lines are `1`, unequal-call lines are `0`.
|
||||
#[test]
|
||||
fn eq_primitives_smoke_compiles_and_runs() {
|
||||
let stdout = build_and_run("eq_primitives_smoke.ail.json");
|
||||
let stdout = build_and_run("eq_primitives_smoke.ail");
|
||||
assert_eq!(stdout, "1\n0\n1\n0\n1\n0\n");
|
||||
}
|
||||
|
||||
@@ -945,7 +945,7 @@ fn eq_primitives_smoke_compiles_and_runs() {
|
||||
fn manifest_workspace_lists_all_defs() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let entry = workspace.join("examples").join("ws_main.ail.json");
|
||||
let entry = workspace.join("examples").join("ws_main.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args([
|
||||
@@ -988,7 +988,7 @@ fn manifest_workspace_lists_all_defs() {
|
||||
fn describe_workspace_resolves_qualified_name() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let entry = workspace.join("examples").join("ws_main.ail.json");
|
||||
let entry = workspace.join("examples").join("ws_main.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args([
|
||||
@@ -1031,7 +1031,7 @@ fn describe_workspace_resolves_qualified_name() {
|
||||
fn deps_filters_builtins_params_locals() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src = workspace.join("examples").join("sum.ail.json");
|
||||
let src = workspace.join("examples").join("sum.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args(["deps", src.to_str().unwrap(), "--of", "sum", "--json"])
|
||||
@@ -1070,7 +1070,7 @@ fn deps_filters_builtins_params_locals() {
|
||||
fn deps_workspace_filters_builtins_and_params() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let entry = workspace.join("examples").join("ws_main.ail.json");
|
||||
let entry = workspace.join("examples").join("ws_main.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args(["deps", entry.to_str().unwrap(), "--workspace", "--json"])
|
||||
@@ -1096,7 +1096,7 @@ fn deps_workspace_filters_builtins_and_params() {
|
||||
fn deps_workspace_includes_cross_module() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let entry = workspace.join("examples").join("ws_main.ail.json");
|
||||
let entry = workspace.join("examples").join("ws_main.ail");
|
||||
|
||||
let output = Command::new(ail_bin())
|
||||
.args(["deps", entry.to_str().unwrap(), "--workspace", "--json"])
|
||||
@@ -1266,7 +1266,7 @@ fn check_json_unbound_var() {
|
||||
/// chain default).
|
||||
#[test]
|
||||
fn lit_pat_demo() {
|
||||
let stdout = build_and_run("lit_pat.ail.json");
|
||||
let stdout = build_and_run("lit_pat.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["100", "200", "999", "-1", "0", "7"]);
|
||||
}
|
||||
@@ -1281,7 +1281,7 @@ fn lit_pat_demo() {
|
||||
/// print the expected outputs.
|
||||
#[test]
|
||||
fn unreachable_demo() {
|
||||
let stdout = build_and_run("unreachable_demo.ail.json");
|
||||
let stdout = build_and_run("unreachable_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["4", "5"]);
|
||||
}
|
||||
@@ -1321,7 +1321,7 @@ fn borrow_own_demo_modes_are_metadata_only() {
|
||||
"expected `param_modes:[\"own\"]` in canonical JSON; the schema for `(own T)` regressed"
|
||||
);
|
||||
|
||||
let stdout = build_and_run("borrow_own_demo.ail.json");
|
||||
let stdout = build_and_run("borrow_own_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(lines, vec!["3", "6"]);
|
||||
}
|
||||
@@ -1338,7 +1338,7 @@ fn borrow_own_demo_modes_are_metadata_only() {
|
||||
/// non-Int args at typecheck.
|
||||
#[test]
|
||||
fn eq_demo() {
|
||||
let stdout = build_and_run("eq_demo.ail.json");
|
||||
let stdout = build_and_run("eq_demo.ail");
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
assert_eq!(
|
||||
lines,
|
||||
@@ -1374,7 +1374,7 @@ fn alloc_rc_produces_same_stdout_as_gc() {
|
||||
/// passthrough with `call void @ailang_rc_inc` under `--alloc=rc`.
|
||||
#[test]
|
||||
fn clone_demo_is_identity_in_18c1() {
|
||||
let stdout = build_and_run("clone_demo.ail.json");
|
||||
let stdout = build_and_run("clone_demo.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
@@ -1413,11 +1413,11 @@ fn reuse_as_demo_under_rc_uses_inplace_rewrite() {
|
||||
);
|
||||
|
||||
// (2) gc baseline.
|
||||
let stdout_gc = build_and_run_with_alloc("reuse_as_demo.ail.json", "gc");
|
||||
let stdout_gc = build_and_run_with_alloc("reuse_as_demo.ail", "gc");
|
||||
assert_eq!(stdout_gc.trim(), "9");
|
||||
// (3) rc matches gc, (4) clean exit (build_and_run_with_alloc
|
||||
// panics on non-zero status).
|
||||
let stdout_rc = build_and_run_with_alloc("reuse_as_demo.ail.json", "rc");
|
||||
let stdout_rc = build_and_run_with_alloc("reuse_as_demo.ail", "rc");
|
||||
assert_eq!(stdout_rc.trim(), "9");
|
||||
|
||||
// (5) Inspect the rc IR text. We re-lower via the codegen API
|
||||
@@ -2176,7 +2176,7 @@ fn build_and_run_with_rc_stats(example: &str) -> (String, u64, u64, i64) {
|
||||
#[test]
|
||||
fn alloc_rc_explicit_mode_tail_sum_does_not_leak_outer_cells() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("rc_tail_sum_explicit_leak.ail.json");
|
||||
build_and_run_with_rc_stats("rc_tail_sum_explicit_leak.ail");
|
||||
assert_eq!(
|
||||
stdout.trim(),
|
||||
"4950",
|
||||
@@ -2211,7 +2211,7 @@ fn alloc_rc_explicit_mode_tail_sum_does_not_leak_outer_cells() {
|
||||
#[test]
|
||||
fn alloc_rc_let_binder_for_owned_returning_app_drops_at_scope_close() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("rc_let_owned_app_leak.ail.json");
|
||||
build_and_run_with_rc_stats("rc_let_owned_app_leak.ail");
|
||||
assert_eq!(
|
||||
stdout.trim(),
|
||||
"1",
|
||||
@@ -2255,7 +2255,7 @@ fn alloc_rc_let_binder_for_owned_returning_app_drops_at_scope_close() {
|
||||
#[test]
|
||||
fn alloc_rc_let_binder_for_implicit_returning_app_does_not_drop() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("rc_let_implicit_returning_app.ail.json");
|
||||
build_and_run_with_rc_stats("rc_let_implicit_returning_app.ail");
|
||||
assert_eq!(stdout.trim(), "7", "alloc(7) -> unbox should print 7");
|
||||
assert_eq!(
|
||||
live, 1,
|
||||
@@ -2339,7 +2339,7 @@ fn alloc_rc_let_alias_of_implicit_param_does_not_dec_borrowed_children() {
|
||||
#[test]
|
||||
fn alloc_rc_partial_drop_at_fn_return_does_not_leak_unmoved_fields() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("rc_own_param_partial_drop_leak.ail.json");
|
||||
build_and_run_with_rc_stats("rc_own_param_partial_drop_leak.ail");
|
||||
assert_eq!(
|
||||
stdout.trim(),
|
||||
"1",
|
||||
@@ -2378,7 +2378,7 @@ fn alloc_rc_partial_drop_at_fn_return_does_not_leak_unmoved_fields() {
|
||||
#[test]
|
||||
fn alloc_rc_partial_drop_at_arm_close_does_not_leak_unmoved_fields() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("rc_match_arm_partial_drop_leak.ail.json");
|
||||
build_and_run_with_rc_stats("rc_match_arm_partial_drop_leak.ail");
|
||||
assert_eq!(
|
||||
stdout.trim(),
|
||||
"1",
|
||||
@@ -2411,7 +2411,7 @@ fn alloc_rc_partial_drop_at_arm_close_does_not_leak_unmoved_fields() {
|
||||
#[test]
|
||||
fn alloc_rc_partial_drop_at_app_let_close_does_not_leak_unmoved_fields() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("rc_app_let_partial_drop_leak.ail.json");
|
||||
build_and_run_with_rc_stats("rc_app_let_partial_drop_leak.ail");
|
||||
assert_eq!(
|
||||
stdout.trim(),
|
||||
"1",
|
||||
@@ -2571,7 +2571,7 @@ fn ail_run_accepts_ail_source_with_same_stdout_as_ail_json() {
|
||||
/// every alloc strategy after the hs.4 hoist).
|
||||
#[test]
|
||||
fn int_to_str_smoke() {
|
||||
let out = build_and_run("int_to_str_smoke.ail.json");
|
||||
let out = build_and_run("int_to_str_smoke.ail");
|
||||
assert_eq!(out, "42\n");
|
||||
}
|
||||
|
||||
@@ -2584,7 +2584,7 @@ fn int_to_str_smoke() {
|
||||
/// trip-wire that surfaces it.
|
||||
#[test]
|
||||
fn float_to_str_smoke() {
|
||||
let out = build_and_run("float_to_str_smoke.ail.json");
|
||||
let out = build_and_run("float_to_str_smoke.ail");
|
||||
assert_eq!(out, "3.5\n");
|
||||
}
|
||||
|
||||
@@ -2600,7 +2600,7 @@ fn float_to_str_smoke() {
|
||||
#[test]
|
||||
fn int_to_str_drop_balances_rc_stats() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("int_to_str_drop_rc.ail.json");
|
||||
build_and_run_with_rc_stats("int_to_str_drop_rc.ail");
|
||||
assert_eq!(stdout, "42\n");
|
||||
assert!(allocs >= 1, "expected at least one heap-Str allocation; got allocs={allocs}");
|
||||
assert_eq!(allocs, frees, "every heap-Str alloc must be freed; allocs={allocs}, frees={frees}");
|
||||
@@ -2616,7 +2616,7 @@ fn int_to_str_drop_balances_rc_stats() {
|
||||
#[test]
|
||||
fn str_field_in_adt_drops_heap_str_correctly() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("str_field_in_adt_heap.ail.json");
|
||||
build_and_run_with_rc_stats("str_field_in_adt_heap.ail");
|
||||
assert_eq!(stdout, "42\n");
|
||||
assert!(allocs >= 2, "expected ADT cell + heap-Str slab; got allocs={allocs}");
|
||||
assert_eq!(allocs, frees, "every RC slab must be freed; allocs={allocs}, frees={frees}");
|
||||
@@ -2631,7 +2631,7 @@ fn str_field_in_adt_drops_heap_str_correctly() {
|
||||
#[test]
|
||||
fn int_arg_to_effect_op_does_not_rc_track() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("int_to_print_int_borrow.ail.json");
|
||||
build_and_run_with_rc_stats("int_to_print_int_borrow.ail");
|
||||
assert_eq!(stdout, "7\n");
|
||||
assert_eq!(allocs, 0, "Int arg should not trigger any RC alloc; got allocs={allocs}");
|
||||
assert_eq!(frees, 0, "Int arg should not trigger any RC free; got frees={frees}");
|
||||
@@ -2649,7 +2649,7 @@ fn int_arg_to_effect_op_does_not_rc_track() {
|
||||
#[test]
|
||||
fn heap_str_repeated_print_balances_rc_stats() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("heap_str_repeated_print_borrow.ail.json");
|
||||
build_and_run_with_rc_stats("heap_str_repeated_print_borrow.ail");
|
||||
assert_eq!(stdout, "42\n42\n");
|
||||
assert_eq!(allocs, 1, "expected exactly one heap-Str slab; got allocs={allocs}");
|
||||
assert_eq!(frees, 1, "expected exactly one free; got frees={frees}");
|
||||
@@ -2665,7 +2665,7 @@ fn heap_str_repeated_print_balances_rc_stats() {
|
||||
#[test]
|
||||
fn bool_to_str_drop_balances_rc_stats() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("bool_to_str_drop_rc.ail.json");
|
||||
build_and_run_with_rc_stats("bool_to_str_drop_rc.ail");
|
||||
assert_eq!(stdout, "true\n");
|
||||
assert_eq!(allocs, 1, "expected exactly one heap-Str slab; got allocs={allocs}");
|
||||
assert_eq!(frees, 1, "expected exactly one free; got frees={frees}");
|
||||
@@ -2678,7 +2678,7 @@ fn bool_to_str_drop_balances_rc_stats() {
|
||||
/// "true" slab.
|
||||
#[test]
|
||||
fn bool_to_str_emits_true_branch() {
|
||||
let out = build_and_run("bool_to_str_drop_rc.ail.json");
|
||||
let out = build_and_run("bool_to_str_drop_rc.ail");
|
||||
assert_eq!(out, "true\n");
|
||||
}
|
||||
|
||||
@@ -2686,7 +2686,7 @@ fn bool_to_str_emits_true_branch() {
|
||||
/// content of `ailang_bool_to_str`'s "false" slab.
|
||||
#[test]
|
||||
fn bool_to_str_emits_false_branch() {
|
||||
let out = build_and_run("bool_to_str_smoke_false.ail.json");
|
||||
let out = build_and_run("bool_to_str_smoke_false.ail");
|
||||
assert_eq!(out, "false\n");
|
||||
}
|
||||
|
||||
@@ -2698,7 +2698,7 @@ fn bool_to_str_emits_false_branch() {
|
||||
#[test]
|
||||
fn str_clone_drop_balances_rc_stats() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("str_clone_drop_rc.ail.json");
|
||||
build_and_run_with_rc_stats("str_clone_drop_rc.ail");
|
||||
assert_eq!(stdout, "hello\n");
|
||||
assert_eq!(allocs, 1, "expected exactly one heap-Str clone slab; got allocs={allocs}");
|
||||
assert_eq!(frees, 1, "expected exactly one free; got frees={frees}");
|
||||
@@ -2716,7 +2716,7 @@ fn str_clone_drop_balances_rc_stats() {
|
||||
#[test]
|
||||
fn str_clone_cross_realisation_uniform_abi() {
|
||||
let (stdout, allocs, frees, live) =
|
||||
build_and_run_with_rc_stats("str_clone_cross_realisation.ail.json");
|
||||
build_and_run_with_rc_stats("str_clone_cross_realisation.ail");
|
||||
assert_eq!(stdout, "42\nabc\n");
|
||||
assert_eq!(allocs, 3, "expected one int_to_str slab + two str_clone slabs; got allocs={allocs}");
|
||||
assert_eq!(frees, 3, "expected three matching frees; got frees={frees}");
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! than seeing a bare "no instance" message.
|
||||
|
||||
use ailang_check::check_workspace;
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture(name: &str) -> PathBuf {
|
||||
@@ -19,7 +19,7 @@ fn fixture(name: &str) -> PathBuf {
|
||||
|
||||
#[test]
|
||||
fn eq_at_float_fires_float_aware_noinstance() {
|
||||
let ws = load_workspace(&fixture("eq_float_noinstance.ail.json")).expect("load");
|
||||
let ws = load_workspace(&fixture("eq_float_noinstance.ail")).expect("load");
|
||||
let diags = check_workspace(&ws);
|
||||
|
||||
assert!(!diags.is_empty(), "expected NoInstance diagnostic, got none");
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
use ailang_check::{check_workspace, monomorphise_workspace};
|
||||
use ailang_core::ast::Def;
|
||||
use ailang_core::hash::def_hash;
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
@@ -59,7 +59,7 @@ fn build_and_run(fixture: &str) -> String {
|
||||
|
||||
#[test]
|
||||
fn eq_ord_polymorphic_runs_end_to_end() {
|
||||
let stdout = build_and_run("eq_ord_polymorphic.ail.json");
|
||||
let stdout = build_and_run("eq_ord_polymorphic.ail");
|
||||
// Helper `at_most(3, 5)` at Int = true → 1
|
||||
// `at_most(true, false)` at Bool = false → 0
|
||||
// `at_most("abc", "abd")` at Str = true → 1
|
||||
@@ -70,7 +70,7 @@ fn eq_ord_polymorphic_runs_end_to_end() {
|
||||
|
||||
#[test]
|
||||
fn eq_ord_user_adt_runs_end_to_end() {
|
||||
let stdout = build_and_run("eq_ord_user_adt.ail.json");
|
||||
let stdout = build_and_run("eq_ord_user_adt.ail");
|
||||
// eq(MkIntBox 3, MkIntBox 3) = true → 1
|
||||
// eq(MkIntBox 3, MkIntBox 5) = false → 0
|
||||
// `io/print_int` emits one int per line; trimmed stdout is "1\n0".
|
||||
@@ -79,7 +79,7 @@ fn eq_ord_user_adt_runs_end_to_end() {
|
||||
|
||||
#[test]
|
||||
fn eq_ord_user_adt_eq_intbox_hash_stable() {
|
||||
let ws = load_workspace(&fixture_path("eq_ord_user_adt.ail.json")).expect("load");
|
||||
let ws = load_workspace(&fixture_path("eq_ord_user_adt.ail")).expect("load");
|
||||
let diags = check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "typecheck failed: {diags:#?}");
|
||||
let mono = monomorphise_workspace(&ws).expect("mono");
|
||||
|
||||
@@ -20,7 +20,7 @@ fn workspace_root() -> PathBuf {
|
||||
#[test]
|
||||
fn floats_example_prints_expected_stdout() {
|
||||
let root = workspace_root();
|
||||
let example = root.join("examples").join("floats.ail.json");
|
||||
let example = root.join("examples").join("floats.ail");
|
||||
assert!(example.exists(), "expected fixture at {:?}", example);
|
||||
|
||||
// Build via `cargo run -p ail -- build` to use the in-tree CLI.
|
||||
|
||||
@@ -134,22 +134,22 @@ fn check_ir_snapshot(example: &str, snapshot_name: &str) {
|
||||
|
||||
#[test]
|
||||
fn ir_snapshot_sum() {
|
||||
check_ir_snapshot("sum.ail.json", "sum.ll");
|
||||
check_ir_snapshot("sum.ail", "sum.ll");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ir_snapshot_max3() {
|
||||
check_ir_snapshot("max3.ail.json", "max3.ll");
|
||||
check_ir_snapshot("max3.ail", "max3.ll");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ir_snapshot_hello() {
|
||||
check_ir_snapshot("hello.ail.json", "hello.ll");
|
||||
check_ir_snapshot("hello.ail", "hello.ll");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ir_snapshot_list() {
|
||||
check_ir_snapshot("list.ail.json", "list.ll");
|
||||
check_ir_snapshot("list.ail", "list.ll");
|
||||
}
|
||||
|
||||
/// Guards workspace lowering (Iter 5c): the entry module `ws_main`
|
||||
@@ -158,5 +158,5 @@ fn ir_snapshot_list() {
|
||||
/// `@main` calls `@ail_ws_main_main`.
|
||||
#[test]
|
||||
fn ir_snapshot_ws_main() {
|
||||
check_ir_snapshot("ws_main.ail.json", "ws_main.ll");
|
||||
check_ir_snapshot("ws_main.ail", "ws_main.ll");
|
||||
}
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
|
||||
use ailang_core::ast::Def;
|
||||
use ailang_core::hash::def_hash;
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture_path() -> PathBuf {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.pop();
|
||||
d.pop();
|
||||
d.join("examples").join("mono_hash_pin_smoke.ail.json")
|
||||
d.join("examples").join("mono_hash_pin_smoke.ail")
|
||||
}
|
||||
|
||||
fn show_fixture_path() -> PathBuf {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.pop();
|
||||
d.pop();
|
||||
d.join("examples").join("show_mono_pin_smoke.ail.json")
|
||||
d.join("examples").join("show_mono_pin_smoke.ail")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -40,7 +40,7 @@ fn mono_pass_handles_recursive_fn_in_class_workspace() {
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src = workspace
|
||||
.join("examples")
|
||||
.join("test_mono_recursive_fn_bug.ail.json");
|
||||
.join("test_mono_recursive_fn_bug.ail");
|
||||
let tmp = std::env::temp_dir().join(format!(
|
||||
"ailang_mono_recursive_fn_{}",
|
||||
std::process::id()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use ailang_check::mono::{mono_target_key, MonoTarget};
|
||||
use ailang_core::ast::{Def, Type};
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture(name: &str) -> PathBuf {
|
||||
@@ -19,7 +19,7 @@ fn fixture(name: &str) -> PathBuf {
|
||||
|
||||
#[test]
|
||||
fn cmp_max_smoke_produces_both_mono_symbols_in_one_fixpoint() {
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail.json"))
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail"))
|
||||
.expect("workspace loads");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "typecheck diagnostics: {diags:?}");
|
||||
@@ -62,7 +62,7 @@ fn cmp_max_smoke_produces_both_mono_symbols_in_one_fixpoint() {
|
||||
#[test]
|
||||
fn collect_mono_targets_emits_free_fn_target_for_cmp_max_at_int() {
|
||||
use ailang_check::mono::collect_mono_targets;
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail.json")).expect("workspace loads");
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail")).expect("workspace loads");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "typecheck diagnostics: {diags:?}");
|
||||
let env = ailang_check::build_check_env(&ws);
|
||||
@@ -93,7 +93,7 @@ fn cmp_max_smoke_runs_end_to_end() {
|
||||
use std::process::Command;
|
||||
let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let workspace = manifest_dir.parent().unwrap().parent().unwrap();
|
||||
let src = workspace.join("examples").join("cmp_max_smoke.ail.json");
|
||||
let src = workspace.join("examples").join("cmp_max_smoke.ail");
|
||||
let tmp = std::env::temp_dir().join(format!(
|
||||
"ailang_cmp_max_smoke_{}",
|
||||
std::process::id()
|
||||
@@ -123,7 +123,7 @@ fn workspace_with_only_poly_free_fn_and_no_classes_still_monomorphises() {
|
||||
// the predicate to also include `Def::Fn` with `Type::Forall`
|
||||
// as a specialisable target — which makes the predicate true
|
||||
// for any workspace with poly free fns (regardless of classes).
|
||||
let ws = load_workspace(&fixture("poly_id.ail.json")).expect("workspace loads");
|
||||
let ws = load_workspace(&fixture("poly_id.ail")).expect("workspace loads");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "typecheck diagnostics: {diags:?}");
|
||||
let post_mono = ailang_check::monomorphise_workspace(&ws).expect("mono green");
|
||||
@@ -144,7 +144,7 @@ fn workspace_with_only_poly_free_fn_and_no_classes_still_monomorphises() {
|
||||
|
||||
#[test]
|
||||
fn rewrite_mono_calls_rewrites_bare_poly_free_fn_to_mono_symbol() {
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail.json")).expect("workspace loads");
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail")).expect("workspace loads");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "typecheck diagnostics: {diags:?}");
|
||||
let post_mono = ailang_check::monomorphise_workspace(&ws).expect("mono green");
|
||||
@@ -170,7 +170,7 @@ fn rewrite_mono_calls_rewrites_bare_poly_free_fn_to_mono_symbol() {
|
||||
#[test]
|
||||
fn synthesise_mono_fn_free_fn_arm_substitutes_rigid_vars() {
|
||||
use ailang_check::mono::synthesise_mono_fn_for_free_fn;
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail.json")).expect("workspace loads");
|
||||
let ws = load_workspace(&fixture("cmp_max_smoke.ail")).expect("workspace loads");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "typecheck diagnostics: {diags:?}");
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ fn examples_dir() -> PathBuf {
|
||||
/// `env.module_types` and validates the ctor by name there.
|
||||
#[test]
|
||||
fn mono_pass_handles_xmod_ctor_pattern() {
|
||||
let entry = examples_dir().join("test_mono_ctor_main.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_mono_ctor_main.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
|
||||
// Pre-condition: the workspace typechecks cleanly. The bug is
|
||||
// localised to the mono pass; the typecheck path does not have it.
|
||||
|
||||
@@ -57,7 +57,7 @@ fn mono_pass_handles_qualified_cross_module_reference() {
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src = workspace
|
||||
.join("examples")
|
||||
.join("test_mono_imports_main.ail.json");
|
||||
.join("test_mono_imports_main.ail");
|
||||
let tmp = std::env::temp_dir().join(format!(
|
||||
"ailang_mono_xmod_qualified_{}",
|
||||
std::process::id()
|
||||
|
||||
@@ -44,7 +44,7 @@ fn run_ail_check_json(entry: &str) -> std::process::Output {
|
||||
/// `ambiguous-method-resolution` and names both candidate classes.
|
||||
#[test]
|
||||
fn mq3_two_show_ambiguous_fires_ambiguous_method_resolution() {
|
||||
let out = run_ail_check_json("mq3_two_show_ambiguous.ail.json");
|
||||
let out = run_ail_check_json("mq3_two_show_ambiguous.ail");
|
||||
assert!(
|
||||
!out.status.success(),
|
||||
"expected check to reject ambiguous dispatch; stdout={} stderr={}",
|
||||
@@ -76,7 +76,7 @@ fn mq3_two_show_ambiguous_fires_ambiguous_method_resolution() {
|
||||
/// workspace as the ambiguous fixture. Typecheck succeeds.
|
||||
#[test]
|
||||
fn mq3_two_show_qualified_resolves_clean() {
|
||||
let out = run_ail_check_json("mq3_two_show_qualified.ail.json");
|
||||
let out = run_ail_check_json("mq3_two_show_qualified.ail");
|
||||
assert!(
|
||||
out.status.success(),
|
||||
"expected check to succeed with explicit qualifier; stdout={} stderr={}",
|
||||
@@ -92,7 +92,7 @@ fn mq3_two_show_qualified_resolves_clean() {
|
||||
/// LLM-author sees the shadow.
|
||||
#[test]
|
||||
fn mq3_class_eq_vs_fn_eq_fn_wins_with_warning() {
|
||||
let out = run_ail_check_json("mq3_class_eq_vs_fn_eq.ail.json");
|
||||
let out = run_ail_check_json("mq3_class_eq_vs_fn_eq.ail");
|
||||
assert!(
|
||||
out.status.success(),
|
||||
"expected check to succeed (fn wins); stdout={} stderr={}",
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
//! the negative case — confusing diagnostic, hard to bisect.
|
||||
|
||||
use ailang_check::check_workspace;
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture_path() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../examples")
|
||||
.join("show_no_instance.ail.json")
|
||||
.join("show_no_instance.ail")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//! the mono symbols are produced.
|
||||
|
||||
use ailang_check::{check_workspace, monomorphise_workspace};
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture(name: &str) -> PathBuf {
|
||||
@@ -38,7 +38,7 @@ fn mono_symbol_names(workspace_name: &str) -> Vec<String> {
|
||||
|
||||
#[test]
|
||||
fn ne_at_int_produces_mono_symbol() {
|
||||
let names = mono_symbol_names("ne_at_int_smoke.ail.json");
|
||||
let names = mono_symbol_names("ne_at_int_smoke.ail");
|
||||
assert!(
|
||||
names.iter().any(|n| n == "ne__Int"),
|
||||
"expected ne__Int in workspace, found: {names:#?}"
|
||||
@@ -47,7 +47,7 @@ fn ne_at_int_produces_mono_symbol() {
|
||||
|
||||
#[test]
|
||||
fn lt_at_int_produces_mono_symbol() {
|
||||
let names = mono_symbol_names("lt_at_int_smoke.ail.json");
|
||||
let names = mono_symbol_names("lt_at_int_smoke.ail");
|
||||
assert!(
|
||||
names.iter().any(|n| n == "lt__Int"),
|
||||
"expected lt__Int in workspace, found: {names:#?}"
|
||||
@@ -56,7 +56,7 @@ fn lt_at_int_produces_mono_symbol() {
|
||||
|
||||
#[test]
|
||||
fn le_at_str_produces_mono_symbol() {
|
||||
let names = mono_symbol_names("le_at_str_smoke.ail.json");
|
||||
let names = mono_symbol_names("le_at_str_smoke.ail");
|
||||
assert!(
|
||||
names.iter().any(|n| n == "le__Str"),
|
||||
"expected le__Str in workspace, found: {names:#?}"
|
||||
@@ -65,7 +65,7 @@ fn le_at_str_produces_mono_symbol() {
|
||||
|
||||
#[test]
|
||||
fn gt_at_bool_produces_mono_symbol() {
|
||||
let names = mono_symbol_names("gt_at_bool_smoke.ail.json");
|
||||
let names = mono_symbol_names("gt_at_bool_smoke.ail");
|
||||
assert!(
|
||||
names.iter().any(|n| n == "gt__Bool"),
|
||||
"expected gt__Bool in workspace, found: {names:#?}"
|
||||
@@ -74,7 +74,7 @@ fn gt_at_bool_produces_mono_symbol() {
|
||||
|
||||
#[test]
|
||||
fn ge_at_int_produces_mono_symbol() {
|
||||
let names = mono_symbol_names("ge_at_int_smoke.ail.json");
|
||||
let names = mono_symbol_names("ge_at_int_smoke.ail");
|
||||
assert!(
|
||||
names.iter().any(|n| n == "ge__Int"),
|
||||
"expected ge__Int in workspace, found: {names:#?}"
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
//! function values inside `InstanceMethod.body`).
|
||||
|
||||
use ailang_core::ast::{Def, Term};
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture_path() -> PathBuf {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.pop();
|
||||
d.pop();
|
||||
d.join("examples").join("show_print_smoke.ail.json")
|
||||
d.join("examples").join("show_print_smoke.ail")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -45,6 +45,23 @@ fn list_json_fixtures() -> Vec<PathBuf> {
|
||||
paths
|
||||
}
|
||||
|
||||
fn list_ail_fixtures() -> Vec<PathBuf> {
|
||||
let dir = examples_dir();
|
||||
let mut paths: Vec<PathBuf> = std::fs::read_dir(&dir)
|
||||
.unwrap_or_else(|e| panic!("read_dir({}): {e}", dir.display()))
|
||||
.filter_map(|entry| entry.ok())
|
||||
.map(|e| e.path())
|
||||
.filter(|p| {
|
||||
p.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.map(|n| n.ends_with(".ail"))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.collect();
|
||||
paths.sort();
|
||||
paths
|
||||
}
|
||||
|
||||
fn strip_trailing_newlines(mut v: Vec<u8>) -> Vec<u8> {
|
||||
while v.last() == Some(&b'\n') {
|
||||
v.pop();
|
||||
@@ -144,3 +161,110 @@ fn cli_render_then_parse_preserves_canonical_bytes_on_every_fixture() {
|
||||
}
|
||||
eprintln!("CLI roundtrip ok for {passed} fixtures");
|
||||
}
|
||||
|
||||
/// CLI-pipeline idempotency (post-form-a-default-authoring §C3): for
|
||||
/// every `.ail` fixture, the user-facing pipeline
|
||||
/// `ail parse <ail> | ail render | ail parse` is byte-identical
|
||||
/// to direct `ail parse <ail>`. Pins drift internal tests cannot see.
|
||||
#[test]
|
||||
fn cli_parse_then_render_then_parse_is_idempotent() {
|
||||
let fixtures = list_ail_fixtures();
|
||||
assert!(
|
||||
!fixtures.is_empty(),
|
||||
"no .ail fixtures found under {}",
|
||||
examples_dir().display()
|
||||
);
|
||||
|
||||
let tmpdir = tempfile::TempDir::new().expect("create tempdir");
|
||||
let mut checked = 0usize;
|
||||
let mut failures = Vec::<String>::new();
|
||||
|
||||
for ail_path in &fixtures {
|
||||
// Direct parse → JSON tempfile.
|
||||
let json1 = tmpdir.path().join(format!("v1_{checked}.ail.json"));
|
||||
let parse1 = Command::new(ail_bin())
|
||||
.args([
|
||||
"parse",
|
||||
ail_path.to_str().unwrap(),
|
||||
"-o",
|
||||
json1.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.expect("spawn ail parse #1");
|
||||
if !parse1.status.success() {
|
||||
failures.push(format!(
|
||||
"{}: first ail parse exit={:?}\nstderr: {}",
|
||||
ail_path.display(),
|
||||
parse1.status.code(),
|
||||
String::from_utf8_lossy(&parse1.stderr),
|
||||
));
|
||||
checked += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Render that JSON → .ail tempfile.
|
||||
let ail_round = tmpdir.path().join(format!("round_{checked}.ail"));
|
||||
let rendered = Command::new(ail_bin())
|
||||
.args(["render", json1.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("spawn ail render");
|
||||
if !rendered.status.success() {
|
||||
failures.push(format!(
|
||||
"{}: ail render exit={:?}\nstderr: {}",
|
||||
ail_path.display(),
|
||||
rendered.status.code(),
|
||||
String::from_utf8_lossy(&rendered.stderr),
|
||||
));
|
||||
checked += 1;
|
||||
continue;
|
||||
}
|
||||
std::fs::write(&ail_round, &rendered.stdout)
|
||||
.expect("write ail_round tempfile");
|
||||
|
||||
// Re-parse → second JSON tempfile.
|
||||
let json2 = tmpdir.path().join(format!("v2_{checked}.ail.json"));
|
||||
let parse2 = Command::new(ail_bin())
|
||||
.args([
|
||||
"parse",
|
||||
ail_round.to_str().unwrap(),
|
||||
"-o",
|
||||
json2.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.expect("spawn ail parse #2");
|
||||
if !parse2.status.success() {
|
||||
failures.push(format!(
|
||||
"{}: second ail parse exit={:?}\nstderr: {}",
|
||||
ail_path.display(),
|
||||
parse2.status.code(),
|
||||
String::from_utf8_lossy(&parse2.stderr),
|
||||
));
|
||||
checked += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assert the two canonical JSONs are byte-equal.
|
||||
let b1 = std::fs::read(&json1).expect("read json1");
|
||||
let b2 = std::fs::read(&json2).expect("read json2");
|
||||
if b1 != b2 {
|
||||
let s1 = String::from_utf8_lossy(&b1).into_owned();
|
||||
let s2 = String::from_utf8_lossy(&b2).into_owned();
|
||||
failures.push(format!(
|
||||
"{}: CLI parse|render|parse non-idempotent.\n v1: {s1}\n v2: {s2}",
|
||||
ail_path.display(),
|
||||
));
|
||||
}
|
||||
checked += 1;
|
||||
}
|
||||
|
||||
if !failures.is_empty() {
|
||||
panic!(
|
||||
"CLI parse|render|parse non-idempotent on {} of {} fixtures:\n{}",
|
||||
failures.len(),
|
||||
checked,
|
||||
failures.join("\n\n")
|
||||
);
|
||||
}
|
||||
assert!(checked > 0, "no .ail fixtures found");
|
||||
eprintln!("CLI parse|render|parse idempotent for {checked} fixtures");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//! post-mono module.
|
||||
|
||||
use ailang_core::ast::Def;
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use ailang_check::{check_workspace, monomorphise_workspace};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -14,7 +14,7 @@ fn fixture_path() -> PathBuf {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.pop();
|
||||
d.pop();
|
||||
d.join("examples").join("show_mono_pin_smoke.ail.json")
|
||||
d.join("examples").join("show_mono_pin_smoke.ail")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//! and how to declare their own instance for a user type.
|
||||
|
||||
use ailang_check::check_workspace;
|
||||
use ailang_core::workspace::load_workspace;
|
||||
use ailang_surface::load_workspace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn fixture(name: &str) -> PathBuf {
|
||||
@@ -18,7 +18,7 @@ fn fixture(name: &str) -> PathBuf {
|
||||
|
||||
#[test]
|
||||
fn print_on_fn_type_fires_show_aware_no_instance() {
|
||||
let ws = load_workspace(&fixture("show_no_instance.ail.json")).expect("load");
|
||||
let ws = load_workspace(&fixture("show_no_instance.ail")).expect("load");
|
||||
let diags = check_workspace(&ws);
|
||||
|
||||
assert!(
|
||||
|
||||
@@ -55,7 +55,7 @@ fn build_and_run(fixture: &str) -> String {
|
||||
|
||||
#[test]
|
||||
fn print_primitives_smoke_runs_end_to_end() {
|
||||
let stdout = build_and_run("show_print_smoke.ail.json");
|
||||
let stdout = build_and_run("show_print_smoke.ail");
|
||||
// print 42 → "42\n" (int_to_str + puts)
|
||||
// print true → "true\n" (bool_to_str + puts)
|
||||
// print "hello" → "hello\n" (str_clone + puts)
|
||||
@@ -67,7 +67,7 @@ fn print_primitives_smoke_runs_end_to_end() {
|
||||
|
||||
#[test]
|
||||
fn print_user_adt_runs_end_to_end() {
|
||||
let stdout = build_and_run("show_user_adt.ail.json");
|
||||
let stdout = build_and_run("show_user_adt.ail");
|
||||
// print (MkIntBox 7) → "7\n" (via user instance prelude.Show
|
||||
// IntBox that unwraps via match + int_to_str).
|
||||
assert_eq!(stdout, "7", "got: {stdout:?}");
|
||||
|
||||
@@ -25,8 +25,8 @@ fn examples_dir() -> PathBuf {
|
||||
/// the call site.
|
||||
#[test]
|
||||
fn class_method_is_in_module_globals() {
|
||||
let entry = examples_dir().join("test_22b2_class_method_lookup.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_class_method_lookup.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace must load");
|
||||
let globals = ailang_check::build_module_globals(&ws)
|
||||
.expect("globals build");
|
||||
@@ -59,8 +59,8 @@ fn class_method_is_in_module_globals() {
|
||||
/// "Str"` with empty effects.
|
||||
#[test]
|
||||
fn class_method_entry_carries_full_metadata() {
|
||||
let entry = examples_dir().join("test_22b2_class_method_lookup.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_class_method_lookup.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace must load");
|
||||
let globals = ailang_check::build_module_globals(&ws)
|
||||
.expect("globals build");
|
||||
@@ -144,8 +144,8 @@ fn class_method_entry_carries_full_metadata() {
|
||||
/// which dictionary to thread.
|
||||
#[test]
|
||||
fn fn_calling_class_method_without_declared_constraint_fires_missing_constraint() {
|
||||
let entry = examples_dir().join("test_22b2_missing_constraint.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_missing_constraint.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -164,8 +164,8 @@ fn fn_calling_class_method_without_declared_constraint_fires_missing_constraint(
|
||||
/// well-formed inside the body.
|
||||
#[test]
|
||||
fn fn_with_correct_constraint_typechecks_green() {
|
||||
let entry = examples_dir().join("test_22b2_constraint_declared.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_constraint_declared.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -186,8 +186,8 @@ fn fn_with_correct_constraint_typechecks_green() {
|
||||
#[test]
|
||||
fn fn_calling_superclass_method_via_subclass_constraint_typechecks_green() {
|
||||
let entry = examples_dir()
|
||||
.join("test_22b2_constraint_declared_via_superclass.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
.join("test_22b2_constraint_declared_via_superclass.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -207,8 +207,8 @@ fn fn_calling_superclass_method_via_subclass_constraint_typechecks_green() {
|
||||
#[test]
|
||||
fn fn_with_superclass_constraint_calling_subclass_method_fires_missing_constraint() {
|
||||
let entry = examples_dir()
|
||||
.join("test_22b2_missing_constraint_subclass.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
.join("test_22b2_missing_constraint_subclass.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -230,8 +230,8 @@ fn fn_with_superclass_constraint_calling_subclass_method_fires_missing_constrain
|
||||
/// the workspace.
|
||||
#[test]
|
||||
fn fn_calling_class_method_at_type_without_instance_fires_no_instance() {
|
||||
let entry = examples_dir().join("test_22b2_no_instance.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_no_instance.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -253,8 +253,8 @@ fn fn_calling_class_method_at_type_without_instance_fires_no_instance() {
|
||||
/// `tshow 42` with `instance Show Int` declared in the same workspace.
|
||||
#[test]
|
||||
fn fn_calling_class_method_at_type_with_instance_typechecks_green() {
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -277,8 +277,8 @@ fn fn_calling_class_method_at_type_with_instance_typechecks_green() {
|
||||
/// `class TShow a`; B = `test_22b2_xmod_no_instance` calls `tshow 42`.
|
||||
#[test]
|
||||
fn cross_module_class_method_resolves_and_fires_no_instance() {
|
||||
let entry = examples_dir().join("test_22b2_xmod_no_instance.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_xmod_no_instance.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
let codes: Vec<&str> = diagnostics.iter().map(|d| d.code.as_str()).collect();
|
||||
@@ -307,8 +307,8 @@ fn cross_module_class_method_resolves_and_fires_no_instance() {
|
||||
/// declares `forall a. (a) -> Str` and calls `tshow x`.
|
||||
#[test]
|
||||
fn cross_module_polymorphic_fn_without_constraint_fires_missing_constraint() {
|
||||
let entry = examples_dir().join("test_22b2_xmod_missing_constraint.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_xmod_missing_constraint.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -329,8 +329,8 @@ fn cross_module_polymorphic_fn_without_constraint_fires_missing_constraint() {
|
||||
/// `test_22b2_xmod_classmod`; B = `test_22b2_xmod_instance_present`.
|
||||
#[test]
|
||||
fn cross_module_instance_satisfies_concrete_call() {
|
||||
let entry = examples_dir().join("test_22b2_xmod_instance_present.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_xmod_instance_present.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
assert!(
|
||||
@@ -352,8 +352,8 @@ fn cross_module_instance_satisfies_concrete_call() {
|
||||
/// both ill-formed in the same way; both must surface.
|
||||
#[test]
|
||||
fn two_fns_each_missing_constraint_produce_two_diagnostics() {
|
||||
let entry = examples_dir().join("test_22b2_two_fns_missing_constraint.ail.json");
|
||||
let ws = ailang_core::workspace::load_workspace(&entry)
|
||||
let entry = examples_dir().join("test_22b2_two_fns_missing_constraint.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry)
|
||||
.expect("workspace loads");
|
||||
let diagnostics = ailang_check::check_workspace(&ws);
|
||||
let mc: Vec<&ailang_check::Diagnostic> = diagnostics
|
||||
|
||||
@@ -20,8 +20,8 @@ fn examples_dir() -> PathBuf {
|
||||
fn monomorphise_workspace_is_identity_on_class_free_workspace() {
|
||||
// Pick any class-free fixture; `examples/hello.ail.json` is
|
||||
// the canonical class-free smoke test.
|
||||
let entry = examples_dir().join("hello.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("hello.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
@@ -29,7 +29,7 @@ fn monomorphise_workspace_is_identity_on_class_free_workspace() {
|
||||
.expect("mono on class-free workspace");
|
||||
|
||||
// Module set unchanged.
|
||||
let before = ailang_core::load_workspace(&examples_dir().join("hello.ail.json"))
|
||||
let before = ailang_surface::load_workspace(&examples_dir().join("hello.ail"))
|
||||
.expect("re-load");
|
||||
assert_eq!(
|
||||
ws.modules.keys().collect::<Vec<_>>(),
|
||||
@@ -63,8 +63,8 @@ fn monomorphise_workspace_is_identity_on_class_free_workspace() {
|
||||
/// (correctly) materialises into `tshow__Int`.
|
||||
#[test]
|
||||
fn monomorphise_workspace_is_identity_when_no_concrete_call_sites() {
|
||||
let entry = examples_dir().join("test_22b3_no_call_sites.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b3_no_call_sites.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
@@ -72,7 +72,7 @@ fn monomorphise_workspace_is_identity_when_no_concrete_call_sites() {
|
||||
.expect("mono on class-present workspace");
|
||||
|
||||
// Module set unchanged.
|
||||
let before = ailang_core::load_workspace(&entry).expect("re-load");
|
||||
let before = ailang_surface::load_workspace(&entry).expect("re-load");
|
||||
assert_eq!(
|
||||
ws_after.modules.keys().collect::<Vec<_>>(),
|
||||
before.modules.keys().collect::<Vec<_>>(),
|
||||
@@ -120,8 +120,8 @@ fn mono_symbol_primitive_types_use_surface_form() {
|
||||
fn collect_mono_targets_single_concrete_call_site() {
|
||||
use ailang_check::mono::collect_mono_targets;
|
||||
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
@@ -376,8 +376,8 @@ fn synthesise_mono_fn_zero_arg_method_uses_body_verbatim() {
|
||||
/// dedup contract — the pass must not emit one FnDef per call site.
|
||||
#[test]
|
||||
fn fixpoint_dedupes_repeated_calls_at_same_type() {
|
||||
let entry = examples_dir().join("test_22b3_dup_call_sites.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b3_dup_call_sites.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
@@ -416,8 +416,8 @@ fn fixpoint_dedupes_repeated_calls_at_same_type() {
|
||||
/// body).
|
||||
#[test]
|
||||
fn fixpoint_handles_chained_class_method_calls() {
|
||||
let entry = examples_dir().join("test_22b3_chained_calls.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b3_chained_calls.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
@@ -480,8 +480,8 @@ fn fixpoint_handles_chained_class_method_calls() {
|
||||
fn rewrite_walker_skips_locally_shadowed_class_method() {
|
||||
use ailang_core::ast::{Def, Term};
|
||||
|
||||
let entry = examples_dir().join("test_22b3_shadow_class_method.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b3_shadow_class_method.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
// mq.3: this fixture intentionally shadows the class method `tshow`
|
||||
// with a local `let show = "shadow"`, which fires the new
|
||||
@@ -570,8 +570,8 @@ fn rewrite_walker_skips_locally_shadowed_class_method() {
|
||||
/// placement contract: the synthesised FnDef lives in B, not A.
|
||||
#[test]
|
||||
fn rewrite_uses_qualified_name_for_cross_module_call_site() {
|
||||
let entry = examples_dir().join("test_22b2_xmod_instance_present.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b2_xmod_instance_present.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
@@ -624,8 +624,8 @@ fn rewrite_uses_qualified_name_for_cross_module_call_site() {
|
||||
/// be ambiguous between mono-pass bug and 22b.2 typecheck bug.
|
||||
#[test]
|
||||
fn synthetic_fixture_typechecks_clean() {
|
||||
let entry = examples_dir().join("test_22b3_mono_synthetic.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b3_mono_synthetic.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
}
|
||||
@@ -641,7 +641,7 @@ fn synthetic_fixture_runs_and_prints_five() {
|
||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let ail_bin = std::env::var("CARGO_BIN_EXE_ail")
|
||||
.expect("CARGO_BIN_EXE_ail set by cargo test");
|
||||
let fixture = examples_dir().join("test_22b3_mono_synthetic.ail.json");
|
||||
let fixture = examples_dir().join("test_22b3_mono_synthetic.ail");
|
||||
|
||||
let tmp = manifest_dir.join("target").join(format!(
|
||||
"test_22b3_synthetic_{}", std::process::id()
|
||||
@@ -674,8 +674,8 @@ fn synthetic_fixture_runs_and_prints_five() {
|
||||
/// of `tshow`.
|
||||
#[test]
|
||||
fn rewrite_replaces_class_method_var_with_mono_symbol_same_module() {
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail");
|
||||
let ws = ailang_surface::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
|
||||
@@ -53,6 +53,6 @@ fn build_and_run(example: &str) -> String {
|
||||
/// `lib.rs:2316`) fall through.
|
||||
#[test]
|
||||
fn user_class_instance_over_user_adt_builds_and_runs() {
|
||||
let stdout = build_and_run("test_22c_user_class_e2e.ail.json");
|
||||
let stdout = build_and_run("test_22c_user_class_e2e.ail");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user