Skip to content

Commit 8ecb9f6

Browse files
committed
support type with parameter for record rest
1 parent 0ec00ae commit 8ecb9f6

8 files changed

Lines changed: 90 additions & 14 deletions

File tree

compiler/ml/typecore.ml

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,11 +1558,11 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp
15581558
| None -> None
15591559
| Some rest_pat ->
15601560
(* Extract type annotation and binding name from rest pattern *)
1561-
let rest_type_lid, rest_name =
1561+
let rest_type_lid, rest_name, rest_type_args_syntax =
15621562
match rest_pat.ppat_desc with
15631563
| Ppat_constraint ({ppat_desc = Ppat_var name}, cty) -> (
15641564
match cty.ptyp_desc with
1565-
| Ptyp_constr (lid, []) -> (lid, name)
1565+
| Ptyp_constr (lid, type_args) -> (lid, name, type_args)
15661566
| _ ->
15671567
raise
15681568
(Error (rest_pat.ppat_loc, !env, Record_rest_invalid_type)))
@@ -1661,12 +1661,30 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp
16611661
(Ident.name rest_label.ld_id, rest_type_lid.txt) )))
16621662
rest_labels
16631663
| [] -> ());
1664+
let rest_type_args =
1665+
match rest_type_args_syntax with
1666+
| [] -> List.map (fun _ -> newvar ()) rest_decl.type_params
1667+
| args ->
1668+
let n_args = List.length args in
1669+
let n_params = List.length rest_decl.type_params in
1670+
if n_args <> n_params then
1671+
raise
1672+
(Typetexp.Error
1673+
( rest_type_lid.loc,
1674+
!env,
1675+
Typetexp.Type_arity_mismatch
1676+
(rest_type_lid.txt, n_params, n_args) ));
1677+
List.map
1678+
(fun sty ->
1679+
let cty, force =
1680+
Typetexp.transl_simple_type_delayed !env sty
1681+
in
1682+
pattern_force := force :: !pattern_force;
1683+
cty.ctyp_type)
1684+
args
1685+
in
16641686
let rest_type_expr =
1665-
newgenty
1666-
(Tconstr
1667-
( rest_path,
1668-
List.map (fun _ -> newvar ()) rest_decl.type_params,
1669-
ref Mnil ))
1687+
newgenty (Tconstr (rest_path, rest_type_args, ref Mnil))
16701688
in
16711689
let rest_ident =
16721690
enter_variable rest_pat.ppat_loc rest_name rest_type_expr

