defvar in a .fln file suggests once and def in its spelling, and x++ on a global suggests ++(x)

This commit is contained in:
Joseph Ferano 2026-09-25 23:48:59 +07:00
parent dca29a5605
commit dbddc61b30
3 changed files with 21 additions and 2 deletions

View File

@ -9041,7 +9041,7 @@ and unknown_name : 'a. ?setting:bool -> ctx -> Loc.t -> string -> 'a =
let n = String.length name in let n = String.length name in
let stem = if n > 2 then String.sub name 0 (n - 2) else "" in let stem = if n > 2 then String.sub name 0 (n - 2) else "" in
let suffix = if n > 2 then String.sub name (n - 2) 2 else "" in let suffix = if n > 2 then String.sub name (n - 2) 2 else "" in
if (suffix = "++" || suffix = "--") && lookup ctx stem <> None then if (suffix = "++" || suffix = "--") && List.mem stem (value_candidates ctx) then
Loc.failk "check/unknown-name" loc Loc.failk "check/unknown-name" loc
"unknown name %s — to %s %s, write %s" "unknown name %s — to %s %s, write %s"
name (if suffix = "++" then "add one to" else "take one from") stem name (if suffix = "++" then "add one to" else "take one from") stem

View File

@ -1972,7 +1972,22 @@ let rec decl (f : Form.t) : Ast.decl =
rule against a suggestion that does not compile. The shapes alone rule against a suggestion that does not compile. The shapes alone
then, which is what there is to say about a form that named too then, which is what there is to say about a form that named too
little. *) little. *)
let atom (x : Form.t) = match x.v with Form.List _ | Form.Vec _ | Form.Map _ -> false | _ -> true in
(match args with (match args with
(* In a .fln file, the two definitions in its spelling. *)
| [ n; v ] when Source.indented_at f.loc && atom n ->
let rest =
Form.to_string n ^ " = " ^ (if atom v then Form.to_string v else "...") in
Loc.failk "parse/defvar-renamed" f.loc
"there is no defvar. Did you mean once? once %s initialises once and \
keeps its value; def %s re-initialises on every re-run" rest rest
| [ n; t; v ] when Source.indented_at f.loc && atom n && atom t ->
let rest =
Form.to_string n ^ ": " ^ Form.to_string t ^ " = "
^ (if atom v then Form.to_string v else "...") in
Loc.failk "parse/defvar-renamed" f.loc
"there is no defvar. Did you mean once? once %s initialises once and \
keeps its value; def %s re-initialises on every re-run" rest rest
| [] | [ _ ] -> | [] | [ _ ] ->
Loc.failk "parse/defvar-renamed" f.loc Loc.failk "parse/defvar-renamed" f.loc
"there is no defvar. Did you mean defonce? \ "there is no defvar. Did you mean defonce? \

View File

@ -980,7 +980,11 @@ let () =
refused "untyped-lambda.fln" "fn main() -> i32\n let f = fn(a)\n a\n 0\n" refused "untyped-lambda.fln" "fn main() -> i32\n let f = fn(a)\n a\n 0\n"
[ "let f: Fn(T, ...) -> R = fn(...)" ]; [ "let f: Fn(T, ...) -> R = fn(...)" ];
refused "plusplus.fln" "fn main() -> i32\n let x = 1\n x++\n x\n" refused "plusplus.fln" "fn main() -> i32\n let x = 1\n x++\n x\n"
[ "write ++(x) or x += 1" ] [ "write ++(x) or x += 1" ];
refused "plusplus-global.fln" "once g = 0\n\nfn main() -> i32\n g--\n 0\n"
[ "write --(g) or g -= 1" ];
refused "defvar.fln" "defvar(x, 1)\n\nfn main() -> i32 = 0\n"
[ "once x = 1 initialises once"; "def x = 1 re-initialises" ]
(* ── Both directions of an import, on both backends ────────────────── *) (* ── Both directions of an import, on both backends ────────────────── *)