A loop, dotimes, match, macro, class or generic binding that starts with $ is refused too

This commit is contained in:
Joseph Ferano 2026-09-25 10:37:43 +07:00
parent 83b244475a
commit 222dc0ae90
3 changed files with 16 additions and 7 deletions

View File

@ -622,9 +622,10 @@ arguments, which can pick the wrong one of two equal subtrees.
** DONE A declared name may carry the $ sigil ** DONE A declared name may carry the $ sigil
CLOSED: [2026-09-25] CLOSED: [2026-09-25]
A name that starts with =$= is refused where it is declared — every top-level A name that starts with =$= is refused where it is declared — every top-level
form, a struct or union field, an enum member, a data case and a =let= name — form, a struct or union field, an enum member, a data case, a class slot, and a
saying =$= marks a type variable and naming the bare spelling. A parameter was =let=, =loop=, =dotimes=, =match=, macro or generic binding — saying =$= marks a
already refused, as a type in a name slot. type variable and naming the bare spelling. A =defn= parameter was already
refused, as a type in a name slot.
* Checker * Checker

View File

@ -177,6 +177,7 @@ and dyn_params which (items : Form.t list) : Ast.field list =
(fun (it : Form.t) -> (fun (it : Form.t) ->
match it.v with match it.v with
| Sym s -> | Sym s ->
no_sigil it;
{ Ast.fname = s; { Ast.fname = s;
fty = { Ast.t = Ast.Tname "dyn"; tloc = it.loc }; fty = { Ast.t = Ast.Tname "dyn"; tloc = it.loc };
floc = it.loc } floc = it.loc }
@ -554,7 +555,7 @@ and form f mk (head : Form.t) (args : Form.t list) : Ast.expr =
{ Ast.dstart = Some start; dstop = stop; dstep = Some step } { Ast.dstart = Some start; dstop = stop; dstep = Some step }
| _ -> assert false | _ -> assert false
in in
mk (Ast.Dotimes (lbl, sym n, b, body_of body)) mk (Ast.Dotimes (lbl, dname n, b, body_of body))
| _ -> | _ ->
fail f fail f
"dotimes is (dotimes [name stop] body ...), \ "dotimes is (dotimes [name stop] body ...), \
@ -800,7 +801,7 @@ and loop_bindings f (items : Form.t list) : (string * Ast.expr) list =
| [] -> [] | [] -> []
| name :: value :: rest -> | name :: value :: rest ->
no_pattern name; no_pattern name;
(sym name, expr value) :: go rest (dname name, expr value) :: go rest
| [ odd ] -> | [ odd ] ->
Loc.fail odd.loc Loc.fail odd.loc
"binding %s has no value — loop takes name/value pairs" "binding %s has no value — loop takes name/value pairs"
@ -1237,7 +1238,7 @@ and pattern (f : Form.t) : Ast.pattern =
member member member member
| List ({ v = Sym ctor; _ } :: binds) -> | List ({ v = Sym ctor; _ } :: binds) ->
List.iter no_pattern binds; List.iter no_pattern binds;
Ast.Pctor (ctor, List.map sym binds) Ast.Pctor (ctor, List.map dname binds)
| _ -> fail f "expected a pattern, found %s" (Form.to_string f) | _ -> fail f "expected a pattern, found %s" (Form.to_string f)
(* ── The third element of a defonce or a def ─────────────────────────── (* ── The third element of a defonce or a def ───────────────────────────
@ -1485,7 +1486,7 @@ let rec decl (f : Form.t) : Ast.decl =
List.map List.map
(fun (s : Form.t) -> (fun (s : Form.t) ->
match s.v with match s.v with
| Sym name -> (name, s.loc) | Sym name -> no_sigil s; (name, s.loc)
| _ -> | _ ->
fail s fail s
"a class slot is a name — its value is dyn, so there \ "a class slot is a name — its value is dyn, so there \

View File

@ -6341,6 +6341,13 @@ let () =
sigil "defdata case" "(defdata D [($C [a i32])])"; sigil "defdata case" "(defdata D [($C [a i32])])";
sigil "defmacro" "(defmacro $m [x] x)"; sigil "defmacro" "(defmacro $m [x] x)";
sigil "a let binding" "(defn f [] i32 (let [$y 1] y))"; sigil "a let binding" "(defn f [] i32 (let [$y 1] y))";
sigil "a dotimes counter" "(defn f [] () (dotimes [$i 3] (println i)))";
sigil "a loop binding" "(defn f [] i32 (loop [$i 0] i))";
sigil "a match bind"
"(defdata D [(C [a i32])]) (defn f [d D] i32 (match d (D.C $x) x))";
sigil "a macro parameter" "(defmacro m [$x] x)";
sigil "a class slot" "(defclass K [$s])";
sigil "a generic's parameter" "(defgeneric area [$s] f64)";
parse_rejects "the $ refusal names the bare spelling" parse_rejects "the $ refusal names the bare spelling"
"(defn $foo [x i32] i32 x)" ~needle:"Name it foo"; "(defn $foo [x i32] i32 x)" ~needle:"Name it foo";