Iter 16d: chain-terminator via __unreachable__ builtin

Eliminates the Unit-typed chain default that 16c left in place.
Adds __unreachable__ : forall a. a — codegen lowers to LLVM
unreachable. The 16a/16c chain machinery now uses it as the
deepest fall-through, so exhaustive matches with non-Unit arms
no longer need a (case _ ...) workaround.

- check/builtins.rs: register __unreachable__ as Forall(a, a).
- codegen: Term::Var "__unreachable__" emits LLVM unreachable
  and sets block_terminated; If/Match/fn-body gate downstream
  work on that flag.
- desugar: chain default switched from Lit{Unit} to Var.
- examples/lit_pat: categorize_first's trailing _ arm removed.
  Hash changes from c4faec3abc2ed388 to 644de0c0ec15fc17.
- examples/unreachable_demo: positive fixture using safe_div
  with __unreachable__ in the impossible branch.
- e2e + desugar tests: 122 → 124 (+2).

Path-a from 16b.2 planning: real primitive over a desugar-time
exhaustiveness pre-check (which would need cross-module type
registry access from desugar).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 23:00:23 +02:00
parent e5f9828a04
commit af35612c1d
10 changed files with 353 additions and 14 deletions
+20
View File
@@ -863,6 +863,20 @@ impl<'a> Emitter<'a> {
Literal::Unit => ("0".into(), "i8".into()),
}),
Term::Var { name } => {
// Iter 16d: `__unreachable__` is a polymorphic bottom
// value (`forall a. a`). At codegen we emit LLVM
// `unreachable` as the block terminator and return a
// dummy SSA value. The surrounding `if`/`match`/`seq`
// already inspects `block_terminated` and forwards the
// sibling branch's type, so the type we report here is
// not consumed by a phi node — `i8` is a sound
// placeholder. Subsequent emissions in this block are
// gated by `block_terminated`.
if name == "__unreachable__" {
self.body.push_str(" unreachable\n");
self.block_terminated = true;
return Ok(("0".into(), "i8".into()));
}
if let Some((_, ssa, ty, _)) =
self.locals.iter().rev().find(|(n, _, _, _)| n == name)
{
@@ -2632,6 +2646,12 @@ fn builtin_ail_type(name: &str) -> Option<Type> {
ret: Box::new(Type::bool_()),
effects: vec![],
},
// Iter 16d: `__unreachable__` is the polymorphic bottom value
// (`forall a. a`). Mirrors the typechecker's `builtins::install`.
"__unreachable__" => Type::Forall {
vars: vec!["a".into()],
body: Box::new(Type::Var { name: "a".into() }),
},
_ => return None,
})
}