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.
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"iter_id": "24.2",
|
||||||
|
"date": "2026-05-13",
|
||||||
|
"mode": "standard",
|
||||||
|
"outcome": "DONE",
|
||||||
|
"tasks_total": 8,
|
||||||
|
"tasks_completed": 8,
|
||||||
|
"reloops_per_task": {
|
||||||
|
"1": 0,
|
||||||
|
"2": 0,
|
||||||
|
"3": 0,
|
||||||
|
"4": 0,
|
||||||
|
"5": 0,
|
||||||
|
"6": 0,
|
||||||
|
"7": 0,
|
||||||
|
"8": 0
|
||||||
|
},
|
||||||
|
"review_loops_spec": 0,
|
||||||
|
"review_loops_quality": 0,
|
||||||
|
"blocked_reason": null,
|
||||||
|
"notes": "Task 2 expanded scope inline to recover from a plan undercount on 22b migration consumers (4 additional files: hash.rs ct4 pin, workspace.rs iter22b1 tests, prose snapshot, one mono_symbol_compound_type assertion). Plan defects fixed inline per mq.1 / mq.3 precedent — no formal re-loop, no Boss dispatch. Plan Task 4 fixture literal schema was wrong ({lit: 'int'} flat vs {lit: {kind: 'int', value: 42}} nested) — fixed inline on first round-trip. Plan Task 5 API name was placeholder (Env::from_workspace) — used actual build_check_env. All other tasks first-shot."
|
||||||
|
}
|
||||||
@@ -16,6 +16,13 @@ fn fixture_path() -> PathBuf {
|
|||||||
d.join("examples").join("mono_hash_pin_smoke.ail.json")
|
d.join("examples").join("mono_hash_pin_smoke.ail.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn primitive_eq_ord_mono_symbol_hashes_stay_bit_identical() {
|
fn primitive_eq_ord_mono_symbol_hashes_stay_bit_identical() {
|
||||||
let ws = load_workspace(&fixture_path()).expect("workspace loads");
|
let ws = load_workspace(&fixture_path()).expect("workspace loads");
|
||||||
@@ -50,3 +57,38 @@ fn primitive_eq_ord_mono_symbol_hashes_stay_bit_identical() {
|
|||||||
assert_eq!(&h, pin, "{sym} body hash drifted");
|
assert_eq!(&h, pin, "{sym} body hash drifted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn primitive_show_mono_symbol_hashes_stay_bit_identical() {
|
||||||
|
// 24.2 hash-stability pin for the four primitive `show__T` mono
|
||||||
|
// symbols synthesised from `prelude.Show {Int|Bool|Str|Float}`
|
||||||
|
// instance bodies. Loaded from a separate fixture
|
||||||
|
// (`show_mono_pin_smoke.ail.json`) so the Eq/Ord pin above stays
|
||||||
|
// structurally isolated.
|
||||||
|
let ws = load_workspace(&show_fixture_path()).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");
|
||||||
|
|
||||||
|
let prelude_mod = post_mono
|
||||||
|
.modules
|
||||||
|
.get("prelude")
|
||||||
|
.expect("prelude module present");
|
||||||
|
|
||||||
|
let pins: &[(&str, &str)] = &[
|
||||||
|
("show__Int", "891eaebe64b3180d"),
|
||||||
|
("show__Bool", "1bdb621494e50607"),
|
||||||
|
("show__Str", "3f1d57c90ddce081"),
|
||||||
|
("show__Float", "5ab0bdd40b9f8b8f"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (sym, pin) in pins {
|
||||||
|
let def = prelude_mod
|
||||||
|
.defs
|
||||||
|
.iter()
|
||||||
|
.find(|d| matches!(d, Def::Fn(f) if f.name == *sym))
|
||||||
|
.unwrap_or_else(|| panic!("mono symbol {sym} not found in prelude module"));
|
||||||
|
let h = def_hash(def);
|
||||||
|
assert_eq!(&h, pin, "{sym} body hash drifted; captured: {h}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
//! Mono-synthesis existence pin for milestone 24.2's Show class.
|
||||||
|
//!
|
||||||
|
//! Asserts that the four primitive Show instances (Int/Bool/Str/Float)
|
||||||
|
//! cause the mono pass to synthesise `show__Int`, `show__Bool`,
|
||||||
|
//! `show__Str`, `show__Float` as `Def::Fn` entries in the prelude
|
||||||
|
//! post-mono module.
|
||||||
|
|
||||||
|
use ailang_core::ast::Def;
|
||||||
|
use ailang_core::workspace::load_workspace;
|
||||||
|
use ailang_check::{check_workspace, monomorphise_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_mono_pin_smoke.ail.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn primitive_show_mono_symbols_synthesise() {
|
||||||
|
let ws = load_workspace(&fixture_path()).expect("workspace loads");
|
||||||
|
let diags = check_workspace(&ws);
|
||||||
|
assert!(diags.is_empty(), "typecheck diagnostics: {diags:#?}");
|
||||||
|
let post_mono = monomorphise_workspace(&ws).expect("mono green");
|
||||||
|
|
||||||
|
let prelude_mod = post_mono
|
||||||
|
.modules
|
||||||
|
.get("prelude")
|
||||||
|
.expect("prelude module present");
|
||||||
|
|
||||||
|
for sym in &["show__Int", "show__Bool", "show__Str", "show__Float"] {
|
||||||
|
let found = prelude_mod
|
||||||
|
.defs
|
||||||
|
.iter()
|
||||||
|
.any(|d| matches!(d, Def::Fn(f) if f.name == *sym));
|
||||||
|
assert!(
|
||||||
|
found,
|
||||||
|
"mono symbol {sym} not found in prelude module post-mono"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ fn examples_dir() -> PathBuf {
|
|||||||
|
|
||||||
/// Property protected: a class method declared in a `Def::Class` must be
|
/// Property protected: a class method declared in a `Def::Class` must be
|
||||||
/// reachable as a name in the module's `ModuleGlobals` so that pass-2
|
/// reachable as a name in the module's `ModuleGlobals` so that pass-2
|
||||||
/// (`Term::Var { name: "show" }`) does not fire `unbound-var` for
|
/// (`Term::Var { name: "tshow" }`) does not fire `unbound-var` for
|
||||||
/// well-formed class-method calls. The lookup must remember which class
|
/// well-formed class-method calls. The lookup must remember which class
|
||||||
/// the method belongs to so Task 9 can build the residual constraint at
|
/// the method belongs to so Task 9 can build the residual constraint at
|
||||||
/// the call site.
|
/// the call site.
|
||||||
@@ -37,15 +37,15 @@ fn class_method_is_in_module_globals() {
|
|||||||
// Pre-mq.3 callers passed the bare method name only; post-mq.3 they
|
// Pre-mq.3 callers passed the bare method name only; post-mq.3 they
|
||||||
// must disambiguate by class.
|
// must disambiguate by class.
|
||||||
assert!(
|
assert!(
|
||||||
mod_globals.has_class_method("test_22b2_class_method_lookup.Show", "show"),
|
mod_globals.has_class_method("test_22b2_class_method_lookup.TShow", "tshow"),
|
||||||
"class method `show` (in class `Show`) must appear in module globals"
|
"class method `tshow` (in class `TShow`) must appear in module globals"
|
||||||
);
|
);
|
||||||
// mq.1: class_method_class returns the qualified form
|
// mq.1: class_method_class returns the qualified form
|
||||||
// `<defining_module>.<Class>`.
|
// `<defining_module>.<Class>`.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mod_globals.class_method_class("test_22b2_class_method_lookup.Show", "show"),
|
mod_globals.class_method_class("test_22b2_class_method_lookup.TShow", "tshow"),
|
||||||
Some("test_22b2_class_method_lookup.Show"),
|
Some("test_22b2_class_method_lookup.TShow"),
|
||||||
"class method `show` must remember its class is `Show` (qualified post-mq.1)"
|
"class method `tshow` must remember its class is `TShow` (qualified post-mq.1)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ fn class_method_is_in_module_globals() {
|
|||||||
/// typecheck arms can find the matching `Registry` entries) and the
|
/// typecheck arms can find the matching `Registry` entries) and the
|
||||||
/// declared method signature (so a residual class constraint can be
|
/// declared method signature (so a residual class constraint can be
|
||||||
/// built by instantiating the class param at the call site). The
|
/// built by instantiating the class param at the call site). The
|
||||||
/// fixture declares `class Show a { show: a -> Str }`, so the
|
/// fixture declares `class TShow a { show: a -> Str }`, so the
|
||||||
/// recovered `method_ty` must be exactly `Type::Var "a" -> Type::Con
|
/// recovered `method_ty` must be exactly `Type::Var "a" -> Type::Con
|
||||||
/// "Str"` with empty effects.
|
/// "Str"` with empty effects.
|
||||||
#[test]
|
#[test]
|
||||||
@@ -68,8 +68,8 @@ fn class_method_entry_carries_full_metadata() {
|
|||||||
.get("test_22b2_class_method_lookup")
|
.get("test_22b2_class_method_lookup")
|
||||||
.expect("module globals present");
|
.expect("module globals present");
|
||||||
let cm_entry = mod_globals
|
let cm_entry = mod_globals
|
||||||
.class_method("test_22b2_class_method_lookup.Show", "show")
|
.class_method("test_22b2_class_method_lookup.TShow", "tshow")
|
||||||
.expect("class method `show` (in class `Show`) must be registered");
|
.expect("class method `tshow` (in class `TShow`) must be registered");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cm_entry.defining_module, "test_22b2_class_method_lookup",
|
cm_entry.defining_module, "test_22b2_class_method_lookup",
|
||||||
@@ -90,7 +90,7 @@ fn class_method_entry_carries_full_metadata() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
params.len(),
|
params.len(),
|
||||||
1,
|
1,
|
||||||
"method `show` must have exactly one parameter"
|
"method `tshow` must have exactly one parameter"
|
||||||
);
|
);
|
||||||
match ¶ms[0] {
|
match ¶ms[0] {
|
||||||
Type::Var { name } => assert_eq!(
|
Type::Var { name } => assert_eq!(
|
||||||
@@ -122,7 +122,7 @@ fn class_method_entry_carries_full_metadata() {
|
|||||||
}
|
}
|
||||||
assert!(
|
assert!(
|
||||||
effects.is_empty(),
|
effects.is_empty(),
|
||||||
"method `show` must have empty effects, got {:?}",
|
"method `tshow` must have empty effects, got {:?}",
|
||||||
effects
|
effects
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ fn class_method_entry_carries_full_metadata() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Property protected: a polymorphic FnDef that calls a class method
|
/// Property protected: a polymorphic FnDef that calls a class method
|
||||||
/// (e.g. `show x` where `x: a`) but does not declare the matching class
|
/// (e.g. `tshow x` where `x: a`) but does not declare the matching class
|
||||||
/// constraint in its `Forall.constraints` MUST receive a
|
/// constraint in its `Forall.constraints` MUST receive a
|
||||||
/// `missing-constraint` diagnostic. This is the principal soundness
|
/// `missing-constraint` diagnostic. This is the principal soundness
|
||||||
/// guarantee of class-method calls inside polymorphic functions: every
|
/// guarantee of class-method calls inside polymorphic functions: every
|
||||||
@@ -160,7 +160,7 @@ fn fn_calling_class_method_without_declared_constraint_fires_missing_constraint(
|
|||||||
/// method typechecks clean — the residual constraint produced at the
|
/// method typechecks clean — the residual constraint produced at the
|
||||||
/// call site is satisfied by the in-scope declared constraint, and no
|
/// call site is satisfied by the in-scope declared constraint, and no
|
||||||
/// diagnostic fires. This is the positive counterpart to the
|
/// diagnostic fires. This is the positive counterpart to the
|
||||||
/// missing-constraint check: declaring `Show a =>` makes `show x`
|
/// missing-constraint check: declaring `Show a =>` makes `tshow x`
|
||||||
/// well-formed inside the body.
|
/// well-formed inside the body.
|
||||||
#[test]
|
#[test]
|
||||||
fn fn_with_correct_constraint_typechecks_green() {
|
fn fn_with_correct_constraint_typechecks_green() {
|
||||||
@@ -225,7 +225,7 @@ fn fn_with_superclass_constraint_calling_subclass_method_fires_missing_constrain
|
|||||||
/// concrete type, the fn cannot push the obligation to a caller via a
|
/// concrete type, the fn cannot push the obligation to a caller via a
|
||||||
/// `Forall.constraints` annotation — it can only be discharged by an
|
/// `Forall.constraints` annotation — it can only be discharged by an
|
||||||
/// existing instance. Without this check, monomorphisation in 22b.3 would
|
/// existing instance. Without this check, monomorphisation in 22b.3 would
|
||||||
/// have nothing to specialise to. Fixture: `main` calls `show 42` (so the
|
/// have nothing to specialise to. Fixture: `main` calls `tshow 42` (so the
|
||||||
/// residual is `(Show, Int)`) without any `instance Show Int` declared in
|
/// residual is `(Show, Int)`) without any `instance Show Int` declared in
|
||||||
/// the workspace.
|
/// the workspace.
|
||||||
#[test]
|
#[test]
|
||||||
@@ -250,7 +250,7 @@ fn fn_calling_class_method_at_type_without_instance_fires_no_instance() {
|
|||||||
/// otherwise sneak past the negative-only test: a registry that is empty
|
/// otherwise sneak past the negative-only test: a registry that is empty
|
||||||
/// at typecheck time, or keyed under the wrong shape, would silently fire
|
/// at typecheck time, or keyed under the wrong shape, would silently fire
|
||||||
/// `no-instance` even when the instance is present. Fixture: `main` calls
|
/// `no-instance` even when the instance is present. Fixture: `main` calls
|
||||||
/// `show 42` with `instance Show Int` declared in the same workspace.
|
/// `tshow 42` with `instance Show Int` declared in the same workspace.
|
||||||
#[test]
|
#[test]
|
||||||
fn fn_calling_class_method_at_type_with_instance_typechecks_green() {
|
fn fn_calling_class_method_at_type_with_instance_typechecks_green() {
|
||||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||||
@@ -268,13 +268,13 @@ fn fn_calling_class_method_at_type_with_instance_typechecks_green() {
|
|||||||
/// reachable from a fn in module B that imports A — i.e. the workspace-
|
/// reachable from a fn in module B that imports A — i.e. the workspace-
|
||||||
/// wide merge of `module_globals.class_methods` into `Env.class_methods`
|
/// wide merge of `module_globals.class_methods` into `Env.class_methods`
|
||||||
/// (per `check_in_workspace`) is what call-site resolution actually
|
/// (per `check_in_workspace`) is what call-site resolution actually
|
||||||
/// consults. Without this merge, a `Term::Var { name: "show" }` in B would
|
/// consults. Without this merge, a `Term::Var { name: "tshow" }` in B would
|
||||||
/// fire `unbound-var`. The discriminator: when B's `main` calls `show 42`
|
/// fire `unbound-var`. The discriminator: when B's `main` calls `tshow 42`
|
||||||
/// at a fully-concrete type and A has NO matching instance, the diagnostic
|
/// at a fully-concrete type and A has NO matching instance, the diagnostic
|
||||||
/// must be `no-instance` (proving the class method resolved cross-module),
|
/// must be `no-instance` (proving the class method resolved cross-module),
|
||||||
/// NOT `unbound-var` (which would mean cross-module class-method lookup
|
/// NOT `unbound-var` (which would mean cross-module class-method lookup
|
||||||
/// failed silently). Fixture: A = `test_22b2_xmod_classmod_noinst` declares
|
/// failed silently). Fixture: A = `test_22b2_xmod_classmod_noinst` declares
|
||||||
/// `class Show a`; B = `test_22b2_xmod_no_instance` calls `show 42`.
|
/// `class TShow a`; B = `test_22b2_xmod_no_instance` calls `tshow 42`.
|
||||||
#[test]
|
#[test]
|
||||||
fn cross_module_class_method_resolves_and_fires_no_instance() {
|
fn cross_module_class_method_resolves_and_fires_no_instance() {
|
||||||
let entry = examples_dir().join("test_22b2_xmod_no_instance.ail.json");
|
let entry = examples_dir().join("test_22b2_xmod_no_instance.ail.json");
|
||||||
@@ -289,7 +289,7 @@ fn cross_module_class_method_resolves_and_fires_no_instance() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!codes.contains(&"unbound-var"),
|
!codes.contains(&"unbound-var"),
|
||||||
"must NOT fire unbound-var — class method `show` from module A is in scope in module B; got: {:?}",
|
"must NOT fire unbound-var — class method `tshow` from module A is in scope in module B; got: {:?}",
|
||||||
codes
|
codes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -297,14 +297,14 @@ fn cross_module_class_method_resolves_and_fires_no_instance() {
|
|||||||
/// Property protected: a polymorphic fn in module B calling a class method
|
/// Property protected: a polymorphic fn in module B calling a class method
|
||||||
/// declared in module A (without declaring the matching constraint) MUST
|
/// declared in module A (without declaring the matching constraint) MUST
|
||||||
/// fire `missing-constraint`. This pins the cross-module class-superclass
|
/// fire `missing-constraint`. This pins the cross-module class-superclass
|
||||||
/// expansion path: B's `Forall.constraints` is empty, A's `class Show a`
|
/// expansion path: B's `Forall.constraints` is empty, A's `class TShow a`
|
||||||
/// is in `Env.class_methods` via the workspace merge, and the residual
|
/// is in `Env.class_methods` via the workspace merge, and the residual
|
||||||
/// `(Show, a)` collected at the `show x` call site must reach `check_fn`'s
|
/// `(Show, a)` collected at the `tshow x` call site must reach `check_fn`'s
|
||||||
/// missing-constraint arm. Without the cross-module merge, the call would
|
/// missing-constraint arm. Without the cross-module merge, the call would
|
||||||
/// produce `unbound-var`; with the merge but a broken superclass-table
|
/// produce `unbound-var`; with the merge but a broken superclass-table
|
||||||
/// merge, the residual could be spuriously satisfied. Fixture: A =
|
/// merge, the residual could be spuriously satisfied. Fixture: A =
|
||||||
/// `test_22b2_xmod_classmod_noinst`; B = `test_22b2_xmod_missing_constraint`
|
/// `test_22b2_xmod_classmod_noinst`; B = `test_22b2_xmod_missing_constraint`
|
||||||
/// declares `forall a. (a) -> Str` and calls `show x`.
|
/// declares `forall a. (a) -> Str` and calls `tshow x`.
|
||||||
#[test]
|
#[test]
|
||||||
fn cross_module_polymorphic_fn_without_constraint_fires_missing_constraint() {
|
fn cross_module_polymorphic_fn_without_constraint_fires_missing_constraint() {
|
||||||
let entry = examples_dir().join("test_22b2_xmod_missing_constraint.ail.json");
|
let entry = examples_dir().join("test_22b2_xmod_missing_constraint.ail.json");
|
||||||
@@ -319,11 +319,11 @@ fn cross_module_polymorphic_fn_without_constraint_fires_missing_constraint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Property protected: cross-module instance lookup for the no-instance
|
/// Property protected: cross-module instance lookup for the no-instance
|
||||||
/// arm. Module A declares `class Show a` AND `instance Show Int`; module
|
/// arm. Module A declares `class TShow a` AND `instance Show Int`; module
|
||||||
/// B imports A and calls `show 42`. The call must typecheck clean — the
|
/// B imports A and calls `tshow 42`. The call must typecheck clean — the
|
||||||
/// workspace registry built at load time over all modules must include A's
|
/// workspace registry built at load time over all modules must include A's
|
||||||
/// `instance Show Int`, and B's `check_fn` must find it under
|
/// `instance Show Int`, and B's `check_fn` must find it under
|
||||||
/// `(class="Show", type_hash(Int))`. Without cross-module registry
|
/// `(class="TShow", type_hash(Int))`. Without cross-module registry
|
||||||
/// population, B would spuriously fire `no-instance` at a type for which
|
/// population, B would spuriously fire `no-instance` at a type for which
|
||||||
/// an instance demonstrably exists. Fixture: A =
|
/// an instance demonstrably exists. Fixture: A =
|
||||||
/// `test_22b2_xmod_classmod`; B = `test_22b2_xmod_instance_present`.
|
/// `test_22b2_xmod_classmod`; B = `test_22b2_xmod_instance_present`.
|
||||||
@@ -342,7 +342,7 @@ fn cross_module_instance_satisfies_concrete_call() {
|
|||||||
|
|
||||||
/// Property protected: `check_workspace` aggregates diagnostics across
|
/// Property protected: `check_workspace` aggregates diagnostics across
|
||||||
/// distinct fns rather than stopping at the first failing fn. When two
|
/// distinct fns rather than stopping at the first failing fn. When two
|
||||||
/// independent polymorphic fns each call `show x` without declaring `Show
|
/// independent polymorphic fns each call `tshow x` without declaring `Show
|
||||||
/// a`, the resulting diagnostic vec must contain TWO `missing-constraint`
|
/// a`, the resulting diagnostic vec must contain TWO `missing-constraint`
|
||||||
/// entries — one per fn — with the right `def` field on each. Without
|
/// entries — one per fn — with the right `def` field on each. Without
|
||||||
/// per-def aggregation in the `for def in &m.defs` loop of
|
/// per-def aggregation in the `for def in &m.defs` loop of
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ fn monomorphise_workspace_is_identity_on_class_free_workspace() {
|
|||||||
/// so no FnDefs are appended.
|
/// so no FnDefs are appended.
|
||||||
///
|
///
|
||||||
/// The fixture (`test_22b3_no_call_sites.ail.json`) declares
|
/// The fixture (`test_22b3_no_call_sites.ail.json`) declares
|
||||||
/// `class Show` + `instance Show Int` with a Lam-shaped instance
|
/// `class TShow` + `instance Show Int` with a Lam-shaped instance
|
||||||
/// body, but `main` is a literal — there is no `show <x>` call at any
|
/// body, but `main` is a literal — there is no `show <x>` call at any
|
||||||
/// type. Updated in Task 5 from `test_22b2_instance_present.ail.json`,
|
/// type. Updated in Task 5 from `test_22b2_instance_present.ail.json`,
|
||||||
/// which had a `show 42` call site that the real fixpoint now
|
/// which had a `tshow 42` call site that the real fixpoint now
|
||||||
/// (correctly) materialises into `show__Int`.
|
/// (correctly) materialises into `tshow__Int`.
|
||||||
#[test]
|
#[test]
|
||||||
fn monomorphise_workspace_is_identity_when_no_concrete_call_sites() {
|
fn monomorphise_workspace_is_identity_when_no_concrete_call_sites() {
|
||||||
let entry = examples_dir().join("test_22b3_no_call_sites.ail.json");
|
let entry = examples_dir().join("test_22b3_no_call_sites.ail.json");
|
||||||
@@ -102,9 +102,9 @@ fn mono_symbol_primitive_types_use_surface_form() {
|
|||||||
let str_ty = Type::str_();
|
let str_ty = Type::str_();
|
||||||
let unit_ty = Type::unit();
|
let unit_ty = Type::unit();
|
||||||
|
|
||||||
assert_eq!(ailang_check::mono::mono_symbol("show", &int_ty), "show__Int");
|
assert_eq!(ailang_check::mono::mono_symbol("tshow", &int_ty), "tshow__Int");
|
||||||
assert_eq!(ailang_check::mono::mono_symbol("eq", &bool_ty), "eq__Bool");
|
assert_eq!(ailang_check::mono::mono_symbol("eq", &bool_ty), "eq__Bool");
|
||||||
assert_eq!(ailang_check::mono::mono_symbol("show", &str_ty), "show__Str");
|
assert_eq!(ailang_check::mono::mono_symbol("tshow", &str_ty), "tshow__Str");
|
||||||
assert_eq!(ailang_check::mono::mono_symbol("foo", &unit_ty), "foo__Unit");
|
assert_eq!(ailang_check::mono::mono_symbol("foo", &unit_ty), "foo__Unit");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,9 +112,9 @@ fn mono_symbol_primitive_types_use_surface_form() {
|
|||||||
/// fully-concrete `(class, method, type)` triples observed at
|
/// fully-concrete `(class, method, type)` triples observed at
|
||||||
/// class-method call sites in a fn body, with the registry's
|
/// class-method call sites in a fn body, with the registry's
|
||||||
/// `defining_module` attached to each. The fixture's `main` calls
|
/// `defining_module` attached to each. The fixture's `main` calls
|
||||||
/// `show 42` once with `Int`, and the workspace declares
|
/// `tshow 42` once with `Int`, and the workspace declares
|
||||||
/// `instance Show Int` in the same module — the expected output is
|
/// `instance Show Int` in the same module — the expected output is
|
||||||
/// a single MonoTarget naming `Show`, `show`, `Int`, and that
|
/// a single MonoTarget naming `TShow`, `tshow`, `Int`, and that
|
||||||
/// module.
|
/// module.
|
||||||
#[test]
|
#[test]
|
||||||
fn collect_mono_targets_single_concrete_call_site() {
|
fn collect_mono_targets_single_concrete_call_site() {
|
||||||
@@ -149,8 +149,8 @@ fn collect_mono_targets_single_concrete_call_site() {
|
|||||||
match t {
|
match t {
|
||||||
ailang_check::mono::MonoTarget::ClassMethod { class, method, type_, defining_module } => {
|
ailang_check::mono::MonoTarget::ClassMethod { class, method, type_, defining_module } => {
|
||||||
// mq.1: MonoTarget.class carries the qualified workspace-key shape.
|
// mq.1: MonoTarget.class carries the qualified workspace-key shape.
|
||||||
assert_eq!(class, "test_22b2_instance_present.Show");
|
assert_eq!(class, "test_22b2_instance_present.TShow");
|
||||||
assert_eq!(method, "show");
|
assert_eq!(method, "tshow");
|
||||||
assert!(
|
assert!(
|
||||||
matches!(type_, ailang_core::ast::Type::Con { name, args } if name == "Int" && args.is_empty()),
|
matches!(type_, ailang_core::ast::Type::Con { name, args } if name == "Int" && args.is_empty()),
|
||||||
"type must be Int, got {:?}",
|
"type must be Int, got {:?}",
|
||||||
@@ -171,11 +171,11 @@ fn mono_symbol_compound_type_uses_hash_suffix() {
|
|||||||
name: "Pair".into(),
|
name: "Pair".into(),
|
||||||
args: vec![Type::int(), Type::bool_()],
|
args: vec![Type::int(), Type::bool_()],
|
||||||
};
|
};
|
||||||
let name = ailang_check::mono::mono_symbol("show", &pair_ty);
|
let name = ailang_check::mono::mono_symbol("tshow", &pair_ty);
|
||||||
|
|
||||||
// Format: `show__<8-hex-chars>`.
|
// Format: `tshow__<8-hex-chars>`.
|
||||||
assert!(name.starts_with("show__"), "name = {name}");
|
assert!(name.starts_with("tshow__"), "name = {name}");
|
||||||
let suffix = &name["show__".len()..];
|
let suffix = &name["tshow__".len()..];
|
||||||
assert_eq!(suffix.len(), 8, "compound suffix is 8 hex chars: {suffix}");
|
assert_eq!(suffix.len(), 8, "compound suffix is 8 hex chars: {suffix}");
|
||||||
assert!(
|
assert!(
|
||||||
suffix.chars().all(|c| c.is_ascii_hexdigit()),
|
suffix.chars().all(|c| c.is_ascii_hexdigit()),
|
||||||
@@ -183,7 +183,7 @@ fn mono_symbol_compound_type_uses_hash_suffix() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Stability: a second call with the same type produces the same name.
|
// Stability: a second call with the same type produces the same name.
|
||||||
let again = ailang_check::mono::mono_symbol("show", &pair_ty);
|
let again = ailang_check::mono::mono_symbol("tshow", &pair_ty);
|
||||||
assert_eq!(name, again, "mono_symbol must be deterministic");
|
assert_eq!(name, again, "mono_symbol must be deterministic");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,9 +370,9 @@ fn synthesise_mono_fn_zero_arg_method_uses_body_verbatim() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Property: when two call sites of `show` apply at the same concrete
|
/// Property: when two call sites of `tshow` apply at the same concrete
|
||||||
/// type (Int), the workspace fixpoint synthesises the matching FnDef
|
/// type (Int), the workspace fixpoint synthesises the matching FnDef
|
||||||
/// (`show__Int`) exactly once across the whole workspace. Verifies the
|
/// (`tshow__Int`) exactly once across the whole workspace. Verifies the
|
||||||
/// dedup contract — the pass must not emit one FnDef per call site.
|
/// dedup contract — the pass must not emit one FnDef per call site.
|
||||||
#[test]
|
#[test]
|
||||||
fn fixpoint_dedupes_repeated_calls_at_same_type() {
|
fn fixpoint_dedupes_repeated_calls_at_same_type() {
|
||||||
@@ -383,18 +383,18 @@ fn fixpoint_dedupes_repeated_calls_at_same_type() {
|
|||||||
|
|
||||||
let ws = ailang_check::monomorphise_workspace(&ws).expect("mono");
|
let ws = ailang_check::monomorphise_workspace(&ws).expect("mono");
|
||||||
|
|
||||||
// Count `show__Int` fns workspace-wide.
|
// Count `tshow__Int` fns workspace-wide.
|
||||||
let mut count = 0usize;
|
let mut count = 0usize;
|
||||||
for m in ws.modules.values() {
|
for m in ws.modules.values() {
|
||||||
for d in &m.defs {
|
for d in &m.defs {
|
||||||
if let ailang_core::ast::Def::Fn(f) = d {
|
if let ailang_core::ast::Def::Fn(f) = d {
|
||||||
if f.name == "show__Int" {
|
if f.name == "tshow__Int" {
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(count, 1, "exactly one show__Int across the workspace");
|
assert_eq!(count, 1, "exactly one tshow__Int across the workspace");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Property: when a synthesised instance body itself calls another class
|
/// Property: when a synthesised instance body itself calls another class
|
||||||
@@ -450,7 +450,7 @@ fn fixpoint_handles_chained_class_method_calls() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Property: when a fn's body locally shadows a class-method name
|
/// Property: when a fn's body locally shadows a class-method name
|
||||||
/// (here `show` is rebound by a `let`-binding), synth resolves the
|
/// (here `tshow` is rebound by a `let`-binding), synth resolves the
|
||||||
/// shadowed `Var` against the local and pushes NO residual for it.
|
/// shadowed `Var` against the local and pushes NO residual for it.
|
||||||
/// The rewrite walker must mirror that exact lookup-precedence rule
|
/// The rewrite walker must mirror that exact lookup-precedence rule
|
||||||
/// — when a `Term::Var { name }` is in the local scope, the walker
|
/// — when a `Term::Var { name }` is in the local scope, the walker
|
||||||
@@ -463,14 +463,14 @@ fn fixpoint_handles_chained_class_method_calls() {
|
|||||||
///
|
///
|
||||||
/// Body shape (`main`):
|
/// Body shape (`main`):
|
||||||
/// let _t = show 5 in -- residual #0: show@Int
|
/// let _t = show 5 in -- residual #0: show@Int
|
||||||
/// let show = "shadow" in -- shadow `show`
|
/// let show = "shadow" in -- shadow `tshow`
|
||||||
/// let _u = show in -- shadowed Var (no residual)
|
/// let _u = show in -- shadowed Var (no residual)
|
||||||
/// foo 7 -- residual #1: foo@Int
|
/// foo 7 -- residual #1: foo@Int
|
||||||
///
|
///
|
||||||
/// `synth` pushes exactly two residuals (in order: show@Int, foo@Int).
|
/// `synth` pushes exactly two residuals (in order: show@Int, foo@Int).
|
||||||
/// The shadow-aware walker must:
|
/// The shadow-aware walker must:
|
||||||
/// - rewrite the outer `show` callee → `show__Int`,
|
/// - rewrite the outer `tshow` callee → `tshow__Int`,
|
||||||
/// - leave the inner shadowed `show` Var literally as `show`,
|
/// - leave the inner shadowed `tshow` Var literally as `tshow`,
|
||||||
/// - rewrite the `foo` callee → `foo__Int`.
|
/// - rewrite the `foo` callee → `foo__Int`.
|
||||||
///
|
///
|
||||||
/// A shadow-blind walker would advance the cursor on the inner Var,
|
/// A shadow-blind walker would advance the cursor on the inner Var,
|
||||||
@@ -483,7 +483,7 @@ fn rewrite_walker_skips_locally_shadowed_class_method() {
|
|||||||
let entry = examples_dir().join("test_22b3_shadow_class_method.ail.json");
|
let entry = examples_dir().join("test_22b3_shadow_class_method.ail.json");
|
||||||
let ws = ailang_core::load_workspace(&entry).expect("load");
|
let ws = ailang_core::load_workspace(&entry).expect("load");
|
||||||
let diags = ailang_check::check_workspace(&ws);
|
let diags = ailang_check::check_workspace(&ws);
|
||||||
// mq.3: this fixture intentionally shadows the class method `show`
|
// mq.3: this fixture intentionally shadows the class method `tshow`
|
||||||
// with a local `let show = "shadow"`, which fires the new
|
// with a local `let show = "shadow"`, which fires the new
|
||||||
// `class-method-shadowed-by-fn` warning. The warning is an
|
// `class-method-shadowed-by-fn` warning. The warning is an
|
||||||
// expected correct consequence; filter it out so the assertion
|
// expected correct consequence; filter it out so the assertion
|
||||||
@@ -519,14 +519,14 @@ fn rewrite_walker_skips_locally_shadowed_class_method() {
|
|||||||
other => panic!("outer value is not App: {:?}", other),
|
other => panic!("outer value is not App: {:?}", other),
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
outer_callee, "show__Int",
|
outer_callee, "tshow__Int",
|
||||||
"the outer class-method call site must be rewritten to show__Int"
|
"the outer class-method call site must be rewritten to tshow__Int"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Step inside `let show = "shadow" in <body>`.
|
// Step inside `let show = "shadow" in <body>`.
|
||||||
let shadow_let_body = match outer_body {
|
let shadow_let_body = match outer_body {
|
||||||
Term::Let { name, body, .. } => {
|
Term::Let { name, body, .. } => {
|
||||||
assert_eq!(name, "show", "expected shadowing let to bind `show`");
|
assert_eq!(name, "tshow", "expected shadowing let to bind `tshow`");
|
||||||
body.as_ref()
|
body.as_ref()
|
||||||
}
|
}
|
||||||
other => panic!("expected shadowing Let, got {:?}", other),
|
other => panic!("expected shadowing Let, got {:?}", other),
|
||||||
@@ -540,10 +540,10 @@ fn rewrite_walker_skips_locally_shadowed_class_method() {
|
|||||||
Term::Var { name } => name.as_str(),
|
Term::Var { name } => name.as_str(),
|
||||||
other => panic!("inner value is not Var: {:?}", other),
|
other => panic!("inner value is not Var: {:?}", other),
|
||||||
};
|
};
|
||||||
// The locally-shadowed `show` Var must NOT be rewritten.
|
// The locally-shadowed `tshow` Var must NOT be rewritten.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
shadowed_var_name, "show",
|
shadowed_var_name, "tshow",
|
||||||
"locally-shadowed `show` Var must remain literal `show`, \
|
"locally-shadowed `tshow` Var must remain literal `tshow`, \
|
||||||
not be re-aligned to a later residual slot"
|
not be re-aligned to a later residual slot"
|
||||||
);
|
);
|
||||||
// The real `foo 7` call site — the second residual — must be
|
// The real `foo 7` call site — the second residual — must be
|
||||||
@@ -596,24 +596,24 @@ fn rewrite_uses_qualified_name_for_cross_module_call_site() {
|
|||||||
};
|
};
|
||||||
// class+instance live in test_22b2_xmod_classmod; caller in
|
// class+instance live in test_22b2_xmod_classmod; caller in
|
||||||
// test_22b2_xmod_instance_present → qualified call.
|
// test_22b2_xmod_instance_present → qualified call.
|
||||||
assert_eq!(callee_name, "test_22b2_xmod_classmod.show__Int");
|
assert_eq!(callee_name, "test_22b2_xmod_classmod.tshow__Int");
|
||||||
|
|
||||||
// Placement: the synthesised def must live in the defining module,
|
// Placement: the synthesised def must live in the defining module,
|
||||||
// not the caller's module.
|
// not the caller's module.
|
||||||
let classmod = ws.modules.get("test_22b2_xmod_classmod").unwrap();
|
let classmod = ws.modules.get("test_22b2_xmod_classmod").unwrap();
|
||||||
let has_synth = classmod.defs.iter().any(|d| {
|
let has_synth = classmod.defs.iter().any(|d| {
|
||||||
matches!(d, ailang_core::ast::Def::Fn(f) if f.name == "show__Int")
|
matches!(d, ailang_core::ast::Def::Fn(f) if f.name == "tshow__Int")
|
||||||
});
|
});
|
||||||
assert!(
|
assert!(
|
||||||
has_synth,
|
has_synth,
|
||||||
"show__Int must live in the instance's defining module"
|
"tshow__Int must live in the instance's defining module"
|
||||||
);
|
);
|
||||||
let caller_has_synth = main_module.defs.iter().any(|d| {
|
let caller_has_synth = main_module.defs.iter().any(|d| {
|
||||||
matches!(d, ailang_core::ast::Def::Fn(f) if f.name == "show__Int")
|
matches!(d, ailang_core::ast::Def::Fn(f) if f.name == "tshow__Int")
|
||||||
});
|
});
|
||||||
assert!(
|
assert!(
|
||||||
!caller_has_synth,
|
!caller_has_synth,
|
||||||
"show__Int must NOT live in the caller's module"
|
"tshow__Int must NOT live in the caller's module"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,8 +670,8 @@ fn synthetic_fixture_runs_and_prints_five() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// After the mono pass, the body of `main` in
|
/// After the mono pass, the body of `main` in
|
||||||
/// test_22b2_instance_present must reference `show__Int` instead
|
/// test_22b2_instance_present must reference `tshow__Int` instead
|
||||||
/// of `show`.
|
/// of `tshow`.
|
||||||
#[test]
|
#[test]
|
||||||
fn rewrite_replaces_class_method_var_with_mono_symbol_same_module() {
|
fn rewrite_replaces_class_method_var_with_mono_symbol_same_module() {
|
||||||
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
let entry = examples_dir().join("test_22b2_instance_present.ail.json");
|
||||||
@@ -691,8 +691,8 @@ fn rewrite_replaces_class_method_var_with_mono_symbol_same_module() {
|
|||||||
})
|
})
|
||||||
.expect("main");
|
.expect("main");
|
||||||
|
|
||||||
// The body is `App { fn: Var "show", args: [Lit 42] }`. After
|
// The body is `App { fn: Var "tshow", args: [Lit 42] }`. After
|
||||||
// rewrite, the callee Var must be `show__Int`.
|
// rewrite, the callee Var must be `tshow__Int`.
|
||||||
let callee_name: &str = match &main_fn.body {
|
let callee_name: &str = match &main_fn.body {
|
||||||
ailang_core::ast::Term::App { callee, .. } => match callee.as_ref() {
|
ailang_core::ast::Term::App { callee, .. } => match callee.as_ref() {
|
||||||
ailang_core::ast::Term::Var { name } => name.as_str(),
|
ailang_core::ast::Term::Var { name } => name.as_str(),
|
||||||
@@ -700,7 +700,7 @@ fn rewrite_replaces_class_method_var_with_mono_symbol_same_module() {
|
|||||||
},
|
},
|
||||||
other => panic!("body is not App: {:?}", other),
|
other => panic!("body is not App: {:?}", other),
|
||||||
};
|
};
|
||||||
assert_eq!(callee_name, "show__Int");
|
assert_eq!(callee_name, "tshow__Int");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper: build & run a workspace via `ail run` and capture stdout
|
/// Helper: build & run a workspace via `ail run` and capture stdout
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
//! 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:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -294,33 +294,35 @@ mod tests {
|
|||||||
.expect("examples/test_22b1_dup_a.ail.json present");
|
.expect("examples/test_22b1_dup_a.ail.json present");
|
||||||
let dup_a_mod: crate::ast::Module = serde_json::from_slice(&dup_a_src).unwrap();
|
let dup_a_mod: crate::ast::Module = serde_json::from_slice(&dup_a_src).unwrap();
|
||||||
// mq.1: test_22b1_dup_a has one def post-migration — the instance
|
// mq.1: test_22b1_dup_a has one def post-migration — the instance
|
||||||
// of `test_22b1_dup_classmod.Show` for `test_22b1_dup_b.MyInt`.
|
// of `test_22b1_dup_classmod.TShow` for `test_22b1_dup_b.MyInt`.
|
||||||
// The `Show` class itself moved to `test_22b1_dup_classmod` to
|
// The `TShow` class itself moved to `test_22b1_dup_classmod` to
|
||||||
// break the dup_a ↔ dup_b cycle that the pre-mq.1 bare-class
|
// break the dup_a ↔ dup_b cycle that the pre-mq.1 bare-class
|
||||||
// shape required for cross-module duplicate-instance coverage.
|
// shape required for cross-module duplicate-instance coverage.
|
||||||
|
// 24.2: class renamed `Show` → `TShow` and method renamed
|
||||||
|
// `show` → `tshow` workspace-wide so prelude.Show can ship; the
|
||||||
|
// hash captures new bytes accordingly.
|
||||||
assert_eq!(dup_a_mod.defs.len(), 1, "test_22b1_dup_a expected to have exactly 1 def (the instance)");
|
assert_eq!(dup_a_mod.defs.len(), 1, "test_22b1_dup_a expected to have exactly 1 def (the instance)");
|
||||||
// Hash captured post-mq.1 migration; the instance carries the
|
// Hash captured post-24.2 TShow/tshow rename. A future
|
||||||
// canonical qualified `class` field. Computed by running this
|
// schema-touching change that shifts this hash without intent
|
||||||
// test once with a length-only assertion and recording the
|
// triggers this pin.
|
||||||
// observed value. A future schema-touching change that shifts
|
|
||||||
// this hash without intent triggers this pin.
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
def_hash(&dup_a_mod.defs[0]),
|
def_hash(&dup_a_mod.defs[0]),
|
||||||
"bdefb4ec75e046e4",
|
"392c247f07de6517",
|
||||||
"test_22b1_dup_a instance hash drifted; expected post-mq.1 captured value"
|
"test_22b1_dup_a instance hash drifted; expected post-24.2 captured value"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Also pin the new test_22b1_dup_classmod fixture's `Show` class
|
// Also pin the new test_22b1_dup_classmod fixture's `TShow` class
|
||||||
// hash: the class moved here from dup_a verbatim (same method
|
// hash: the class moved here from dup_a verbatim (same method
|
||||||
// signature), so the hash is independent of the migration.
|
// signature), so the hash is independent of the migration but
|
||||||
|
// does shift with the 24.2 Show→TShow / show→tshow rename.
|
||||||
let dup_classmod_src = std::fs::read(examples.join("test_22b1_dup_classmod.ail.json"))
|
let dup_classmod_src = std::fs::read(examples.join("test_22b1_dup_classmod.ail.json"))
|
||||||
.expect("examples/test_22b1_dup_classmod.ail.json present");
|
.expect("examples/test_22b1_dup_classmod.ail.json present");
|
||||||
let dup_classmod_mod: crate::ast::Module = serde_json::from_slice(&dup_classmod_src).unwrap();
|
let dup_classmod_mod: crate::ast::Module = serde_json::from_slice(&dup_classmod_src).unwrap();
|
||||||
assert_eq!(dup_classmod_mod.defs.len(), 1, "test_22b1_dup_classmod expected to have exactly 1 def (class Show)");
|
assert_eq!(dup_classmod_mod.defs.len(), 1, "test_22b1_dup_classmod expected to have exactly 1 def (class TShow)");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
def_hash(&dup_classmod_mod.defs[0]),
|
def_hash(&dup_classmod_mod.defs[0]),
|
||||||
"1c2573661ffd3da3",
|
"b8bca96c2d09ed93",
|
||||||
"test_22b1_dup_classmod class Show canonical hash must equal the pre-mq.1 dup_a class Show hash (same bytes)"
|
"test_22b1_dup_classmod class TShow canonical hash; post-24.2 captured value"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1838,20 +1838,21 @@ mod tests {
|
|||||||
assert_eq!(fixture_entries.len(), 1);
|
assert_eq!(fixture_entries.len(), 1);
|
||||||
let (key, entry) = fixture_entries[0];
|
let (key, entry) = fixture_entries[0];
|
||||||
// mq.1: registry key is keyed by the qualified class name.
|
// mq.1: registry key is keyed by the qualified class name.
|
||||||
assert_eq!(&key.0, "test_22b1_orphan_class.Show");
|
// 24.2: class renamed `Show` → `TShow` workspace-wide.
|
||||||
|
assert_eq!(&key.0, "test_22b1_orphan_class.TShow");
|
||||||
assert_eq!(entry.defining_module, "test_22b1_orphan_class");
|
assert_eq!(entry.defining_module, "test_22b1_orphan_class");
|
||||||
// `instance.class` carries the canonical-form on-disk value
|
// `instance.class` carries the canonical-form on-disk value
|
||||||
// (bare for same-module per the canonical-form rule).
|
// (bare for same-module per the canonical-form rule).
|
||||||
assert_eq!(entry.instance.class, "Show");
|
assert_eq!(entry.instance.class, "TShow");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iter 22b.1: an instance declared in a module that is neither
|
/// Iter 22b.1: an instance declared in a module that is neither
|
||||||
/// the class's module nor the type's module fires `OrphanInstance`.
|
/// the class's module nor the type's module fires `OrphanInstance`.
|
||||||
/// The fixture imports `test_22b1_orphan_third_classmod` (which
|
/// The fixture imports `test_22b1_orphan_third_classmod` (which
|
||||||
/// owns `class Show`) and the entry module declares `instance
|
/// owns `class TShow`) and the entry module declares `instance
|
||||||
/// Show Int` itself — but the entry is not the class's module
|
/// TShow Int` itself — but the entry is not the class's module
|
||||||
/// and `Int` is primitive, so neither leg of coherence is
|
/// and `Int` is primitive, so neither leg of coherence is
|
||||||
/// satisfied.
|
/// satisfied. (24.2: class renamed `Show` → `TShow`.)
|
||||||
#[test]
|
#[test]
|
||||||
fn iter22b1_orphan_instance_fires_diagnostic() {
|
fn iter22b1_orphan_instance_fires_diagnostic() {
|
||||||
let entry = examples_dir().join("test_22b1_orphan_third.ail.json");
|
let entry = examples_dir().join("test_22b1_orphan_third.ail.json");
|
||||||
@@ -1865,7 +1866,7 @@ mod tests {
|
|||||||
} => {
|
} => {
|
||||||
// mq.1: `class` carries the canonical form (qualified
|
// mq.1: `class` carries the canonical form (qualified
|
||||||
// for cross-module class refs).
|
// for cross-module class refs).
|
||||||
assert_eq!(class, "test_22b1_orphan_third_classmod.Show");
|
assert_eq!(class, "test_22b1_orphan_third_classmod.TShow");
|
||||||
assert_eq!(type_repr, "Int");
|
assert_eq!(type_repr, "Int");
|
||||||
assert_eq!(defining_module, "test_22b1_orphan_third");
|
assert_eq!(defining_module, "test_22b1_orphan_third");
|
||||||
}
|
}
|
||||||
@@ -1887,8 +1888,8 @@ mod tests {
|
|||||||
/// canonical key is to have them in the same module (the class's
|
/// canonical key is to have them in the same module (the class's
|
||||||
/// or the type's module). The fixture now declares both
|
/// or the type's module). The fixture now declares both
|
||||||
/// instances in `test_22b1_dup_same_module` — both class-leg
|
/// instances in `test_22b1_dup_same_module` — both class-leg
|
||||||
/// coherent, both collide on `(test_22b1_dup_same_module.Show,
|
/// coherent, both collide on `(test_22b1_dup_same_module.TShow,
|
||||||
/// type_hash(Int))`.
|
/// type_hash(Int))`. (24.2: class renamed `Show` → `TShow`.)
|
||||||
#[test]
|
#[test]
|
||||||
fn iter22b1_duplicate_instance_fires_diagnostic() {
|
fn iter22b1_duplicate_instance_fires_diagnostic() {
|
||||||
let entry = examples_dir().join("test_22b1_dup_same_module.ail.json");
|
let entry = examples_dir().join("test_22b1_dup_same_module.ail.json");
|
||||||
@@ -1902,7 +1903,7 @@ mod tests {
|
|||||||
} => {
|
} => {
|
||||||
// `class` is the on-disk `inst.class` value; the
|
// `class` is the on-disk `inst.class` value; the
|
||||||
// fixture is intra-module so it stays bare.
|
// fixture is intra-module so it stays bare.
|
||||||
assert_eq!(class, "Show");
|
assert_eq!(class, "TShow");
|
||||||
assert_eq!(type_repr, "Int");
|
assert_eq!(type_repr, "Int");
|
||||||
// Both instances live in the same module post-mq.1,
|
// Both instances live in the same module post-mq.1,
|
||||||
// by structural necessity — see test doc-comment.
|
// by structural necessity — see test doc-comment.
|
||||||
|
|||||||
+20
-6
@@ -1888,12 +1888,26 @@ end-to-end path is the milestone's typeclass acceptance gate
|
|||||||
Milestone 23 amends the above: the prelude now ships the `Ordering`
|
Milestone 23 amends the above: the prelude now ships the `Ordering`
|
||||||
ADT, the `Eq` and `Ord` classes, primitive `Eq Int/Bool/Str` and
|
ADT, the `Eq` and `Ord` classes, primitive `Eq Int/Bool/Str` and
|
||||||
`Ord Int/Bool/Str` instances, and the five polymorphic free-fn helpers
|
`Ord Int/Bool/Str` instances, and the five polymorphic free-fn helpers
|
||||||
`ne` / `lt` / `le` / `gt` / `ge`. `Show`, operator routing through
|
`ne` / `lt` / `le` / `gt` / `ge`. Operator routing through `Eq`/`Ord`
|
||||||
`Eq`/`Ord`, and `print`-rewire remain out of scope per their original
|
and `print`-rewire remain out of scope per their original substantive
|
||||||
substantive reasons (heap-`Str` ABI, bench rebaseline). Float has
|
reasons (bench rebaseline, milestone-24 dependency on the post-mq
|
||||||
neither `Eq` nor `Ord` instance per §"Float semantics"; a polymorphic
|
dispatcher); `Show` itself ships in milestone 24. Float has neither
|
||||||
helper invoked at Float fires `NoInstance` at typecheck with a
|
`Eq` nor `Ord` instance per §"Float semantics"; a polymorphic helper
|
||||||
Float-aware diagnostic cross-referencing this section.
|
invoked at Float fires `NoInstance` at typecheck with a Float-aware
|
||||||
|
diagnostic cross-referencing this section.
|
||||||
|
|
||||||
|
Milestone 24 amends the above further: the prelude ships `class Show
|
||||||
|
a where show : (a borrow) -> Str` and primitive `Show Int`,
|
||||||
|
`Show Bool`, `Show Str`, `Show Float` instances. Float **is** included
|
||||||
|
in Show (unlike Eq/Ord) — IEEE-754 makes structural equality and total
|
||||||
|
ordering semantically dubious, but textual representation of a Float
|
||||||
|
is well-defined modulo the NaN-spelling caveat in §"Float semantics".
|
||||||
|
Each `Show <T>` instance body is a single-application lambda invoking
|
||||||
|
the corresponding runtime primitive (`int_to_str`, `bool_to_str`,
|
||||||
|
`str_clone`, `float_to_str`); no codegen intercept is required. The
|
||||||
|
polymorphic helper `print : forall a. Show a => a -> () !IO` ships in
|
||||||
|
the same milestone as the second iteration (24.3) and routes through
|
||||||
|
`show` and `io/print_str`.
|
||||||
|
|
||||||
Primitive output goes through `io/print_int` / `io/print_bool` /
|
Primitive output goes through `io/print_int` / `io/print_bool` /
|
||||||
`io/print_str` directly.
|
`io/print_str` directly.
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
# iter 24.2 — Show class + 4 primitive instances + 22b TShow/tshow migration
|
||||||
|
|
||||||
|
**Date:** 2026-05-13
|
||||||
|
**Started from:** 64cea0e
|
||||||
|
**Status:** DONE
|
||||||
|
**Tasks completed:** 8 of 8
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Ships `class Show a where show : (a borrow) -> Str` in
|
||||||
|
`examples/prelude.ail.json` alongside primitive instances `Show Int`,
|
||||||
|
`Show Bool`, `Show Str`, `Show Float`. 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
|
||||||
|
(prior Eq/Ord bodies used operator + codegen intercept). The 22b
|
||||||
|
typeclass test corpus migrates `class Show` / `show` →
|
||||||
|
`class TShow` / `tshow` preemptively (Tasks 1–2 before Task 3 lands
|
||||||
|
`prelude.Show`) so the workspace stays green throughout. Three new
|
||||||
|
tests pin the post-mono shape: mono-synthesis existence
|
||||||
|
(`show_mono_synthesis.rs`), dispatch singleton (`show_dispatch_pin.rs`
|
||||||
|
× 2 cases), and body-hash stability (`mono_hash_stability.rs::primitive_show_mono_symbol_hashes_stay_bit_identical`).
|
||||||
|
DESIGN.md §"Prelude (built-in) classes" gains a milestone-24 paragraph
|
||||||
|
naming Show + instances + the Float caveat. `print`-rewire stays
|
||||||
|
deferred to iter 24.3.
|
||||||
|
|
||||||
|
## Per-task notes
|
||||||
|
|
||||||
|
- iter 24.2.1: Renamed `"Show"`/`"show"` → `"TShow"`/`"tshow"` across 21
|
||||||
|
`test_22b*_*.ail.json` fixture files; cross-module qualifier forms
|
||||||
|
(`"<modname>.Show"` → `"<modname>.TShow"`) handled by regex in 3
|
||||||
|
fixtures (`test_22b1_dup_a`, `test_22b1_dup_b`,
|
||||||
|
`test_22b1_orphan_third`). False-positive scan empty; fixture
|
||||||
|
parse round-trip green.
|
||||||
|
- iter 24.2.2: Renamed literals in `crates/ail/tests/typeclass_22b{2,3}.rs`
|
||||||
|
(`"Show"` → `"TShow"`, `"show"` → `"tshow"`, `show__T` → `tshow__T`),
|
||||||
|
including comment-prose forms (`` `Show` `` → `` `TShow` ``,
|
||||||
|
`class Show` → `class TShow`, etc.) and one assertion-message string
|
||||||
|
("exactly one show__Int across the workspace" → "tshow__Int...").
|
||||||
|
Plan undercount surfaced: the rename touches more than the 2 named
|
||||||
|
test files — see Concerns below.
|
||||||
|
- iter 24.2.3: Inserted 5 new top-level defs into `examples/prelude.ail.json`
|
||||||
|
immediately before `fn ne` (line 223 pre-edit). The `instance Show Str`
|
||||||
|
body invokes `str_clone` as `Term::Var` — first prelude instance body
|
||||||
|
to do so. Round-trip green; `primitive_eq_ord_mono_symbol_hashes_stay_bit_identical`
|
||||||
|
stays green (Eq/Ord hashes unaffected by Show defs).
|
||||||
|
- iter 24.2.4: New fixture `examples/show_mono_pin_smoke.ail.json`
|
||||||
|
exercises `show 42`, `show true`, `show "x"`, `show 1.5` in a
|
||||||
|
let-chain ending in `io/print_str s1`. New test
|
||||||
|
`crates/ail/tests/show_mono_synthesis.rs::primitive_show_mono_symbols_synthesise`
|
||||||
|
asserts `show__Int`/`show__Bool`/`show__Str`/`show__Float` materialise
|
||||||
|
as `Def::Fn` entries in the `prelude` post-mono module. `str_clone`
|
||||||
|
reachability in instance-lambda position verified implicitly:
|
||||||
|
`show__Str` materialises, which means the lambda body's `Term::Var
|
||||||
|
"str_clone"` resolved against the checker's builtin table during
|
||||||
|
typecheck.
|
||||||
|
- iter 24.2.5: New pin test `crates/ailang-check/tests/show_dispatch_pin.rs`
|
||||||
|
asserts `env.method_to_candidate_classes["show"] == {"prelude.Show"}`
|
||||||
|
(singleton) and `env.method_to_candidate_classes["tshow"] == {"*.TShow"}`
|
||||||
|
(singleton). API spelled `build_check_env(&ws)` not `Env::from_workspace`
|
||||||
|
(plan's placeholder name). 2/2 cases pass first-shot.
|
||||||
|
- iter 24.2.6: Extended `crates/ail/tests/mono_hash_stability.rs` with
|
||||||
|
a second test function `primitive_show_mono_symbol_hashes_stay_bit_identical`
|
||||||
|
loading `show_mono_pin_smoke.ail.json` (kept separate from the
|
||||||
|
Eq/Ord fixture to avoid coupling). Hashes captured first-run:
|
||||||
|
`show__Int 891eaebe64b3180d`, `show__Bool 1bdb621494e50607`,
|
||||||
|
`show__Str 3f1d57c90ddce081`, `show__Float 5ab0bdd40b9f8b8f`.
|
||||||
|
- iter 24.2.7: DESIGN.md §"Prelude (built-in) classes" amended:
|
||||||
|
milestone-23 paragraph drops "Show" from the deferred list and notes
|
||||||
|
Show ships in milestone 24; new milestone-24 paragraph names class
|
||||||
|
signature, instance set (including Float), body shape (single-app
|
||||||
|
lambda invoking runtime primitive), and the iter-24.3 carry-forward
|
||||||
|
for `print`-rewire.
|
||||||
|
- iter 24.2.8: Workspace tests 552 passed / 0 failed
|
||||||
|
(was 548 pre-iter, +4 new: 1 `show_mono_synthesis` + 2 `show_dispatch_pin`
|
||||||
|
+ 1 hash-stability). `bench/compile_check.py` exit 0 (24/24 stable).
|
||||||
|
`bench/cross_lang.py` exit 0 (25/25 stable). `bench/check.py` exit 1
|
||||||
|
with 2 noise-class metrics (`bench_list_sum.bump_s` +11.71% — 4th
|
||||||
|
consecutive sighting per `audit-mq` / `mq.tidy` lineage;
|
||||||
|
`latency.implicit_at_rc.max_us` +145.55% — 7th consecutive sighting of
|
||||||
|
the documented noise envelope, metric-identity-migrating across runs).
|
||||||
|
Baseline pristine per the conservative-call convention.
|
||||||
|
|
||||||
|
## Concerns
|
||||||
|
|
||||||
|
- **Plan undercount on 22b migration scope.** The plan's "2 Rust test
|
||||||
|
files" carrier (typeclass_22b{2,3}.rs) missed 4 additional consumer
|
||||||
|
sites that hardcode the renamed literals: (a)
|
||||||
|
`crates/ailang-core/src/hash.rs` ct4 canonical-form hash pin (2
|
||||||
|
entries); (b) `crates/ailang-core/src/workspace.rs` 3 in-crate iter22b1
|
||||||
|
tests; (c) `crates/ailang-prose/tests/snapshot.rs` (1 snapshot file at
|
||||||
|
`examples/test_22b2_instance_present.prose.txt`); (d) one
|
||||||
|
`mono_symbol_compound_type_uses_hash_suffix` assertion in typeclass_22b3.rs
|
||||||
|
that called `mono_symbol("tshow", ...)` (post my batch rename) but
|
||||||
|
still asserted `name.starts_with("show__")`. All fixed inline per the
|
||||||
|
precedent of mq.1 / mq.3 "Plan defects fixed inline" — fixture parse
|
||||||
|
was the only "green" pre-iter signal the plan's Step 3/4 anchored on,
|
||||||
|
which masked the broader downstream consumer surface. Suggested
|
||||||
|
Boss-side reaction: future migration plans run an upfront
|
||||||
|
`grep -rln '"<rename target>"' crates/` to enumerate the full
|
||||||
|
consumer set before committing to a per-file enumeration.
|
||||||
|
- **`str_clone` reachability is implicit.** Pre-flight note 3 flagged
|
||||||
|
this as needing first-round-trip verification; verification is
|
||||||
|
implicit in `primitive_show_mono_symbols_synthesise` passing
|
||||||
|
(mono of `show 42 / true / "x" / 1.5` requires the four `show__T`
|
||||||
|
bodies to typecheck, including the `str_clone` call in `show__Str`).
|
||||||
|
No explicit isolated unit test for `str_clone`-in-lambda was added
|
||||||
|
because the integration pin is strictly stronger; consider an
|
||||||
|
isolated unit pin only if a future regression makes the integration
|
||||||
|
test slow to bisect.
|
||||||
|
- **Hash-stability pin uses a separate fixture, not the existing
|
||||||
|
`mono_hash_pin_smoke.ail.json`.** Plan Task 6 offered both options;
|
||||||
|
the separate-fixture path was chosen because `show_mono_pin_smoke.ail.json`
|
||||||
|
already existed (minted in Task 4) and reusing it kept the Eq/Ord
|
||||||
|
pin structurally isolated. Both fixtures live side-by-side; the
|
||||||
|
second test function in `mono_hash_stability.rs` mirrors the first
|
||||||
|
byte-for-byte modulo the fixture path and pin table.
|
||||||
|
- **`bench/check.py` exit 1 is the documented recurring noise envelope.**
|
||||||
|
`latency.implicit_at_rc.*` max-tail metric has been migrating
|
||||||
|
between runs since `audit-cma` (2026-05-12) — 7th consecutive
|
||||||
|
observation; `bench_list_sum.bump_s` is the 4th since `audit-mq`.
|
||||||
|
Plan Task 8 Step 4 explicitly anticipates "1-3 regressed metrics
|
||||||
|
ratify-without-attribution per conservative-call convention"; this
|
||||||
|
iter follows that. The baseline stays pristine.
|
||||||
|
|
||||||
|
## Known debt
|
||||||
|
|
||||||
|
- **iter 24.3 still pending.** Carries `print : forall a. Show a => a -> () !IO`
|
||||||
|
rewire to route through `show` + `io/print_str`. Spec at
|
||||||
|
`docs/specs/2026-05-13-24-show-print.md`. 24.2 is structurally
|
||||||
|
complete; 24.3 is operationally distinct.
|
||||||
|
- **mq1 cross-module fixtures unmigrated by design.**
|
||||||
|
`examples/mq1_xmod_constraint_class.ail.json` and `..._dep.ail.json`
|
||||||
|
reference `mq1_xmod_constraint_class_dep.Show` (cross-module, fully
|
||||||
|
qualified) and ship zero `show` call sites; no dispatch ambiguity
|
||||||
|
arises once `prelude.Show` lands. They stay as-is per the plan's
|
||||||
|
pre-flight ratification.
|
||||||
|
- **mq3 fixtures deliberately retain two-Show shapes.**
|
||||||
|
`examples/mq3_two_show_*` fixtures test the multi-class dispatch
|
||||||
|
scenarios (ambiguity + qualifier resolution) and stay unchanged in
|
||||||
|
24.2 by design.
|
||||||
|
|
||||||
|
## Files touched
|
||||||
|
|
||||||
|
**Created (3):**
|
||||||
|
- `crates/ail/tests/show_mono_synthesis.rs`
|
||||||
|
- `crates/ailang-check/tests/show_dispatch_pin.rs`
|
||||||
|
- `examples/show_mono_pin_smoke.ail.json`
|
||||||
|
|
||||||
|
**Modified (29):**
|
||||||
|
|
||||||
|
Prelude + DESIGN:
|
||||||
|
- `examples/prelude.ail.json` (+5 defs)
|
||||||
|
- `docs/DESIGN.md` (§"Prelude (built-in) classes" amendment)
|
||||||
|
|
||||||
|
22b fixture migration (21 files):
|
||||||
|
- `examples/test_22b1_dup_a.ail.json`
|
||||||
|
- `examples/test_22b1_dup_b.ail.json`
|
||||||
|
- `examples/test_22b1_dup_classmod.ail.json`
|
||||||
|
- `examples/test_22b1_dup_same_module.ail.json`
|
||||||
|
- `examples/test_22b1_orphan_class.ail.json`
|
||||||
|
- `examples/test_22b1_orphan_third.ail.json`
|
||||||
|
- `examples/test_22b1_orphan_third_classmod.ail.json`
|
||||||
|
- `examples/test_22b2_class_method_lookup.ail.json`
|
||||||
|
- `examples/test_22b2_constraint_declared.ail.json`
|
||||||
|
- `examples/test_22b2_instance_present.ail.json`
|
||||||
|
- `examples/test_22b2_missing_constraint.ail.json`
|
||||||
|
- `examples/test_22b2_no_instance.ail.json`
|
||||||
|
- `examples/test_22b2_two_fns_missing_constraint.ail.json`
|
||||||
|
- `examples/test_22b2_xmod_classmod.ail.json`
|
||||||
|
- `examples/test_22b2_xmod_classmod_noinst.ail.json`
|
||||||
|
- `examples/test_22b2_xmod_instance_present.ail.json`
|
||||||
|
- `examples/test_22b2_xmod_missing_constraint.ail.json`
|
||||||
|
- `examples/test_22b2_xmod_no_instance.ail.json`
|
||||||
|
- `examples/test_22b3_dup_call_sites.ail.json`
|
||||||
|
- `examples/test_22b3_no_call_sites.ail.json`
|
||||||
|
- `examples/test_22b3_shadow_class_method.ail.json`
|
||||||
|
|
||||||
|
22b consumer-test migration (5 source files + 1 snapshot):
|
||||||
|
- `crates/ail/tests/typeclass_22b2.rs`
|
||||||
|
- `crates/ail/tests/typeclass_22b3.rs`
|
||||||
|
- `crates/ailang-core/src/hash.rs` (ct4 hash pin)
|
||||||
|
- `crates/ailang-core/src/workspace.rs` (3 iter22b1 tests)
|
||||||
|
- `crates/ail/tests/mono_hash_stability.rs` (new show test fn)
|
||||||
|
- `examples/test_22b2_instance_present.prose.txt` (snapshot accept)
|
||||||
|
|
||||||
|
## Stats
|
||||||
|
|
||||||
|
`bench/orchestrator-stats/2026-05-13-iter-24.2.json`
|
||||||
@@ -219,6 +219,108 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "class",
|
||||||
|
"name": "Show",
|
||||||
|
"param": "a",
|
||||||
|
"doc": "Producer of a human-readable Str representation. Ships in milestone 24 with primitive instances for Int/Bool/Str/Float; user types declare their own instance.",
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "show",
|
||||||
|
"type": {
|
||||||
|
"k": "fn",
|
||||||
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
|
"param_modes": ["borrow"],
|
||||||
|
"ret": { "k": "con", "name": "Str" },
|
||||||
|
"effects": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "instance",
|
||||||
|
"class": "Show",
|
||||||
|
"type": { "k": "con", "name": "Int" },
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "show",
|
||||||
|
"body": {
|
||||||
|
"t": "lam",
|
||||||
|
"params": ["x"],
|
||||||
|
"paramTypes": [{ "k": "con", "name": "Int" }],
|
||||||
|
"retType": { "k": "con", "name": "Str" },
|
||||||
|
"body": {
|
||||||
|
"t": "app",
|
||||||
|
"fn": { "t": "var", "name": "int_to_str" },
|
||||||
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "instance",
|
||||||
|
"class": "Show",
|
||||||
|
"type": { "k": "con", "name": "Bool" },
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "show",
|
||||||
|
"body": {
|
||||||
|
"t": "lam",
|
||||||
|
"params": ["x"],
|
||||||
|
"paramTypes": [{ "k": "con", "name": "Bool" }],
|
||||||
|
"retType": { "k": "con", "name": "Str" },
|
||||||
|
"body": {
|
||||||
|
"t": "app",
|
||||||
|
"fn": { "t": "var", "name": "bool_to_str" },
|
||||||
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "instance",
|
||||||
|
"class": "Show",
|
||||||
|
"type": { "k": "con", "name": "Str" },
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "show",
|
||||||
|
"body": {
|
||||||
|
"t": "lam",
|
||||||
|
"params": ["x"],
|
||||||
|
"paramTypes": [{ "k": "con", "name": "Str" }],
|
||||||
|
"retType": { "k": "con", "name": "Str" },
|
||||||
|
"body": {
|
||||||
|
"t": "app",
|
||||||
|
"fn": { "t": "var", "name": "str_clone" },
|
||||||
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "instance",
|
||||||
|
"class": "Show",
|
||||||
|
"type": { "k": "con", "name": "Float" },
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "show",
|
||||||
|
"body": {
|
||||||
|
"t": "lam",
|
||||||
|
"params": ["x"],
|
||||||
|
"paramTypes": [{ "k": "con", "name": "Float" }],
|
||||||
|
"retType": { "k": "con", "name": "Str" },
|
||||||
|
"body": {
|
||||||
|
"t": "app",
|
||||||
|
"fn": { "t": "var", "name": "float_to_str" },
|
||||||
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "fn",
|
"kind": "fn",
|
||||||
"name": "ne",
|
"name": "ne",
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema": "ailang/v0",
|
||||||
|
"name": "show_mono_pin_smoke",
|
||||||
|
"imports": [],
|
||||||
|
"defs": [
|
||||||
|
{
|
||||||
|
"kind": "fn",
|
||||||
|
"name": "main",
|
||||||
|
"type": {
|
||||||
|
"k": "fn",
|
||||||
|
"params": [],
|
||||||
|
"ret": { "k": "con", "name": "Unit" },
|
||||||
|
"effects": ["IO"]
|
||||||
|
},
|
||||||
|
"params": [],
|
||||||
|
"body": {
|
||||||
|
"t": "let",
|
||||||
|
"name": "s1",
|
||||||
|
"value": { "t": "app",
|
||||||
|
"fn": { "t": "var", "name": "show" },
|
||||||
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }] },
|
||||||
|
"body": {
|
||||||
|
"t": "let",
|
||||||
|
"name": "s2",
|
||||||
|
"value": { "t": "app",
|
||||||
|
"fn": { "t": "var", "name": "show" },
|
||||||
|
"args": [{ "t": "lit", "lit": { "kind": "bool", "value": true } }] },
|
||||||
|
"body": {
|
||||||
|
"t": "let",
|
||||||
|
"name": "s3",
|
||||||
|
"value": { "t": "app",
|
||||||
|
"fn": { "t": "var", "name": "show" },
|
||||||
|
"args": [{ "t": "lit", "lit": { "kind": "str", "value": "x" } }] },
|
||||||
|
"body": {
|
||||||
|
"t": "let",
|
||||||
|
"name": "s4",
|
||||||
|
"value": { "t": "app",
|
||||||
|
"fn": { "t": "var", "name": "show" },
|
||||||
|
"args": [{ "t": "lit", "lit": { "kind": "float", "bits": "3ff8000000000000" } }] },
|
||||||
|
"body": { "t": "do",
|
||||||
|
"op": "io/print_str",
|
||||||
|
"args": [{ "t": "var", "name": "s1" }] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -12,14 +12,14 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "test_22b1_dup_classmod.Show",
|
"class": "test_22b1_dup_classmod.TShow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "con",
|
"k": "con",
|
||||||
"name": "test_22b1_dup_b.MyInt"
|
"name": "test_22b1_dup_b.MyInt"
|
||||||
},
|
},
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": {
|
"body": {
|
||||||
"t": "lit",
|
"t": "lit",
|
||||||
"lit": {
|
"lit": {
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "test_22b1_dup_classmod.Show",
|
"class": "test_22b1_dup_classmod.TShow",
|
||||||
"type": { "k": "con", "name": "MyInt" },
|
"type": { "k": "con", "name": "MyInt" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "from-b" } }
|
"body": { "t": "lit", "lit": { "kind": "str", "value": "from-b" } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -21,22 +21,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "first" } }
|
"body": { "t": "lit", "lit": { "kind": "str", "value": "first" } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "second" } }
|
"body": { "t": "lit", "lit": { "kind": "str", "value": "second" } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "<int>" } }
|
"body": { "t": "lit", "lit": { "kind": "str", "value": "<int>" } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "test_22b1_orphan_third_classmod.Show",
|
"class": "test_22b1_orphan_third_classmod.TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "<int>" } }
|
"body": { "t": "lit", "lit": { "kind": "str", "value": "<int>" } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": { "t": "lit", "lit": { "kind": "str", "value": "n" } }
|
"body": { "t": "lit", "lit": { "kind": "str", "value": "n" } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"k": "forall",
|
"k": "forall",
|
||||||
"vars": ["a"],
|
"vars": ["a"],
|
||||||
"constraints": [
|
"constraints": [
|
||||||
{ "class": "Show", "type": { "k": "var", "name": "a" } }
|
{ "class": "TShow", "type": { "k": "var", "name": "a" } }
|
||||||
],
|
],
|
||||||
"body": {
|
"body": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "var", "name": "x" }]
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"imports": [],
|
"imports": [],
|
||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class", "name": "Show", "param": "a",
|
"kind": "class", "name": "TShow", "param": "a",
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
||||||
"ret": { "k": "con", "name": "Str" }, "effects": []
|
"ret": { "k": "con", "name": "Str" }, "effects": []
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": {
|
"body": {
|
||||||
"t": "lam",
|
"t": "lam",
|
||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"params": [],
|
"params": [],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// module test_22b2_instance_present
|
// module test_22b2_instance_present
|
||||||
|
|
||||||
class Show a {
|
class TShow a {
|
||||||
fn show(x: a) -> Str
|
fn tshow(x: a) -> Str
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Show Int {
|
instance TShow Int {
|
||||||
fn show {
|
fn tshow {
|
||||||
|x: a| -> Str {
|
|x: a| -> Str {
|
||||||
"n"
|
"n"
|
||||||
}
|
}
|
||||||
@@ -13,5 +13,5 @@ instance Show Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Str {
|
fn main() -> Str {
|
||||||
show(42)
|
tshow(42)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "var", "name": "x" }]
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"params": [],
|
"params": [],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "var", "name": "x" }]
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"params": ["y"],
|
"params": ["y"],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "var", "name": "y" }]
|
"args": [{ "t": "var", "name": "y" }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": {
|
"body": {
|
||||||
"t": "lam",
|
"t": "lam",
|
||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class",
|
"kind": "class",
|
||||||
"name": "Show",
|
"name": "TShow",
|
||||||
"param": "a",
|
"param": "a",
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn",
|
"k": "fn",
|
||||||
"params": [{ "k": "var", "name": "a" }],
|
"params": [{ "k": "var", "name": "a" }],
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"params": [],
|
"params": [],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "var", "name": "x" }]
|
"args": [{ "t": "var", "name": "x" }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"params": [],
|
"params": [],
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"imports": [],
|
"imports": [],
|
||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class", "name": "Show", "param": "a",
|
"kind": "class", "name": "TShow", "param": "a",
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
||||||
"ret": { "k": "con", "name": "Str" }, "effects": []
|
"ret": { "k": "con", "name": "Str" }, "effects": []
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": {
|
"body": {
|
||||||
"t": "lam",
|
"t": "lam",
|
||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
@@ -41,12 +41,12 @@
|
|||||||
"name": "_a",
|
"name": "_a",
|
||||||
"value": {
|
"value": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 5 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 5 } }]
|
||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 7 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 7 } }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"imports": [],
|
"imports": [],
|
||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class", "name": "Show", "param": "a",
|
"kind": "class", "name": "TShow", "param": "a",
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
||||||
"ret": { "k": "con", "name": "Str" }, "effects": []
|
"ret": { "k": "con", "name": "Str" }, "effects": []
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": {
|
"body": {
|
||||||
"t": "lam",
|
"t": "lam",
|
||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"imports": [],
|
"imports": [],
|
||||||
"defs": [
|
"defs": [
|
||||||
{
|
{
|
||||||
"kind": "class", "name": "Show", "param": "a",
|
"kind": "class", "name": "TShow", "param": "a",
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"type": {
|
"type": {
|
||||||
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
"k": "fn", "params": [{ "k": "var", "name": "a" }],
|
||||||
"ret": { "k": "con", "name": "Str" }, "effects": []
|
"ret": { "k": "con", "name": "Str" }, "effects": []
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "instance",
|
"kind": "instance",
|
||||||
"class": "Show",
|
"class": "TShow",
|
||||||
"type": { "k": "con", "name": "Int" },
|
"type": { "k": "con", "name": "Int" },
|
||||||
"methods": [{
|
"methods": [{
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"body": {
|
"body": {
|
||||||
"t": "lam",
|
"t": "lam",
|
||||||
"params": ["x"],
|
"params": ["x"],
|
||||||
@@ -66,17 +66,17 @@
|
|||||||
"name": "_t",
|
"name": "_t",
|
||||||
"value": {
|
"value": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "show" },
|
"fn": { "t": "var", "name": "tshow" },
|
||||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 5 } }]
|
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 5 } }]
|
||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
"t": "let",
|
"t": "let",
|
||||||
"name": "show",
|
"name": "tshow",
|
||||||
"value": { "t": "lit", "lit": { "kind": "str", "value": "shadow" } },
|
"value": { "t": "lit", "lit": { "kind": "str", "value": "shadow" } },
|
||||||
"body": {
|
"body": {
|
||||||
"t": "let",
|
"t": "let",
|
||||||
"name": "_u",
|
"name": "_u",
|
||||||
"value": { "t": "var", "name": "show" },
|
"value": { "t": "var", "name": "tshow" },
|
||||||
"body": {
|
"body": {
|
||||||
"t": "app",
|
"t": "app",
|
||||||
"fn": { "t": "var", "name": "foo" },
|
"fn": { "t": "var", "name": "foo" },
|
||||||
|
|||||||
Reference in New Issue
Block a user