Skip to content

Commit 33b9130

Browse files
committed
make code path handling the magic record field for dicts just work on the predefined dict
1 parent bd2abd1 commit 33b9130

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed
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/dict_magic_field_on_non_dict.res:5:6-23
4+
5+
3 │ let foo = (fakeDict: fakeDict<'a>) => {
6+
4 │ switch fakeDict {
7+
5 │ | {someUndefinedField: 1} => Js.log("one")
8+
6 │ | _ => Js.log("not one")
9+
7 │ }
10+
11+
The field someUndefinedField does not belong to type fakeDict
12+
13+
This record pattern is expected to have type fakeDict<'a>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
type fakeDict<'t> = {anyOtherField?: 't}
2+
3+
let foo = (fakeDict: fakeDict<'a>) => {
4+
switch fakeDict {
5+
| {someUndefinedField: 1} => Js.log("one")
6+
| _ => Js.log("not one")
7+
}
8+
}

jscomp/ml/predef.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ let common_initial_env add_type add_extension empty_env =
227227
type_variance = [Variance.full];
228228
type_kind = Type_record ([{
229229
ld_id = ident_anyOtherField;
230-
ld_attributes = [(Location.mknoloc "res.optional", Parsetree.PStr [])];
230+
ld_attributes = [(Location.mknoloc "res.optional", Parsetree.PStr []); (Location.mknoloc "res.dictMagicField", Parsetree.PStr [])];
231231
ld_loc = Location.none;
232232
ld_mutable = Immutable; (* TODO(dict-pattern-matching) Should probably be mutable? *)
233233
ld_type = newgenty (Tconstr (path_option, [tvar], ref Mnil));

jscomp/ml/typecore.ml

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -804,18 +804,31 @@ end) = struct
804804
let lookup_from_type env tpath (lid : Longident.t loc) : Name.t =
805805
let descrs = get_descrs (Env.find_type_descrs tpath env) in
806806
Env.mark_type_used env (Path.last tpath) (Env.find_type tpath env);
807-
match lid.txt with
808-
Longident.Lident s_ -> begin
809-
let s =
810-
if List.exists (fun nd -> get_name nd = s_) descrs
811-
|| not (List.exists (fun nd -> get_name nd = "anyOtherField") descrs)
812-
then s_
813-
else "anyOtherField" in
807+
(* TODO(dict-pattern-matching): also lookup the actual definition and check for @res.dict? *)
808+
let is_dict = Path.same tpath Predef.path_dict in
809+
if is_dict then (
810+
match lid.txt with
811+
Longident.Lident s_ -> begin
812+
let s =
813+
if List.exists (fun nd -> get_name nd = s_) descrs
814+
|| not (List.exists (fun nd -> get_name nd = "anyOtherField") descrs)
815+
then s_
816+
else "anyOtherField" in
817+
try
818+
let x = List.find (fun nd -> get_name nd = s) descrs in
819+
if s = "anyOtherField"
820+
then add_with_name x s_
821+
else x
822+
with Not_found ->
823+
let names = List.map get_name descrs in
824+
raise (Error (lid.loc, env,
825+
Wrong_name ("", newvar (), type_kind, tpath, s, names)))
826+
end
827+
| _ -> raise Not_found)
828+
else match lid.txt with
829+
Longident.Lident s -> begin
814830
try
815-
let x = List.find (fun nd -> get_name nd = s) descrs in
816-
if s = "anyOtherField"
817-
then add_with_name x s_
818-
else x
831+
List.find (fun nd -> get_name nd = s) descrs
819832
with Not_found ->
820833
let names = List.map get_name descrs in
821834
raise (Error (lid.loc, env,

0 commit comments

Comments
 (0)