From 385ecc5c484eda1ed91d6a23cb3eaedc2845c0eb Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 12 Sep 2026 22:56:16 +0700 Subject: [PATCH] () 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. --- lib/parse.ml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/parse.ml b/lib/parse.ml index 30b0263..7d3153d 100644 --- a/lib/parse.ml +++ b/lib/parse.ml @@ -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