() is the unit type, accepted alongside the old spelling

The slot after a defn's parameters is about to become mandatory, and a void
function has to have something to write there. () is ML's spelling and it
cannot collide: an empty call is not a valid expression, so () has no reading
in value position for a body form to be confused with.

Additive on its own. Internally it stays Tname "Unit" -- the resolver, the
shim and the emitter all speak that name and none of them change -- so this is
two arms in parse.ml: texpr reads () as the unit type, and is_type_form says
that a leading () is a return type rather than the first form of a body.
This commit is contained in:
Joseph Ferano 2026-09-12 22:56:16 +07:00
parent 8d8346e58a
commit 385ecc5c48

View File

@ -64,6 +64,12 @@ let builtin_types =
let rec texpr (f : Form.t) : Ast.texpr =
let mk t = { Ast.t; tloc = f.loc } in
match f.v with
(* Unit is spelled [()], ML's spelling. It is the honest name, and it cannot
collide with anything: an empty call is not a valid expression, so [()] has
no reading in value position to be confused with. Internally it stays
[Tname "Unit"] -- the resolver, the shim and the emitter all speak that
name, and diagnostics still print it. *)
| List [] -> mk (Ast.Tname "Unit")
| Sym s -> mk (Ast.Tname s)
| Vec [ elem ] -> mk (Ast.Tslice (texpr elem))
| Vec [ n; elem ] -> mk (Ast.Tarray (len n, texpr elem))
@ -865,6 +871,7 @@ and qualified_type types s =
and is_type_form types (f : Form.t) =
match f.v with
| List [] -> true (* () is unit, never a body form *)
| Sym s ->
Names.mem s types || Names.mem ("enum " ^ s) types
|| Names.mem ("prelude " ^ s) types || qualified_type types s