Skip to content

Commit cfdfc1e

Browse files
committedApr 26, 2023
Make untagged variants understand payloads defined as records.
When a payload `A(t)` is a type `t` defined as a record, consider `A` as an object case, not an unknown case. (unless t is an unboxed record)
1 parent a4ae30b commit cfdfc1e

6 files changed

+49
-16
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- `node` (default): Drop extensions.
2020
- `node16`: Use TS output's extensions. Make it ESM-compatible.
2121
- `bundler`: Use TS input's extensions. Make it ESM-compatible.
22+
- Make untagged variants understand payloads defined as records. https://github.com/rescript-lang/rescript-compiler/pull/6208
2223

2324
#### :boom: Breaking Change
2425

‎jscomp/core/matching_polyfill.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
let names_from_construct_pattern (pat : Typedtree.pattern) =
2626
let rec resolve_path n (path : Path.t) =
2727
match Env.find_type path pat.pat_env with
28-
| { type_kind = Type_variant cstrs; _ } -> Ast_untagged_variants.names_from_type_variant cstrs
28+
| { type_kind = Type_variant cstrs; _ } -> Ast_untagged_variants.names_from_type_variant ~env:pat.pat_env cstrs
2929
| { type_kind = Type_abstract; type_manifest = Some t; _ } -> (
3030
match (Ctype.unalias t).desc with
3131
| Tconstr (pathn, _, _) ->

‎jscomp/ml/ast_untagged_variants.ml

+18-14
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ let () =
9292
None
9393
)
9494

95-
let get_untagged (cstr: Types.constructor_declaration) : block_type option =
95+
let get_untagged ~env (cstr: Types.constructor_declaration) : block_type option =
9696
match process_untagged cstr.cd_attributes, cstr.cd_args with
9797
| false, _ -> None
9898
| true, Cstr_tuple [{desc = Tconstr (path, _, _)}] when Path.same path Predef.path_string ->
@@ -105,17 +105,21 @@ let get_untagged (cstr: Types.constructor_declaration) : block_type option =
105105
Some Array
106106
| true, Cstr_tuple [{desc = Tconstr (path, _, _)}] when Path. same path Predef.path_string ->
107107
Some StringType
108-
| true, Cstr_tuple [{desc = Tconstr (path, _, _)}] ->
109-
(match Path.name path with
110-
| "Js.Dict.t"
111-
| "Js_dict.t" -> Some Object
112-
| _ -> Some Unknown)
113-
| true, Cstr_tuple (_ :: _ :: _) ->
108+
| true, Cstr_tuple [{desc = Tconstr (path, _, _)}] when
109+
let name = Path.name path in
110+
name = "Js.Dict.t" || name = "Js_dict.t" ->
111+
Some Object
112+
| true, Cstr_tuple [ty] ->
113+
let default = Some Unknown in
114+
(match Ctype.extract_concrete_typedecl env ty with
115+
| (_, _, {type_kind = Type_record (_, Record_unboxed _)}) -> default
116+
| (_, _, {type_kind = Type_record (_, _)}) -> Some Object
117+
| _ -> default
118+
| exception _ -> default
119+
)
120+
| true, Cstr_tuple (_ :: _ :: _) ->
114121
(* C(_, _) with at least 2 args is an object *)
115122
Some Object
116-
| true, Cstr_tuple [_] ->
117-
(* Every other single payload is unknown *)
118-
Some Unknown
119123
| true, Cstr_record _ ->
120124
(* inline record is an object *)
121125
Some Object
@@ -209,13 +213,13 @@ let checkInvariant ~isUntaggedDef ~(consts : (Location.t * literal) list) ~(bloc
209213
invariant loc
210214
| None -> ())
211215

212-
let names_from_type_variant ?(isUntaggedDef=false) (cstrs : Types.constructor_declaration list) =
216+
let names_from_type_variant ?(isUntaggedDef=false) ~env (cstrs : Types.constructor_declaration list) =
213217
let get_cstr_name (cstr: Types.constructor_declaration) =
214218
(cstr.cd_loc,
215219
{ name = Ident.name cstr.cd_id;
216220
literal_type = process_literal_type cstr.cd_attributes }) in
217221
let get_block cstr : block =
218-
{literal = snd (get_cstr_name cstr); tag_name = get_tag_name cstr; block_type = get_untagged cstr} in
222+
{literal = snd (get_cstr_name cstr); tag_name = get_tag_name cstr; block_type = get_untagged ~env cstr} in
219223
let consts, blocks =
220224
Ext_list.fold_left cstrs ([], []) (fun (consts, blocks) cstr ->
221225
if is_nullary_variant cstr.cd_args then
@@ -229,6 +233,6 @@ let names_from_type_variant ?(isUntaggedDef=false) (cstrs : Types.constructor_de
229233
let blocks = Ext_array.reverse_of_list blocks in
230234
Some { consts; blocks }
231235

232-
let check_well_formed ~isUntaggedDef (cstrs: Types.constructor_declaration list) =
233-
ignore (names_from_type_variant ~isUntaggedDef cstrs)
236+
let check_well_formed ~env ~isUntaggedDef (cstrs: Types.constructor_declaration list) =
237+
ignore (names_from_type_variant ~env ~isUntaggedDef cstrs)
234238

‎jscomp/ml/typedecl.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ let transl_declaration ~typeRecordAsObject env sdecl id =
422422
in
423423
let tcstrs, cstrs = List.split (List.map make_cstr scstrs) in
424424
let isUntaggedDef = Ast_untagged_variants.has_untagged sdecl.ptype_attributes in
425-
Ast_untagged_variants.check_well_formed ~isUntaggedDef cstrs;
425+
Ast_untagged_variants.check_well_formed ~env ~isUntaggedDef cstrs;
426426
Ttype_variant tcstrs, Type_variant cstrs, sdecl
427427
| Ptype_record lbls_ ->
428428
let has_optional attrs = Ext_list.exists attrs (fun ({txt },_) -> txt = "res.optional") in

‎jscomp/test/UntaggedVariants.js

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎jscomp/test/UntaggedVariants.res

+14
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,17 @@ module OverlapObject = {
235235
| Object(_) => "Object..."
236236
}
237237
}
238+
239+
module RecordIsObject = {
240+
// @unboxed
241+
// this is not allowed
242+
type r = {x:int}
243+
244+
@unboxed
245+
type t = | Array(array<int>) | Record(r)
246+
247+
let classify = v => switch v {
248+
| Record({x}) => x
249+
| Array(a) => a[0]
250+
}
251+
}

0 commit comments

Comments
 (0)
Please sign in to comment.