forked from rescript-lang/rescript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathast_typ_uncurry.ml
139 lines (127 loc) · 5.25 KB
/
ast_typ_uncurry.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
(* Copyright (C) 2020 Hongbo Zhang, Authors of ReScript
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition to the permissions granted to you by the LGPL, you may combine
* or link a "work that uses the Library" with a publicly distributed version
* of this file to produce a combined library or application, then distribute
* that combined work under the terms of your choosing, with no requirement
* to comply with the obligations normally placed on you by section 4 of the
* LGPL version 3 (or the corresponding section of a later version of the LGPL
* should you choose to use a later version).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
type typ = Parsetree.core_type
type 'a cxt = Ast_helper.loc -> Bs_ast_mapper.mapper -> 'a
type uncurry_type_gen = (Asttypes.arg_label -> typ -> typ -> typ) cxt
module Typ = Ast_helper.Typ
let to_method_callback_type loc (mapper : Bs_ast_mapper.mapper)
(label : Asttypes.arg_label) (first_arg : Parsetree.core_type)
(typ : Parsetree.core_type) =
let first_arg = mapper.typ mapper first_arg in
let typ = mapper.typ mapper typ in
let meth_type = Typ.arrow ~loc label first_arg typ in
let arity = Ast_core_type.get_uncurry_arity meth_type in
match arity with
| Some n ->
Typ.constr
{
txt =
Ldot (Ast_literal.Lid.js_meth_callback, "arity" ^ string_of_int n);
loc;
}
[ meth_type ]
| None -> assert false
let self_type_lit = "self_type"
let generate_method_type loc (mapper : Bs_ast_mapper.mapper) ?alias_type
method_name lbl pat e : Parsetree.core_type =
let arity = Ast_pat.arity_of_fun pat e in
let result = Typ.var ~loc method_name in
let self_type loc = Typ.var ~loc self_type_lit in
let self_type =
let v = self_type loc in
match alias_type with
| None -> v
| Some ty -> Typ.alias ~loc ty self_type_lit
in
if arity = 0 then to_method_callback_type loc mapper Nolabel self_type result
else
let tyvars =
Ext_list.mapi (lbl :: Ast_pat.labels_of_fun e) (fun i x ->
(x, Typ.var ~loc (method_name ^ string_of_int i)))
(* Ext_list.init arity (fun i -> Typ.var ~loc (method_name ^ string_of_int i)) *)
in
match tyvars with
| (label, x) :: rest ->
let method_rest =
Ext_list.fold_right rest result (fun (label, v) acc ->
Typ.arrow ~loc label v acc)
in
to_method_callback_type loc mapper Nolabel self_type
(Typ.arrow ~loc label x method_rest)
| _ -> assert false
let to_method_type loc (mapper : Bs_ast_mapper.mapper)
(label : Asttypes.arg_label) (first_arg : Parsetree.core_type)
(typ : Parsetree.core_type) =
let first_arg = mapper.typ mapper first_arg in
let typ = mapper.typ mapper typ in
let meth_type = Typ.arrow ~loc label first_arg typ in
let arity = Ast_core_type.get_uncurry_arity meth_type in
match arity with
| Some 0 ->
Typ.constr { txt = Ldot (Ast_literal.Lid.js_meth, "arity0"); loc } [ typ ]
| Some n ->
Typ.constr
{ txt = Ldot (Ast_literal.Lid.js_meth, "arity" ^ string_of_int n); loc }
[ meth_type ]
| None -> assert false
let generate_arg_type loc (mapper : Bs_ast_mapper.mapper) method_name label pat
body : Ast_core_type.t =
let arity = Ast_pat.arity_of_fun pat body in
let result = Typ.var ~loc method_name in
if arity = 0 then
to_method_type loc mapper Nolabel (Ast_literal.type_unit ~loc ()) result
else
let tyvars =
Ext_list.mapi (label :: Ast_pat.labels_of_fun body) (fun i x ->
(x, Typ.var ~loc (method_name ^ string_of_int i)))
in
match tyvars with
| (label, x) :: rest ->
let method_rest =
Ext_list.fold_right rest result (fun (label, v) acc ->
Typ.arrow ~loc label v acc)
in
to_method_type loc mapper label x method_rest
| _ -> assert false
let to_uncurry_type loc (mapper : Bs_ast_mapper.mapper)
(label : Asttypes.arg_label) (first_arg : Parsetree.core_type)
(typ : Parsetree.core_type) =
(* no need to error for optional here,
since we can not make it
TODO: still error out for external?
Maybe no need to error on optional at all
it just does not make sense
*)
let first_arg = mapper.typ mapper first_arg in
let typ = mapper.typ mapper typ in
let fn_type = Typ.arrow ~loc label first_arg typ in
let arity = Ast_core_type.get_uncurry_arity fn_type in
match arity with
| Some 0 ->
Typ.constr { txt = Ldot (Ast_literal.Lid.js_fn, "arity0"); loc } [ typ ]
| Some n ->
Typ.constr
{ txt = Ldot (Ast_literal.Lid.js_fn, "arity" ^ string_of_int n); loc }
[ fn_type ]
| None -> assert false