iter 22b.3.1: fix — quality-review (doc reframe + class-present test)
This commit is contained in:
@@ -47,3 +47,49 @@ fn monomorphise_workspace_is_identity_on_class_free_workspace() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Property: the Task 1 skeleton's class-present branch is also a
|
||||
/// no-op. The fixture has a `Def::Class` and a `Def::Instance` (so
|
||||
/// the early-out does NOT fire) but no concrete class-method call
|
||||
/// sites yet wired through the pipeline; under the skeleton, the
|
||||
/// fall-through `Ok(ws.clone())` must preserve every module's
|
||||
/// canonical hash.
|
||||
///
|
||||
/// NOTE: this test will need updating in Task 5 once the skeleton
|
||||
/// is replaced with the real fixpoint — at that point synth fns
|
||||
/// will be appended to the `defining_module`, breaking module-hash
|
||||
/// equality on that module by design. The test as written
|
||||
/// guarantees the Task 1 contract and catches accidental partial
|
||||
/// rewrites landed before Task 5.
|
||||
#[test]
|
||||
fn monomorphise_workspace_is_identity_when_no_concrete_call_sites() {
|
||||
// `test_22b2_instance_present.ail.json` has `class Show` +
|
||||
// `instance Show Int` and typechecks cleanly; reused across
|
||||
// 22b.2 tests so its shape is stable.
|
||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||
let diags = ailang_check::check_workspace(&ws);
|
||||
assert!(diags.is_empty(), "fixture must typecheck: {:?}", diags);
|
||||
|
||||
let ws_after = ailang_check::monomorphise_workspace(&ws)
|
||||
.expect("mono on class-present workspace");
|
||||
|
||||
// Module set unchanged.
|
||||
let before = ailang_core::load_workspace(&entry).expect("re-load");
|
||||
assert_eq!(
|
||||
ws_after.modules.keys().collect::<Vec<_>>(),
|
||||
before.modules.keys().collect::<Vec<_>>(),
|
||||
"module set must be identical"
|
||||
);
|
||||
// Each module hashes byte-identical (skeleton clones unchanged).
|
||||
for (mname, m) in &ws_after.modules {
|
||||
let before_m = &before.modules[mname];
|
||||
let h_after = ailang_core::module_hash(m);
|
||||
let h_before = ailang_core::module_hash(before_m);
|
||||
assert_eq!(
|
||||
h_after, h_before,
|
||||
"class-present module `{}` must hash-identical through Task 1 skeleton",
|
||||
mname
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
//! Iter 22b.3: workspace monomorphisation pass.
|
||||
//!
|
||||
//! Slots into the build pipeline after [`crate::lift_letrecs`] and
|
||||
//! before `ailang_codegen::lower_workspace_with_alloc`. The pass
|
||||
//! consumes the workspace's typeclass [`Registry`] and the per-
|
||||
//! before `ailang_codegen::lower_workspace_with_alloc`.
|
||||
//!
|
||||
//! ## What Task 1 delivers
|
||||
//!
|
||||
//! Skeleton only. [`monomorphise_workspace`] is a no-op pass with
|
||||
//! two branches:
|
||||
//!
|
||||
//! - Class-free workspaces (no [`Def::Class`] / [`Def::Instance`]
|
||||
//! anywhere) take the early-out and the input workspace is
|
||||
//! cloned unchanged.
|
||||
//! - Class-present workspaces fall through to a second
|
||||
//! `Ok(ws.clone())`, dead-equivalent today but the placeholder
|
||||
//! for the real fixpoint body that later tasks will fill in.
|
||||
//!
|
||||
//! Both branches return a byte-identical workspace clone, so
|
||||
//! `module_hash` is preserved end-to-end through the pass at this
|
||||
//! stage of the iteration.
|
||||
//!
|
||||
//! ## Planned (later tasks in iter 22b.3)
|
||||
//!
|
||||
//! See `docs/plans/2026-05-09-22b3-monomorphisation.md` for the
|
||||
//! full task list. The eventual contract is for the pass to
|
||||
//! consume the workspace's typeclass [`Registry`] and the per-
|
||||
//! module class-method tables (already populated by
|
||||
//! [`crate::check_in_workspace`]) and produces a workspace with:
|
||||
//! [`crate::check_in_workspace`]) and produce a workspace with:
|
||||
//!
|
||||
//! 1. Synthesised [`Def::Fn`] entries — one per unique
|
||||
//! `(class, method, type-hash)` triple observed at any
|
||||
@@ -20,16 +41,15 @@
|
||||
//! preserved verbatim — codegen ignores them, but downstream
|
||||
//! tooling (e.g. `ail describe`) may still consult them.
|
||||
//!
|
||||
//! Class-free workspaces are byte-identical through the pass:
|
||||
//! the early-out check at the top of [`monomorphise_workspace`]
|
||||
//! returns the input clone untouched.
|
||||
//! ## Symbol-hashing invariant (eventual-state)
|
||||
//!
|
||||
//! ## Symbol-hashing invariant
|
||||
//!
|
||||
//! Synthesised FnDefs are post-typecheck artefacts. They do NOT
|
||||
//! enter `CheckedModule.symbols` (built from the original module
|
||||
//! at typecheck time and used by `ail diff` / `ail manifest`).
|
||||
//! Same convention as [`crate::lift_letrecs`].
|
||||
//! Once the synthesis body lands, synthesised FnDefs will be
|
||||
//! post-typecheck artefacts. They will NOT enter
|
||||
//! `CheckedModule.symbols` (built from the original module at
|
||||
//! typecheck time and used by `ail diff` / `ail manifest`). Same
|
||||
//! convention as [`crate::lift_letrecs`]. Documented here ahead of
|
||||
//! the implementation so the constraint is visible to anyone
|
||||
//! extending the skeleton.
|
||||
|
||||
use ailang_core::ast::Def;
|
||||
use ailang_core::workspace::Workspace;
|
||||
|
||||
Reference in New Issue
Block a user