Skip to content

Commit 1babc35

Browse files
cknittclaude
andcommitted
Keep numbered existential names distinct from other existential names
Why: A numbered name can equal the base name of another existential, as $a1 for the second 'a and for 'a1, and the printer then falls back to internal name/stamp names. Names already given in the binding are now skipped. Diagnostic modified (comparing existentials): Example: type rec a2 = A2('a): a2 type rec a1 = A1('a1): a1 type rec a3 = A3('a): a3 let f = (A2(y), A1(x), A3(z)) => z == x Before (text): This has type: \"$a1/1011" But it's being compared to something of type: \"$a1/1013" After (text): This has type: $a1 But it's being compared to something of type: $a2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kbf3gGhHjzBTXqSo8Dckpb Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent ac73578 commit 1babc35

5 files changed

Lines changed: 52 additions & 8 deletions

File tree

‎compiler/ml/ctype.ml‎

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -901,20 +901,33 @@ let instance_list env schl =
901901
let env = gadt_env env in
902902
List.map (fun t -> copy ?env t) schl)
903903

904-
let reified_var_counter_key = Request_local.new_key (fun () -> ref Vars.empty)
904+
(* The next index for each base name, and the names already given *)
905+
let reified_var_counter_key =
906+
Request_local.new_key (fun () -> ref (Vars.empty, Misc.String_set.empty))
905907
let reified_var_counter () = Domain.DLS.get reified_var_counter_key
906-
let reset_reified_var_counter () = reified_var_counter () := Vars.empty
908+
let reset_reified_var_counter () =
909+
reified_var_counter () := (Vars.empty, Misc.String_set.empty)
907910

908911
(* names given to new type constructors.
909912
Used for existential types and
910-
local constraints *)
913+
local constraints. A numbered name can equal a base name ending in
914+
digits, as [$a1] for the second ['a] and the first ['a1], so names
915+
already given are skipped. *)
911916
let get_new_abstract_name s =
912-
let index =
913-
try Vars.find s !(reified_var_counter ()) + 1 with Not_found -> 0
917+
let counters, used = !(reified_var_counter ()) in
918+
let name index =
919+
if index = 0 && s <> "" && s.[String.length s - 1] <> '$' then s
920+
else Printf.sprintf "%s%d" s index
914921
in
915-
reified_var_counter () := Vars.add s index !(reified_var_counter ());
916-
if index = 0 && s <> "" && s.[String.length s - 1] <> '$' then s
917-
else Printf.sprintf "%s%d" s index
922+
let rec first_free index =
923+
if Misc.String_set.mem (name index) used then first_free (index + 1)
924+
else index
925+
in
926+
let index = first_free (try Vars.find s counters + 1 with Not_found -> 0) in
927+
let name = name index in
928+
reified_var_counter () :=
929+
(Vars.add s index counters, Misc.String_set.add name used);
930+
name
918931

919932
let new_declaration newtype manifest =
920933
{
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/gadt_existential_numbered_constructor.res:2:43
4+
5+
1 │ type rec t = Any(_): t | Any1(_): t
6+
2 │ let f = (Any(x), Any(y), Any1(z)) => z == y
7+
3 │
8+
9+
This has type: $Any1
10+
But it's being compared to something of type: $Any11
11+
12+
You can only compare things of the same type.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/gadt_existential_numbered_name.res:4:39
4+
5+
2 │ type rec a1 = A1('a1): a1
6+
3 │ type rec a3 = A3('a): a3
7+
4 │ let f = (A2(y), A1(x), A3(z)) => z == x
8+
5 │
9+
10+
This has type: $a1
11+
But it's being compared to something of type: $a2
12+
13+
You can only compare things of the same type.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
type rec t = Any(_): t | Any1(_): t
2+
let f = (Any(x), Any(y), Any1(z)) => z == y
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type rec a2 = A2('a): a2
2+
type rec a1 = A1('a1): a1
3+
type rec a3 = A3('a): a3
4+
let f = (A2(y), A1(x), A3(z)) => z == x

0 commit comments

Comments
 (0)