compiler/syntax/src/res_core.ml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,11 @@ and parse_record_pattern_row p =
14581458
let start_pos = p.Parser.start_pos in
14591459
match p.Parser.token with
14601460
| Uident _ ->
1461-
(* ...ModulePath.t as name *)
1461+
(* ...ModulePath.t<'a> as name *)
14621462
let type_path = parse_value_path p in
14631463
let type_loc = type_path.loc in
1464-
let core_type = Ast_helper.Typ.constr ~loc:type_loc type_path [] in
1464+
let type_args = parse_type_constructor_args ~constr_name:type_path p in
1465+
let core_type = Ast_helper.Typ.constr ~loc:type_loc type_path type_args in
14651466
Parser.expect As p;
14661467
let name_start = p.start_pos in
14671468
let name =
@@ -1482,14 +1483,17 @@ and parse_record_pattern_row p =
14821483
Some (false, PatRest rest_pat)
14831484
| Lident ident ->
14841485
Parser.next p;
1485-
if p.Parser.token = As then (
1486-
(* ...typeName as name *)
1486+
if p.Parser.token = As || p.Parser.token = Token.LessThan then (
1487+
(* ...typeName<'a> as name *)
14871488
let type_path =
14881489
Location.mkloc (Longident.Lident ident)
14891490
(mk_loc start_pos p.prev_end_pos)
14901491
in
14911492
let type_loc = type_path.loc in
1492-
let core_type = Ast_helper.Typ.constr ~loc:type_loc type_path [] in
1493+
let type_args = parse_type_constructor_args ~constr_name:type_path p in
1494+
let core_type =
1495+
Ast_helper.Typ.constr ~loc:type_loc type_path type_args
1496+
in
14931497
Parser.expect As p;
14941498
let name_start = p.start_pos in
14951499
let name =

tests/syntax_tests/data/parsing/grammar/pattern/expected/record.res.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,8 @@ let { a; b } = x
8888
;;match x with | { a } -> () | { a } -> () | { a } -> ()
8989
let f [arity:1]{ a } = ()
9090
let f [arity:1]{ a } = ()
91-
let f [arity:1]{ a } = ()
91+
let f [arity:1]{ a } = ()
92+
let { a } = x
93+
let { a } = x
94+
let { a } = x
95+
let { a } = x

tests/syntax_tests/data/parsing/grammar/pattern/record.res

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,9 @@ switch x {
104104
let f = ({a, ...rest}) => ()
105105
let f = ({a, ...b as rest}) => ()
106106
let f = ({a, ...M.t as rest}) => ()
107+
108+
// Polymorphic rest type args
109+
let {a, ...t<'v> as rest} = x
110+
let {a, ...M.t<'v> as rest} = x
111+
let {a, ...M.t<int> as rest} = x
112+
let {a, ...M.t<'a, 'b> as rest} = x

tests/syntax_tests/data/printer/pattern/expected/record.res.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,10 @@ let get_age3 = () =>
125125
switch x {
126126
| {_} => ""
127127
}
128+
129+
// Record rest with polymorphic type args
130+
let {a, ...rest} = x
131+
let {a, ...t<'v> as rest} = x
132+
let {a, ...M.t<'v> as rest} = x
133+
let {a, ...M.t<int> as rest} = x
134+
let {a, ...M.t<'a, 'b> as rest} = x

tests/syntax_tests/data/printer/pattern/record.res

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,14 @@ let get_age3 = () =>
6565
switch x {
6666
| {age, _} => age
6767
}
68-
let get_age3 = () =>
68+
let get_age3 = () =>
6969
switch x {
7070
| {_} => ""
7171
}
72+
73+
// Record rest with polymorphic type args
74+
let {a, ...rest} = x
75+
let {a, ...t<'v> as rest} = x
76+
let {a, ...M.t<'v> as rest} = x
77+
let {a, ...M.t<int> as rest} = x
78+
let {a, ...M.t<'a, 'b> as rest} = x

tests/tests/src/record_rest_test.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,27 @@ function extractClassName(param) {
2323
return ((({className, ...__rest}) => __rest))(param);
2424
}
2525

26+
let intRest = ((({id, ...__rest}) => __rest))({
27+
id: "1",
28+
value: 42
29+
});
30+
31+
function getValue(param) {
32+
return ((({id, ...__rest}) => __rest))(param);
33+
}
34+
2635
let name = "test";
2736

37+
let id = "1";
38+
2839
export {
2940
rest,
3041
name,
3142
describe,
3243
getName,
3344
extractClassName,
45+
intRest,
46+
id,
47+
getValue,
3448
}
3549
/* No side effect */

tests/tests/src/record_rest_test.res

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,19 @@ let extractClassName = ({?className, ...baseProps as rest}: fullProps) => {
3939
let _ = className
4040
rest
4141
}
42+
43+
// Polymorphic rest type
44+
type container<'a> = {
45+
id: string,
46+
value: 'a,
47+
}
48+
49+
type valueContainer<'a> = {
50+
value: 'a,
51+
}
52+
53+
let {id, ...valueContainer<int> as intRest} = ({id: "1", value: 42}: container<int>)
54+
let _ = (id, intRest)
55+
56+
// Polymorphic rest in function parameter
57+
let getValue = ({id: _, ...valueContainer<'a> as rest}: container<'a>) => rest

0 commit comments

Comments
 (0)