Files
AILang/crates/ailang-check/tests/show_dispatch_pin.rs
T
Brummel 3286117605 iter 24.2: class Show + 4 primitive instances + 22b TShow migration
Ships class Show a where show : (a borrow) -> Str in the prelude
plus primitive Show Int / Bool / Str / Float instances. Each
instance body is a single-application lambda invoking the
corresponding runtime primitive (int_to_str, bool_to_str,
str_clone, float_to_str) — first prelude instance bodies to call
runtime primitives directly. Float is included in Show (unlike
Eq/Ord) because textual representation is well-defined modulo the
NaN-spelling caveat at DESIGN.md §Float semantics.

The 22b typeclass test corpus is migrated preemptively: 21 fixture
files and 6 consumer files (typeclass_22b{2,3}.rs +
hash.rs ct4 pin + workspace.rs iter22b1 tests + the
instance_present.prose.txt snapshot) rename class Show / show
to class TShow / tshow, analogous to the existing TEq/TOrd
convention. Migration runs before the prelude additions so the
workspace stays green throughout.

Three new tests pin the post-mono shape: show_mono_synthesis.rs
(existence of show__Int/Bool/Str/Float as Def::Fn entries in the
prelude post-mono module), show_dispatch_pin.rs (bare show and
tshow both Step-2 singletons workspace-globally),
mono_hash_stability.rs::primitive_show_mono_symbol_hashes_stay_bit_identical
(body hashes pinned for the 4 new mono symbols).

DESIGN.md §Prelude (built-in) classes drops Show from the
deferred-features list and appends a milestone-24 paragraph
naming the class signature + the 4 instances + the body shape.
print rewire stays deferred to iter 24.3.

Tests: 552 passed (was 548 + 4 new). bench/compile_check +
bench/cross_lang exit 0. bench/check exits 1 on the recurring
noise envelope per the conservative-call lineage.
2026-05-13 03:31:40 +02:00

72 lines
2.6 KiB
Rust

//! Singleton dispatch pin for milestone 24.2's Show class.
//!
//! Asserts that with `prelude.Show` shipping `show` and a user `TShow`
//! shipping `tshow`, the bare method-name dispatcher resolves each via
//! Step-2 singleton (each method has exactly one candidate class globally).
use ailang_check::{build_check_env, check_workspace};
use ailang_core::workspace::load_workspace;
use std::path::PathBuf;
fn fixture_dir() -> PathBuf {
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.pop();
d.pop();
d.join("examples")
}
#[test]
fn bare_show_routes_to_prelude_show_via_singleton() {
// Workspace = auto-loaded prelude (containing class Show) plus a
// non-prelude entry that has zero `Show` declarations of its own.
// Asserts: env.method_to_candidate_classes["show"] == {"prelude.Show"}
// (a singleton), so Step-2 of resolve_method_dispatch resolves bare
// "show" without needing Steps 3-4.
let ws_path = fixture_dir().join("show_mono_pin_smoke.ail.json");
let ws = load_workspace(&ws_path).expect("workspace loads");
let diags = check_workspace(&ws);
assert!(diags.is_empty(), "typecheck diagnostics: {diags:#?}");
let env = build_check_env(&ws);
let candidates = env
.method_to_candidate_classes
.get("show")
.expect("method 'show' has candidates");
assert_eq!(
candidates.len(),
1,
"post-24.2-migration, 'show' has exactly one candidate class globally: got {candidates:?}"
);
assert!(
candidates.iter().any(|c| c == "prelude.Show"),
"candidates do not include prelude.Show: {candidates:?}"
);
}
#[test]
fn bare_tshow_routes_to_user_tshow_via_singleton() {
// Workspace = auto-loaded prelude + the migrated 22b1_dup_classmod
// (which now declares class TShow with method tshow).
// Asserts: env.method_to_candidate_classes["tshow"] has exactly one
// candidate (the user TShow), workspace-globally.
let ws_path = fixture_dir().join("test_22b1_dup_classmod.ail.json");
let ws = load_workspace(&ws_path).expect("workspace loads");
let diags = check_workspace(&ws);
assert!(diags.is_empty(), "typecheck diagnostics: {diags:#?}");
let env = build_check_env(&ws);
let candidates = env
.method_to_candidate_classes
.get("tshow")
.expect("method 'tshow' has candidates");
assert_eq!(
candidates.len(),
1,
"post-22b-migration, 'tshow' is owned by exactly one class globally: got {candidates:?}"
);
assert!(
candidates.iter().any(|c| c.ends_with(".TShow")),
"candidates do not include a *.TShow class: {candidates:?}"
);
}