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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
(* Type-checking of the module language *)
open Misc
open Path
open Parsetree
open Typedtree
type error =
Unbound_module of Longident.t
| Unbound_modtype of Longident.t
| Cannot_apply of module_type
| Not_included of Includemod.error list
| Cannot_eliminate_dependency of module_type
| Signature_expected
| Structure_expected of module_type
| With_not_abstract of string
| With_arity_mismatch of string
exception Error of Location.t * error
(* Merge a set of type definitions in a signature *)
let merge_constraints loc env sg decls =
let sub = ref Subst.identity in
let rec merge_one_constraint id decl = function
[] ->
[Tsig_type(id, decl)]
| (Tsig_type(id', decl') as item) :: rem ->
if Ident.equal id id' then begin
if decl'.type_kind <> Type_abstract then
raise(Error(loc, With_not_abstract(Ident.name id)));
if decl'.type_arity <> decl.type_arity then
raise(Error(loc, With_arity_mismatch(Ident.name id)));
sub := Subst.add_type id (Pident id') !sub;
Tsig_type(id', decl) :: rem
end else
item :: merge_one_constraint id decl rem
| item :: rem ->
item :: merge_one_constraint id decl rem in
let rec merge_all_constraints sg = function
[] ->
sg
| (id, decl) :: rem ->
merge_all_constraints (merge_one_constraint id decl sg) rem in
let newsig = merge_all_constraints sg decls in
Subst.signature !sub newsig
(* Lookup and strengthen the type of a module path *)
let type_module_path env loc lid =
try
Env.lookup_module lid env
with Not_found ->
raise(Error(loc, Unbound_module lid))
(* Extract a signature from a module type *)
let extract_sig env loc mty =
match Mtype.scrape env mty with
Tmty_signature sg -> sg
| _ -> raise(Error(loc, Signature_expected))
let extract_sig_open env loc mty =
match Mtype.scrape env mty with
Tmty_signature sg -> sg
| _ -> raise(Error(loc, Structure_expected mty))
(* Check and translate a module type expression *)
let rec transl_modtype env smty =
match smty.pmty_desc with
Pmty_ident lid ->
begin try
let (path, info) = Env.lookup_modtype lid env in
Tmty_ident path
with Not_found ->
raise(Error(smty.pmty_loc, Unbound_modtype lid))
end
| Pmty_signature sg ->
Tmty_signature (transl_signature env sg)
| Pmty_functor(param, sarg, sres) ->
let arg = transl_modtype env sarg in
let (id, newenv) = Env.enter_module param arg env in
let res = transl_modtype newenv sres in
Tmty_functor(id, arg, res)
| Pmty_with(sbody, sdecls) ->
let body = transl_modtype env sbody in
let sg = extract_sig env sbody.pmty_loc body in
let (decls, newenv) =
Typedecl.transl_type_decl env sdecls in
Tmty_signature(merge_constraints smty.pmty_loc env sg decls)
and transl_signature env sg =
match sg with
[] -> []
| Psig_value(name, sdesc) :: srem ->
let ty = Typetexp.transl_type_scheme env sdesc.pval_type in
let prim =
match sdesc.pval_prim with
None -> Not_prim
| Some p -> Primitive(p, Ctype.arity ty) in
let desc = { val_type = ty; val_prim = prim } in
let (id, newenv) = Env.enter_value name desc env in
let rem = transl_signature newenv srem in
Tsig_value(id, desc) :: rem
| Psig_type sdecls :: srem ->
let (decls, newenv) = Typedecl.transl_type_decl env sdecls in
let rem = transl_signature newenv srem in
map_end (fun (id, info) -> Tsig_type(id, info)) decls rem
| Psig_exception(name, sarg) :: srem ->
let arg = Typedecl.transl_exception env sarg in
let (id, newenv) = Env.enter_exception name arg env in
let rem = transl_signature newenv srem in
Tsig_exception(id, arg) :: rem
| Psig_module(name, smty) :: srem ->
let mty = transl_modtype env smty in
let (id, newenv) = Env.enter_module name mty env in
let rem = transl_signature newenv srem in
Tsig_module(id, mty) :: rem
| Psig_modtype(name, sinfo) :: srem ->
let info = transl_modtype_info env sinfo in
let (id, newenv) = Env.enter_modtype name info env in
let rem = transl_signature newenv srem in
Tsig_modtype(id, info) :: rem
| Psig_open(lid, loc) :: srem ->
let (path, mty) = type_module_path env loc lid in
let sg = extract_sig_open env loc mty in
let newenv = Env.open_signature path sg env in
transl_signature newenv srem
| Psig_include smty :: srem ->
let mty = transl_modtype env smty in
let sg = extract_sig env smty.pmty_loc mty in
let newenv = Env.add_signature sg env in
let rem = transl_signature newenv srem in
sg @ rem
and transl_modtype_info env sinfo =
match sinfo with
Pmodtype_abstract ->
Tmodtype_abstract
| Pmodtype_manifest smty ->
Tmodtype_manifest(transl_modtype env smty)
(* Type a module val expression *)
let rec type_module env smod =
match smod.pmod_desc with
Pmod_ident lid ->
let (path, mty) = type_module_path env smod.pmod_loc lid in
{ mod_desc = Tmod_ident path;
mod_type = Mtype.strengthen env mty path;
mod_loc = smod.pmod_loc }
| Pmod_structure sstr ->
let (str, sg, _) = type_structure env sstr in
{ mod_desc = Tmod_structure str;
mod_type = Tmty_signature sg;
mod_loc = smod.pmod_loc }
| Pmod_functor(name, smty, sbody) ->
let mty = transl_modtype env smty in
let (id, newenv) = Env.enter_module name mty env in
let body = type_module newenv sbody in
{ mod_desc = Tmod_functor(id, mty, body);
mod_type = Tmty_functor(id, mty, body.mod_type);
mod_loc = smod.pmod_loc }
| Pmod_apply(sfunct, sarg) ->
let funct = type_module env sfunct in
let arg = type_module env sarg in
begin match Mtype.scrape env funct.mod_type with
Tmty_functor(param, mty_param, mty_res) as mty_functor ->
let coercion =
try
Includemod.modtypes env arg.mod_type mty_param
with Includemod.Error msg ->
raise(Error(sarg.pmod_loc, Not_included msg)) in
let mty_appl =
match arg with
{mod_desc = Tmod_ident path} ->
Subst.modtype (Subst.add_module param path Subst.identity)
mty_res
| _ ->
try
Mtype.nondep_supertype
(Env.add_module param arg.mod_type env) param mty_res
with Not_found ->
raise(Error(smod.pmod_loc,
Cannot_eliminate_dependency mty_functor)) in
{ mod_desc = Tmod_apply(funct, arg, coercion);
mod_type = mty_appl;
mod_loc = smod.pmod_loc }
| _ ->
raise(Error(sfunct.pmod_loc, Cannot_apply funct.mod_type))
end
| Pmod_constraint(sarg, smty) ->
let arg = type_module env sarg in
let mty = transl_modtype env smty in
let coercion =
try
Includemod.modtypes env arg.mod_type mty
with Includemod.Error msg ->
raise(Error(sarg.pmod_loc, Not_included msg)) in
{ mod_desc = Tmod_constraint(arg, mty, coercion);
mod_type = mty;
mod_loc = smod.pmod_loc }
and type_structure env = function
[] ->
([], [], env)
| Pstr_eval sexpr :: srem ->
let expr = Typecore.type_expression env sexpr in
let (str_rem, sig_rem, final_env) = type_structure env srem in
(Tstr_eval expr :: str_rem, sig_rem, final_env)
| Pstr_value(rec_flag, sdefs) :: srem ->
let (defs, newenv) =
Typecore.type_binding env rec_flag sdefs in
let (str_rem, sig_rem, final_env) = type_structure newenv srem in
let bound_idents = List.rev(let_bound_idents defs) in
let make_sig_value id =
Tsig_value(id, Env.find_value (Pident id) newenv) in
(Tstr_value(rec_flag, defs) :: str_rem,
map_end make_sig_value bound_idents sig_rem,
final_env)
| Pstr_primitive(name, sdesc) :: srem ->
let ty = Typetexp.transl_type_scheme env sdesc.pval_type in
let prim =
match sdesc.pval_prim with
None -> Not_prim
| Some p -> Primitive(p, Ctype.arity ty) in
let desc = { val_type = ty; val_prim = prim } in
let (id, newenv) = Env.enter_value name desc env in
let (str_rem, sig_rem, final_env) = type_structure newenv srem in
(Tstr_primitive(id, desc) :: str_rem,
Tsig_value(id, desc) :: sig_rem,
final_env)
| Pstr_type sdecls :: srem ->
let (decls, newenv) = Typedecl.transl_type_decl env sdecls in
let (str_rem, sig_rem, final_env) = type_structure newenv srem in
(Tstr_type decls :: str_rem,
map_end (fun (id, info) -> Tsig_type(id, info)) decls sig_rem,
final_env)
| Pstr_exception(name, sarg) :: srem ->
let arg = Typedecl.transl_exception env sarg in
let (id, newenv) = Env.enter_exception name arg env in
let (str_rem, sig_rem, final_env) = type_structure newenv srem in
(Tstr_exception(id, arg) :: str_rem,
Tsig_exception(id, arg) :: sig_rem,
final_env)
| Pstr_module(name, smodl) :: srem ->
let modl = type_module env smodl in
let (id, newenv) = Env.enter_module name modl.mod_type env in
let (str_rem, sig_rem, final_env) = type_structure newenv srem in
(Tstr_module(id, modl) :: str_rem,
Tsig_module(id, modl.mod_type) :: sig_rem,
final_env)
| Pstr_modtype(name, smty) :: srem ->
let mty = transl_modtype env smty in
let (id, newenv) = Env.enter_modtype name (Tmodtype_manifest mty) env in
let (str_rem, sig_rem, final_env) = type_structure newenv srem in
(Tstr_modtype(id, mty) :: str_rem,
Tsig_modtype(id, Tmodtype_manifest mty) :: sig_rem,
final_env)
| Pstr_open(lid, loc) :: srem ->
let (path, mty) = type_module_path env loc lid in
let sg = extract_sig_open env loc mty in
type_structure (Env.open_signature path sg env) srem
(* Error report *)
open Format
open Printtyp
let report_error = function
Unbound_module lid ->
print_string "Unbound module "; longident lid
| Unbound_modtype lid ->
print_string "Unbound module type "; longident lid
| Cannot_apply mty ->
open_hovbox 0;
print_string "This module is not a functor; it has type";
print_space(); modtype mty;
close_box()
| Not_included errs ->
open_vbox 0;
print_string "Signature mismatch:"; print_space();
Includemod.report_error errs;
close_box()
| Cannot_eliminate_dependency mty ->
open_hovbox 0;
print_string "This functor has type";
print_space(); modtype mty; print_space();
print_string "The parameter cannot be eliminated in the result type.";
print_space();
print_string "Please bind the argument to a module identifier.";
close_box()
| Signature_expected ->
print_string "This module type is not a signature"
| Structure_expected mty ->
open_hovbox 0;
print_string "This module is not a structure; it has type";
print_space(); modtype mty;
close_box()
| With_not_abstract s ->
print_string "The type "; print_string s; print_string " is not abstract"
| With_arity_mismatch s ->
print_string "Arity mismatch in `with' constraint over type ";
print_string s
|