Iter 16e: == polymorphic over Int / Bool / Str / Unit
Lifts the Int-only restriction on `==`. Declared type becomes
forall a. Fn(a, a) -> Bool; codegen monomorphises and dispatches:
Int → icmp eq i64
Bool → icmp eq i1
Str → call @strcmp + icmp eq i32 0
Unit → constant true (operands still emitted for side effects)
ADT / Fn / other → CodegenError::Internal
This unblocks 16c's build_eq for non-Int lit patterns. == joins
__unreachable__ as the second polymorphic builtin (same Forall
machinery).
- check/builtins.rs: == registered as Forall(a, Fn(a, a) -> Bool).
- codegen: lower_eq dispatch table; @strcmp declared in IR header
alongside @printf/@GC_malloc/@puts.
- examples/eq_demo.{ailx,ail.json}: covers all four supported
scalars including a Str-lit-pattern match.
- IR snapshots refreshed: only +declare i32 @strcmp(ptr, ptr) in
the header; every define body bit-identical.
- e2e + check + codegen tests: 124 → 133 (+9, of which +1 is the
e2e fixture and the rest exercise the new dispatch / typecheck
surface).
Other comparison ops (<, <=, >, >=, !=) remain Int-only — out of
scope for this iter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+42
-18
@@ -773,7 +773,11 @@ collector wired up in Iter 14f, see Decision 9); nested constructor
|
||||
sub-patterns inside `match` (lifted in Iter 16a via the desugar pass);
|
||||
literal sub-patterns inside a Ctor pattern (lifted in Iter 16c — the
|
||||
desugar pass rewrites every `Pattern::Lit` to a `Term::If` on `==`,
|
||||
both at the top level of an arm and inside a Ctor sub-pattern).
|
||||
both at the top level of an arm and inside a Ctor sub-pattern);
|
||||
`==` extended from Int-only to a polymorphic
|
||||
`forall a. (a, a) -> Bool` over `Int`/`Bool`/`Str`/`Unit` (lifted
|
||||
in Iter 16e — codegen monomorphises and dispatches on the
|
||||
resolved arg type; ADT/Fn arg types are rejected at codegen).
|
||||
|
||||
- No effect handlers — only the built-in IO and Diverge ops.
|
||||
- No refinements / SMT escalation.
|
||||
@@ -798,19 +802,39 @@ What **is** supported (and used as the smoke test for the pipeline):
|
||||
- `if`, `let`, function calls, recursion.
|
||||
- Effects on function signatures, with `do op(args)` for direct effect
|
||||
ops (`io/print_int`, `io/print_bool`, `io/print_str`).
|
||||
- **Builtins.** Arithmetic and comparison operators (`+`, `-`, `*`,
|
||||
`/`, `%`, `==`, `!=`, `<`, `<=`, `>`, `>=`) of type
|
||||
`(Int, Int) -> Int` / `Bool`; logical `not : (Bool) -> Bool`; the
|
||||
IO effect ops listed above; and **`__unreachable__ : forall a. a`**
|
||||
(Iter 16d). The latter is a polymorphic bottom value: a use of
|
||||
`__unreachable__` typechecks against any expected type at the use
|
||||
site and codegens to the LLVM `unreachable` instruction (UB if
|
||||
ever executed). It is the chain machinery's deepest fall-through
|
||||
for matches that the typechecker proved exhaustive, and it is
|
||||
available to user code as an explicit panic primitive
|
||||
(`(if cond __unreachable__ ...)` for assertions or impossible
|
||||
branches). Reference site is `Term::Var { name = "__unreachable__" }`
|
||||
/ form-A bare `__unreachable__`.
|
||||
- **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`, `%`) of
|
||||
type `(Int, Int) -> Int`; ordering operators and `!=` (`!=`,
|
||||
`<`, `<=`, `>`, `>=`) of type `(Int, Int) -> Bool`; logical
|
||||
`not : (Bool) -> Bool`; the IO effect ops listed above;
|
||||
**`==` : forall a. (a, a) -> Bool** (Iter 16e); and
|
||||
**`__unreachable__ : forall a. a`** (Iter 16d).
|
||||
- **`==` is polymorphic** (Iter 16e). The typechecker accepts
|
||||
`==` at any type whose two sides agree (the rigid `a` of the
|
||||
`Forall` is unified by HM at the use site). Codegen
|
||||
monomorphises and dispatches on the resolved AIL arg type:
|
||||
`Int` → `icmp eq i64`; `Bool` → `icmp eq i1`;
|
||||
`Str` → `call @strcmp(ptr, ptr)` then `icmp eq i32 0`
|
||||
(`@strcmp` is declared in the LLVM IR header alongside
|
||||
`@printf` / `@GC_malloc`); `Unit` → constant `i1 true`
|
||||
(Unit has a single inhabitant; both sides are still
|
||||
evaluated for any side effects). ADT and `Fn` arg types are
|
||||
rejected at codegen with a `CodegenError::Internal`
|
||||
mentioning `==` and the offending type — neither has a
|
||||
canonical structural-equality scheme yet, and the language
|
||||
deliberately does not silently elide the check. The other
|
||||
comparison ops stay Int-only; their codegen path emits
|
||||
`icmp s{lt,le,gt,ge,ne}` over `i64`.
|
||||
- **`__unreachable__`** is a polymorphic bottom value: a use of
|
||||
`__unreachable__` typechecks against any expected type at
|
||||
the use site and codegens to the LLVM `unreachable`
|
||||
instruction (UB if ever executed). It is the chain
|
||||
machinery's deepest fall-through for matches that the
|
||||
typechecker proved exhaustive, and it is available to user
|
||||
code as an explicit panic primitive
|
||||
(`(if cond __unreachable__ ...)` for assertions or
|
||||
impossible branches). Reference site is
|
||||
`Term::Var { name = "__unreachable__" }` / form-A bare
|
||||
`__unreachable__`.
|
||||
- **ADTs + pattern matching** (Iter 3, extended in Iter 16a/16c).
|
||||
Sub-patterns of a Ctor pattern may be `Var`, `Wild`, another `Ctor`
|
||||
(Iter 16a), or a literal (Iter 16c). The desugar pass flattens
|
||||
@@ -820,10 +844,10 @@ What **is** supported (and used as the smoke test for the pipeline):
|
||||
- Literal patterns at top level and inside Ctor sub-patterns (Iter 16c,
|
||||
via desugar). `(pat-lit 0)` and `(pat-ctor Cons (pat-lit 0) _)` both
|
||||
parse and lower; the rewrite is to `Term::If { cond = (== sv lit) }`,
|
||||
so any literal kind whose `==` is supported by the typechecker is
|
||||
authorable. Today that means `Int`; `Bool`/`Str`/`Unit` lit patterns
|
||||
are accepted by desugar but reach typecheck as a type error because
|
||||
`==` is `(Int, Int) -> Bool` only.
|
||||
so any literal kind whose `==` is supported is authorable. After
|
||||
Iter 16e (`==` polymorphic over `Int`/`Bool`/`Str`/`Unit`), that
|
||||
covers every lit kind the AST ships — including `(pat-lit "hi")`
|
||||
over a `Str` scrutinee, exercised by `examples/eq_demo.ail.json`.
|
||||
- **Imports + qualified cross-module references** via dotted names
|
||||
(Iter 5). Extends to **types and constructors** (Iter 14h): a foreign
|
||||
module's ADT is referenced as `(con std_pair.Pair a b)`, its ctors as
|
||||
|
||||
Reference in New Issue
Block a user