A refused dyn view of a global names its own defining form as the fix, and every dyn fix is spelled in the syntax the code was written in

This commit is contained in:
Joseph Ferano 2026-09-25 22:27:36 +07:00
parent c1b21edaf4
commit 35aa5a8c0f
4 changed files with 46 additions and 5 deletions

View File

@ -3454,7 +3454,13 @@ let view_elem_lit loc (k : int64) =
(* A fix is spelled in the syntax of the file the mistake is in: the checker (* A fix is spelled in the syntax of the file the mistake is in: the checker
sees one AST for both, so the location's file is the only thing left that sees one AST for both, so the location's file is the only thing left that
says which one the reader is looking at. *) says which one the reader is looking at. *)
let fln_source (loc : Loc.t) = Filename.check_suffix loc.Loc.file ".fln" let fln_source (loc : Loc.t) = Source.indented_at loc
(* Which form defined each mutable global, [defonce] or [def], so a fix that
rewrites the definition keeps the form the programmer chose. Filled where
globals are collected; a name missing from it (a defconst) is given
[defonce]. *)
let global_forms : (string, Ast.reinit) Hashtbl.t = Hashtbl.create 16
(* The function being checked and its parameters, by slot. A stack because (* The function being checked and its parameters, by slot. A stack because
a generic's copy is checked from inside the body that called it. *) a generic's copy is checked from inside the body that called it. *)
@ -3496,6 +3502,18 @@ let view_refusal kind loc (e : Tast.expr) reason =
( Printf.sprintf "%s is a %s parameter" n ty, ( Printf.sprintf "%s is a %s parameter" n ty,
Printf.sprintf "Declare %s as dyn in %s's parameters: %s%s" n f n Printf.sprintf "Declare %s as dyn in %s's parameters: %s%s" n f n
(if fln then ": dyn" else " dyn") ) (if fln then ": dyn" else " dyn") )
| None, Some n when (match e.Tast.e with Tast.Global _ -> true | _ -> false) ->
let every =
match e.Tast.e with
| Tast.Global g -> Hashtbl.find_opt global_forms g = Some Ast.Every
| _ -> false
in
( Printf.sprintf "%s is a %s" n ty,
Printf.sprintf "Define %s as a dyn value, as in %s" n
(if fln then
Printf.sprintf "%s %s: dyn = [...]" (if every then "def" else "once") n
else
Printf.sprintf "(%s %s dyn [...])" (if every then "def" else "defonce") n) )
| None, Some n -> | None, Some n ->
( Printf.sprintf "%s is a %s" n ty, ( Printf.sprintf "%s is a %s" n ty,
Printf.sprintf "Build %s as a dyn value where it is made, as in %s" n Printf.sprintf "Build %s as a dyn value where it is made, as in %s" n
@ -14601,6 +14619,7 @@ let collect env (decls : Ast.decl list) =
(match k with Ast.Once -> "defonce" | Ast.Every -> "def") n (match k with Ast.Once -> "defonce" | Ast.Every -> "def") n
in in
Hashtbl.replace env.globals n (ty, false); Hashtbl.replace env.globals n (ty, false);
Hashtbl.replace global_forms n k;
Hashtbl.replace env.global_locs n loc Hashtbl.replace env.global_locs n loc
| Ast.Defconst (n, Some t, _) -> | Ast.Defconst (n, Some t, _) ->
Hashtbl.replace env.globals n (resolve env t, true); Hashtbl.replace env.globals n (resolve env t, true);

View File

@ -610,6 +610,28 @@ let () =
checks "view-param-fix.fln" checks "view-param-fix.fln"
"fn take(d) -> i32 = 1\n\nfn give(n: i32, v: dyn) -> i32\n take(v)\n\n\ "fn take(d) -> i32 = 1\n\nfn give(n: i32, v: dyn) -> i32\n take(v)\n\n\
fn main() -> i32 = 0\n"; fn main() -> i32 = 0\n";
(* A global's fix redefines it, in the form it was defined with. *)
let show_flan = "(defn show [d dyn] i32 1)\n" in
refused "view-global.flan"
("(defonce gs [2 i32] [1 2])\n" ^ show_flan ^ "(defn main [] i32 (show gs))\n")
[ "gs is a [2 i32]"; "as in (defonce gs dyn [...])" ];
refused "view-global-def.flan"
("(def gs [2 i32] [1 2])\n" ^ show_flan ^ "(defn main [] i32 (show gs))\n")
[ "as in (def gs dyn [...])" ];
refused "view-global.fln"
"once gs: [2 i32] = [1 2]\n\nfn show(d) -> i32 = 1\n\nfn main() -> i32 = show(gs)\n"
[ "gs is a [2 i32]"; "as in once gs: dyn = [...]" ];
checks "view-global-fix.flan"
("(defonce gs dyn [1 2])\n(def hs dyn [1 2])\n" ^ show_flan
^ "(defn main [] i32 (show gs) (show hs))\n");
checks "view-global-fix.fln"
"once gs: dyn = [1 2]\n\nfn show(d) -> i32 = 1\n\nfn main() -> i32 = show(gs)\n";
(* The fix is spelled in the syntax the code was sent in, not the one the
file's name implies: an editor request from an indented buffer. *)
Source.with_code ~syntax:Source.Indented ~at:None (fun () ->
refused "unit-tail-request.flan"
"(defn f [coll] dyn (let [i 1] (while (< i 3) (++ i))))\n(defn main [] () (f 1))\n"
[ "fn f(...) -> ()" ]);
(* The fix both of them name. *) (* The fix both of them name. *)
checks "view-fix.fln" checks "view-fix.fln"
(poke_fln ^ "fn main() -> ()\n let d: dyn = [6 2 4 9]\n poke(d)\n poke(the(dyn, [1 2]))\n"); (poke_fln ^ "fn main() -> ()\n let d: dyn = [6 2 4 9]\n poke(d)\n poke(the(dyn, [1 2]))\n");