From 7172e7e8c9156516b56bf426df05bb64d7da907f Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 10 May 2026 22:35:51 +0200 Subject: [PATCH] =?UTF-8?q?iter=2023.2.3:=20prelude=20=E2=80=94=20class=20?= =?UTF-8?q?Eq=20a=20+=20Eq=20Int/Bool/Str=20instances?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/ailang-core/src/workspace.rs | 36 ++++++++++ examples/prelude.ail.json | 105 ++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/crates/ailang-core/src/workspace.rs b/crates/ailang-core/src/workspace.rs index 36f0eef..5122344 100644 --- a/crates/ailang-core/src/workspace.rs +++ b/crates/ailang-core/src/workspace.rs @@ -920,6 +920,42 @@ mod tests { )), "prelude must contain Ordering type def" ); + + // Iter 23.2: prelude also ships the `Eq` class plus three + // primitive instances (Eq Int, Eq Bool, Eq Str). + assert!( + prelude.defs.iter().any(|d| matches!( + d, + crate::ast::Def::Class(c) if c.name == "Eq" + )), + "prelude must contain Eq class def" + ); + let eq_instance_types: Vec<&str> = prelude + .defs + .iter() + .filter_map(|d| match d { + crate::ast::Def::Instance(i) if i.class == "Eq" => { + if let crate::ast::Type::Con { name, .. } = &i.type_ { + Some(name.as_str()) + } else { + None + } + } + _ => None, + }) + .collect(); + assert!( + eq_instance_types.contains(&"Int"), + "prelude must contain `instance Eq Int`; saw Eq instances on: {eq_instance_types:?}" + ); + assert!( + eq_instance_types.contains(&"Bool"), + "prelude must contain `instance Eq Bool`; saw Eq instances on: {eq_instance_types:?}" + ); + assert!( + eq_instance_types.contains(&"Str"), + "prelude must contain `instance Eq Str`; saw Eq instances on: {eq_instance_types:?}" + ); } #[test] diff --git a/examples/prelude.ail.json b/examples/prelude.ail.json index a56ce9e..190ecef 100644 --- a/examples/prelude.ail.json +++ b/examples/prelude.ail.json @@ -13,6 +13,111 @@ { "name": "EQ", "fields": [] }, { "name": "GT", "fields": [] } ] + }, + { + "kind": "class", + "name": "Eq", + "param": "a", + "doc": "Structural equality. Ships in milestone 23 alongside Ord. The primitive `==` operator stays as the surface-level comparator this iter; routing `==` through `Eq.eq` is the declared P2 follow-up (see docs/specs/2026-05-10-23-eq-ord-prelude.md, `Out of scope`).", + "methods": [ + { + "name": "eq", + "type": { + "k": "fn", + "params": [ + { "k": "var", "name": "a" }, + { "k": "var", "name": "a" } + ], + "param_modes": ["borrow", "borrow"], + "ret": { "k": "con", "name": "Bool" }, + "effects": [] + } + } + ] + }, + { + "kind": "instance", + "class": "Eq", + "type": { "k": "con", "name": "Int" }, + "doc": "Eq Int. Body lowers to `icmp eq i64` via the existing primitive `==` dispatch in `lower_eq`.", + "methods": [ + { + "name": "eq", + "body": { + "t": "lam", + "params": ["x", "y"], + "paramTypes": [ + { "k": "var", "name": "a" }, + { "k": "var", "name": "a" } + ], + "retType": { "k": "con", "name": "Bool" }, + "body": { + "t": "app", + "fn": { "t": "var", "name": "==" }, + "args": [ + { "t": "var", "name": "x" }, + { "t": "var", "name": "y" } + ] + } + } + } + ] + }, + { + "kind": "instance", + "class": "Eq", + "type": { "k": "con", "name": "Bool" }, + "doc": "Eq Bool. Body lowers to `icmp eq i1` via the existing primitive `==` dispatch in `lower_eq`.", + "methods": [ + { + "name": "eq", + "body": { + "t": "lam", + "params": ["x", "y"], + "paramTypes": [ + { "k": "var", "name": "a" }, + { "k": "var", "name": "a" } + ], + "retType": { "k": "con", "name": "Bool" }, + "body": { + "t": "app", + "fn": { "t": "var", "name": "==" }, + "args": [ + { "t": "var", "name": "x" }, + { "t": "var", "name": "y" } + ] + } + } + } + ] + }, + { + "kind": "instance", + "class": "Eq", + "type": { "k": "con", "name": "Str" }, + "doc": "Eq Str. The lambda body shape mirrors Int/Bool for round-trip stability, but the codegen intercept in `emit_fn` overrides the body to call `@ail_str_eq` directly — see `try_emit_primitive_instance_body` in `crates/ailang-codegen/src/lib.rs`.", + "methods": [ + { + "name": "eq", + "body": { + "t": "lam", + "params": ["x", "y"], + "paramTypes": [ + { "k": "var", "name": "a" }, + { "k": "var", "name": "a" } + ], + "retType": { "k": "con", "name": "Bool" }, + "body": { + "t": "app", + "fn": { "t": "var", "name": "==" }, + "args": [ + { "t": "var", "name": "x" }, + { "t": "var", "name": "y" } + ] + } + } + } + ] } ] }