A program's global named as a prelude function or global shadows it for the file, with the shadowing warning a defn gets

This commit is contained in:
Joseph Ferano 2026-09-25 17:12:05 +07:00
parent 20684c2d9f
commit d6e6a5dc0c
4 changed files with 48 additions and 8 deletions

View File

@ -14543,30 +14543,37 @@ let shown_name n =
else n else n
let shadow_prelude (prelude : Ast.decl list) (decls : Ast.decl list) = let shadow_prelude (prelude : Ast.decl list) (decls : Ast.decl list) =
let fn_name (d : Ast.decl) = (* A value name, and whether it is a function's. A program's global takes
a prelude function's name over as a program's function does: both are
names a call or a read reaches, and the prelude's own uses keep the
prelude's. *)
let value_name (d : Ast.decl) =
match d.Ast.d with match d.Ast.d with
| Ast.Defn fn | Ast.Declare (fn, _) | Ast.DeclareC (fn, _) -> Some fn.Ast.name | Ast.Defn fn | Ast.Declare (fn, _) | Ast.DeclareC (fn, _) ->
Some (fn.Ast.name, true)
| Ast.Defvar (n, _, _, _) | Ast.Defconst (n, _, _) -> Some (n, false)
| _ -> None | _ -> None
in in
let theirs = List.filter_map fn_name prelude in let theirs = List.map fst (List.filter_map value_name prelude) in
let taken = let taken =
List.filter_map List.filter_map
(fun (d : Ast.decl) -> (fun (d : Ast.decl) ->
match fn_name d with match value_name d with
| Some n when List.mem n theirs -> Some (n, d.Ast.dloc) | Some (n, f) when List.mem n theirs -> Some (n, d.Ast.dloc, f)
| _ -> None) | _ -> None)
decls decls
in in
let warnings = let warnings =
List.map List.map
(fun (n, at) -> (fun (n, at, f) ->
Loc.diag ~kind:"check/shadows-prelude" at Loc.diag ~kind:"check/shadows-prelude" at
(Printf.sprintf (Printf.sprintf
"%s shadows the prelude's %s — every call in this file now \ "%s shadows the prelude's %s — every %s in this file now \
reaches your definition" reaches your definition"
n n)) n n (if f then "call" else "use")))
taken taken
in in
let taken = List.map (fun (n, at, _) -> (n, at)) taken in
let prelude, decls = let prelude, decls =
List.fold_left List.fold_left
(fun (prelude, decls) (n, (at : Loc.t)) -> (fun (prelude, decls) (n, (at : Loc.t)) ->

View File

@ -0,0 +1,14 @@
;;;; A program's global named as a prelude function takes the name over for
;;;; its own file, as a program's function does, and the prelude's own calls
;;;; keep the prelude's: sort still swaps with the prelude's swap.
(defonce swap i32 3)
(defonce clamp i32 4)
(defconst reverse i32 5)
(defn main [] i32
(println (+ swap clamp reverse)) ; 12
(let [xs [3 1 2]]
(sort (slice xs))
(println (at xs 0)) ; 1
(println (at xs 2))) ; 3
0)

View File

@ -592,6 +592,11 @@ let () =
outputs "a prelude function shadowed" "programs/shadow-prelude.flan" sp_out; outputs "a prelude function shadowed" "programs/shadow-prelude.flan" sp_out;
outputs ~x86:true "a prelude function shadowed, x86" outputs ~x86:true "a prelude function shadowed, x86"
"programs/shadow-prelude.flan" sp_out; "programs/shadow-prelude.flan" sp_out;
(* And by a program's global, the same way. *)
outputs "a prelude function shadowed by a global"
"programs/shadow-prelude-global.flan" "12\n1\n3\n";
outputs ~x86:true "a prelude function shadowed by a global, x86"
"programs/shadow-prelude-global.flan" "12\n1\n3\n";
(* (max-value T) and (min-value T), concrete and inside a generic. *) (* (max-value T) and (min-value T), concrete and inside a generic. *)
let maxof_out = let maxof_out =
"255\n0\n127\n-128\n2147483647\n-9223372036854775808\n\ "255\n0\n127\n-128\n2147483647\n-9223372036854775808\n\

View File

@ -5953,6 +5953,20 @@ let () =
| _ -> check "a defn of a prelude function's name warns exactly once" false); | _ -> check "a defn of a prelude function's name warns exactly once" false);
accepts "a defn of a prelude function's name is not defined twice" accepts "a defn of a prelude function's name is not defined twice"
prelude_src; prelude_src;
(* A global takes the name over the same way, with the same warning. *)
(match
snd (Check.shadow_prelude (Parse.program (Prelude.forms ()))
(program "(defonce swap i32 3)"))
with
| [ d ] ->
check "a global of a prelude function's name warns once"
(d.Loc.kind = "check/shadows-prelude"
&& d.Loc.dmsg
= "swap shadows the prelude's swap — every use in this file now \
reaches your definition")
| _ -> check "a global of a prelude function's name warns exactly once" false);
accepts "a global of a prelude function's name is not defined twice"
"(defonce swap i32 3)\n(defn f [] i32 swap)";
rejects_check "a struct of a prelude type's name is still defined twice" rejects_check "a struct of a prelude type's name is still defined twice"
"(defstruct Form [x i32])" ~needle:"Form is defined twice"; "(defstruct Form [x i32])" ~needle:"Form is defined twice";
(* An operator is a builtin like any other and shadows like any other. (* An operator is a builtin like any other and shadows like any other.