/[svn]/typing/typer.ml
ViewVC logotype

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 329 - (show annotations)
Tue Jul 10 17:25:34 2007 UTC (5 years, 10 months ago) by abate
File size: 33780 byte(s)
[r2003-05-11 09:30:40 by cvscast] atom_of

Original author: cvscast
Date: 2003-05-11 09:30:41+00:00
1 (* TODO:
2 - rewrite type-checking of operators to propagate constraint
3 - optimize computation of pattern free variables
4 - check whether it is worth using recursive hash-consing internally
5 *)
6
7
8 let warning loc msg =
9 Format.fprintf !Location.warning_ppf "Warning %a:@\n%a%s@\n"
10 Location.print_loc loc
11 Location.html_hilight loc
12 msg
13
14 (* I. Transform the abstract syntax of types and patterns into
15 the internal form *)
16
17 open Location
18 open Ast
19 open Ident
20
21 module S = struct type t = string let compare = compare end
22 module StringSet = Set.Make(S)
23 module TypeEnv = Map.Make(S)
24 module Env = Map.Make(Id)
25
26
27 exception NonExhaustive of Types.descr
28 exception Constraint of Types.descr * Types.descr * string
29 exception ShouldHave of Types.descr * string
30 exception WrongLabel of Types.descr * label
31 exception UnboundId of string
32
33 let raise_loc loc exn = raise (Location (loc,exn))
34
35
36 (* Eliminate Recursion, propagate Sequence Capture Variables *)
37
38 let rec seq_vars accu = function
39 | Epsilon | Elem _ -> accu
40 | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
41 | Star r | WeakStar r -> seq_vars accu r
42 | SeqCapture (v,r) -> seq_vars (IdSet.add v accu) r
43
44 type derecurs_slot = {
45 ploc : Location.loc;
46 pid : int;
47 mutable ploop : bool;
48 mutable pdescr : derecurs option
49 } and derecurs =
50 | PAlias of derecurs_slot
51 | PType of Types.descr
52 | POr of derecurs * derecurs
53 | PAnd of derecurs * derecurs
54 | PDiff of derecurs * derecurs
55 | PTimes of derecurs * derecurs
56 | PXml of derecurs * derecurs
57 | PArrow of derecurs * derecurs
58 | POptional of derecurs
59 | PRecord of bool * derecurs label_map
60 | PCapture of id
61 | PConstant of id * Types.const
62 | PRegexp of derecurs_regexp * derecurs
63 and derecurs_regexp =
64 | PEpsilon
65 | PElem of derecurs
66 | PSeq of derecurs_regexp * derecurs_regexp
67 | PAlt of derecurs_regexp * derecurs_regexp
68 | PStar of derecurs_regexp
69 | PWeakStar of derecurs_regexp
70
71 let rec hash_derecurs = function
72 | PAlias s -> s.pid
73 | PType t -> 1 + 17 * (Types.hash_descr t)
74 | POr (p1,p2) -> 2 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
75 | PAnd (p1,p2) -> 3 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
76 | PDiff (p1,p2) -> 4 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
77 | PTimes (p1,p2) -> 5 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
78 | PXml (p1,p2) -> 6 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
79 | PArrow (p1,p2) -> 7 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
80 | POptional p -> 8 + 17 * (hash_derecurs p)
81 | PRecord (o,r) -> (if o then 9 else 10) + 17 * (LabelMap.hash hash_derecurs r)
82 | PCapture x -> 11 + 17 * (Id.hash x)
83 | PConstant (x,c) -> 12 + 17 * (Id.hash x) + 257 * (Types.hash_const c)
84 | PRegexp (p,q) -> 13 + 17 * (hash_derecurs_regexp p) + 257 * (hash_derecurs q)
85 and hash_derecurs_regexp = function
86 | PEpsilon -> 1
87 | PElem p -> 2 + 17 * (hash_derecurs p)
88 | PSeq (p1,p2) -> 3 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2)
89 | PAlt (p1,p2) -> 4 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2)
90 | PStar p -> 5 + 17 * (hash_derecurs_regexp p)
91 | PWeakStar p -> 6 + 17 * (hash_derecurs_regexp p)
92
93 let rec equal_derecurs p1 p2 = (p1 == p2) || match p1,p2 with
94 | PAlias s1, PAlias s2 -> s1 == s2
95 | PType t1, PType t2 -> Types.equal_descr t1 t2
96 | POr (p1,q1), POr (p2,q2)
97 | PAnd (p1,q1), PAnd (p2,q2)
98 | PDiff (p1,q1), PDiff (p2,q2)
99 | PTimes (p1,q1), PTimes (p2,q2)
100 | PXml (p1,q1), PXml (p2,q2)
101 | PArrow (p1,q1), PArrow (p2,q2) -> (equal_derecurs p1 p2) && (equal_derecurs q1 q2)
102 | POptional p1, POptional p2 -> equal_derecurs p1 p2
103 | PRecord (o1,r1), PRecord (o2,r2) -> (o1 == o2) && (LabelMap.equal equal_derecurs r1 r2)
104 | PCapture x1, PCapture x2 -> Id.equal x1 x2
105 | PConstant (x1,c1), PConstant (x2,c2) -> (Id.equal x1 x2) && (Types.equal_const c1 c2)
106 | PRegexp (p1,q1), PRegexp (p2,q2) -> (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2)
107 | _ -> false
108 and equal_derecurs_regexp r1 r2 = match r1,r2 with
109 | PEpsilon, PEpsilon -> true
110 | PElem p1, PElem p2 -> equal_derecurs p1 p2
111 | PSeq (p1,q1), PSeq (p2,q2)
112 | PAlt (p1,q1), PAlt (p2,q2) -> (equal_derecurs_regexp p1 p2) && (equal_derecurs_regexp q1 q2)
113 | PStar p1, PStar p2
114 | PWeakStar p1, PWeakStar p2 -> equal_derecurs_regexp p1 p2
115 | _ -> false
116
117 module DerecursTable = Hashtbl.Make(
118 struct
119 type t = derecurs
120 let hash = hash_derecurs
121 let equal = equal_derecurs
122 end
123 )
124
125 module RE = Hashtbl.Make(
126 struct
127 type t = derecurs_regexp * derecurs
128 let hash (p,q) = (hash_derecurs_regexp p) + 17 * (hash_derecurs q)
129 let equal (p1,q1) (p2,q2) = (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2)
130 end
131 )
132
133
134 let counter = State.ref "Typer.counter - derecurs" 0
135 let mk_slot loc =
136 incr counter;
137 { ploop = false; ploc = loc; pid = !counter; pdescr = None }
138
139 let rec derecurs env p = match p.descr with
140 | PatVar v ->
141 (try PAlias (TypeEnv.find v env)
142 with Not_found -> raise_loc_generic p.loc ("Undefined type/pattern " ^ v))
143 | Recurs (p,b) -> derecurs (derecurs_def env b) p
144 | Internal t -> PType t
145 | Or (p1,p2) -> POr (derecurs env p1, derecurs env p2)
146 | And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2)
147 | Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2)
148 | Prod (p1,p2) -> PTimes (derecurs env p1, derecurs env p2)
149 | XmlT (p1,p2) -> PXml (derecurs env p1, derecurs env p2)
150 | Arrow (p1,p2) -> PArrow (derecurs env p1, derecurs env p2)
151 | Optional p -> POptional (derecurs env p)
152 | Record (o,r) -> PRecord (o, LabelMap.map (derecurs env) r)
153 | Capture x -> PCapture x
154 | Constant (x,c) -> PConstant (x,c)
155 | Regexp (r,q) ->
156 let constant_nil t v = PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in
157 let vars = seq_vars IdSet.empty r in
158 let q = IdSet.fold constant_nil (derecurs env q) vars in
159 let r = derecurs_regexp (fun p -> p) env r in
160 PRegexp (r, q)
161 and derecurs_regexp vars env = function
162 | Epsilon -> PEpsilon
163 | Elem p -> PElem (vars (derecurs env p))
164 | Seq (p1,p2) -> PSeq (derecurs_regexp vars env p1, derecurs_regexp vars env p2)
165 | Alt (p1,p2) -> PAlt (derecurs_regexp vars env p1, derecurs_regexp vars env p2)
166 | Star p -> PStar (derecurs_regexp vars env p)
167 | WeakStar p -> PStar (derecurs_regexp vars env p)
168 | SeqCapture (x,p) -> derecurs_regexp (fun p -> PAnd (vars p, PCapture x)) env p
169
170
171 and derecurs_def env b =
172 let b = List.map (fun (v,p) -> (v,p,mk_slot p.loc)) b in
173 let env = List.fold_left (fun env (v,p,s) -> TypeEnv.add v s env) env b in
174 List.iter (fun (v,p,s) -> s.pdescr <- Some (derecurs env p)) b;
175 env
176
177 (* Stratification and recursive hash-consing *)
178
179 type descr =
180 | IType of Types.descr
181 | IOr of descr * descr
182 | IAnd of descr * descr
183 | IDiff of descr * descr
184 | ITimes of slot * slot
185 | IXml of slot * slot
186 | IArrow of slot * slot
187 | IOptional of descr
188 | IRecord of bool * slot label_map
189 | ICapture of id
190 | IConstant of id * Types.const
191 and slot = {
192 mutable fv : fv option;
193 mutable hash : int option;
194 mutable rank1: int; mutable rank2: int;
195 mutable gen1 : int; mutable gen2: int;
196 mutable d : descr option
197 }
198
199 let descr s =
200 match s.d with
201 | Some d -> d
202 | None -> assert false
203
204 let gen = ref 0
205 let rank = ref 0
206
207 let rec hash_descr = function
208 | IType x -> Types.hash_descr x
209 | IOr (d1,d2) -> 1 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
210 | IAnd (d1,d2) -> 2 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
211 | IDiff (d1,d2) -> 3 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
212 | IOptional d -> 4 + 17 * (hash_descr d)
213 | ITimes (s1,s2) -> 5 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
214 | IXml (s1,s2) -> 6 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
215 | IArrow (s1,s2) -> 7 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
216 | IRecord (o,r) -> (if o then 8 else 9) + 17 * (LabelMap.hash hash_slot r)
217 | ICapture x -> 10 + 17 * (Id.hash x)
218 | IConstant (x,y) -> 11 + 17 * (Id.hash x) + 257 * (Types.hash_const y)
219 and hash_slot s =
220 if s.gen1 = !gen then 13 * s.rank1
221 else (
222 incr rank;
223 s.rank1 <- !rank; s.gen1 <- !gen;
224 hash_descr (descr s)
225 )
226
227 let rec equal_descr d1 d2 =
228 match (d1,d2) with
229 | IType x1, IType x2 -> Types.equal_descr x1 x2
230 | IOr (x1,y1), IOr (x2,y2)
231 | IAnd (x1,y1), IAnd (x2,y2)
232 | IDiff (x1,y1), IDiff (x2,y2) -> (equal_descr x1 x2) && (equal_descr y1 y2)
233 | IOptional x1, IOptional x2 -> equal_descr x1 x2
234 | ITimes (x1,y1), ITimes (x2,y2)
235 | IXml (x1,y1), IXml (x2,y2)
236 | IArrow (x1,y1), IArrow (x2,y2) -> (equal_slot x1 x2) && (equal_slot y1 y2)
237 | IRecord (o1,r1), IRecord (o2,r2) -> (o1 = o2) && (LabelMap.equal equal_slot r1 r2)
238 | ICapture x1, ICapture x2 -> Id.equal x1 x2
239 | IConstant (x1,y1), IConstant (x2,y2) -> (Id.equal x1 x2) && (Types.equal_const y1 y2)
240 | _ -> false
241 and equal_slot s1 s2 =
242 ((s1.gen1 = !gen) && (s2.gen2 = !gen) && (s1.rank1 = s2.rank2))
243 ||
244 ((s1.gen1 <> !gen) && (s2.gen2 <> !gen) && (
245 incr rank;
246 s1.rank1 <- !rank; s1.gen1 <- !gen;
247 s2.rank2 <- !rank; s2.gen2 <- !gen;
248 equal_descr (descr s1) (descr s2)
249 ))
250
251 module Arg = struct
252 type t = slot
253
254 let hash s =
255 match s.hash with
256 | Some h -> h
257 | None ->
258 incr gen; rank := 0;
259 let h = hash_slot s in
260 s.hash <- Some h;
261 h
262
263 let equal s1 s2 =
264 (s1 == s2) ||
265 (incr gen; rank := 0;
266 let e = equal_slot s1 s2 in
267 (* if e then Printf.eprintf "Equal\n"; *)
268 e)
269 end
270 module SlotTable = Hashtbl.Make(Arg)
271
272 let rec fv_slot s =
273 match s.fv with
274 | Some x -> x
275 | None ->
276 if s.gen1 = !gen then IdSet.empty
277 else (s.gen1 <- !gen; fv_descr (descr s))
278 and fv_descr = function
279 | IType _ -> IdSet.empty
280 | IOr (d1,d2)
281 | IAnd (d1,d2)
282 | IDiff (d1,d2) -> IdSet.cup (fv_descr d1) (fv_descr d2)
283 | IOptional d -> fv_descr d
284 | ITimes (s1,s2)
285 | IXml (s1,s2)
286 | IArrow (s1,s2) -> IdSet.cup (fv_slot s1) (fv_slot s2)
287 | IRecord (o,r) -> List.fold_left IdSet.cup IdSet.empty (LabelMap.map_to_list fv_slot r)
288 | ICapture x | IConstant (x,_) -> IdSet.singleton x
289
290
291 let compute_fv s =
292 match s.fv with
293 | Some x -> ()
294 | None ->
295 incr gen;
296 let x = fv_slot s in
297 s.fv <- Some x
298
299
300 let todo_fv = ref []
301
302 let mk () =
303 let s =
304 { d = None;
305 fv = None;
306 hash = None;
307 rank1 = 0; rank2 = 0;
308 gen1 = 0; gen2 = 0 } in
309 todo_fv := s :: !todo_fv;
310 s
311
312 let flush_fv () =
313 List.iter compute_fv !todo_fv;
314 todo_fv := []
315
316 let compile_slot_hash = DerecursTable.create 67
317 let compile_hash = DerecursTable.create 67
318
319 let defs = ref []
320
321 let rec compile p =
322 try DerecursTable.find compile_hash p
323 with Not_found ->
324 let c = real_compile p in
325 DerecursTable.replace compile_hash p c;
326 c
327 and real_compile = function
328 | PAlias v ->
329 if v.ploop then
330 raise_loc_generic v.ploc ("Unguarded recursion on type/pattern");
331 v.ploop <- true;
332 let r = match v.pdescr with Some x -> compile x | _ -> assert false in
333 v.ploop <- false;
334 r
335 | PType t -> IType t
336 | POr (t1,t2) -> IOr (compile t1, compile t2)
337 | PAnd (t1,t2) -> IAnd (compile t1, compile t2)
338 | PDiff (t1,t2) -> IDiff (compile t1, compile t2)
339 | PTimes (t1,t2) -> ITimes (compile_slot t1, compile_slot t2)
340 | PXml (t1,t2) -> IXml (compile_slot t1, compile_slot t2)
341 | PArrow (t1,t2) -> IArrow (compile_slot t1, compile_slot t2)
342 | POptional t -> IOptional (compile t)
343 | PRecord (o,r) -> IRecord (o, LabelMap.map compile_slot r)
344 | PConstant (x,v) -> IConstant (x,v)
345 | PCapture x -> ICapture x
346 | PRegexp (r,q) -> compile_regexp r q
347 and compile_regexp r q =
348 let memo = RE.create 17 in
349 let rec aux accu r q =
350 if RE.mem memo (r,q) then accu
351 else (
352 RE.add memo (r,q) ();
353 match r with
354 | PEpsilon -> (match q with PRegexp (r,q) -> aux accu r q | _ -> (compile q) :: accu)
355 | PElem p -> ITimes (compile_slot p, compile_slot q) :: accu
356 | PSeq (r1,r2) -> aux accu r1 (PRegexp (r2,q))
357 | PAlt (r1,r2) -> aux (aux accu r1 q) r2 q
358 | PStar r1 -> aux (aux accu r1 (PRegexp (r,q))) PEpsilon q
359 | PWeakStar r1 -> aux (aux accu PEpsilon q) r1 (PRegexp (r,q))
360 )
361 in
362 let accu = aux [] r q in
363 match accu with
364 | [] -> assert false
365 | p::l -> List.fold_left (fun acc p -> IOr (p,acc)) p l
366 and compile_slot p =
367 try DerecursTable.find compile_slot_hash p
368 with Not_found ->
369 let s = mk () in
370 defs := (s,p) :: !defs;
371 DerecursTable.add compile_slot_hash p s;
372 s
373
374
375 let rec flush_defs () =
376 match !defs with
377 | [] -> ()
378 | (s,p)::t -> defs := t; s.d <- Some (compile p); flush_defs ()
379
380 let typ_nodes = SlotTable.create 67
381 let pat_nodes = SlotTable.create 67
382
383 let rec typ = function
384 | IType t -> t
385 | IOr (s1,s2) -> Types.cup (typ s1) (typ s2)
386 | IAnd (s1,s2) -> Types.cap (typ s1) (typ s2)
387 | IDiff (s1,s2) -> Types.diff (typ s1) (typ s2)
388 | ITimes (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
389 | IXml (s1,s2) -> Types.xml (typ_node s1) (typ_node s2)
390 | IArrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
391 | IOptional s -> Types.Record.or_absent (typ s)
392 | IRecord (o,r) -> Types.record' (o, LabelMap.map typ_node r)
393 | ICapture x | IConstant (x,_) -> assert false
394
395 and typ_node s : Types.node =
396 try SlotTable.find typ_nodes s
397 with Not_found ->
398 let x = Types.make () in
399 SlotTable.add typ_nodes s x;
400 Types.define x (typ (descr s));
401 x
402
403 let rec pat d : Patterns.descr =
404 if IdSet.is_empty (fv_descr d)
405 then Patterns.constr (typ d)
406 else pat_aux d
407
408
409 and pat_aux = function
410 | IOr (s1,s2) -> Patterns.cup (pat s1) (pat s2)
411 | IAnd (s1,s2) -> Patterns.cap (pat s1) (pat s2)
412 | IDiff (s1,s2) when IdSet.is_empty (fv_descr s2) ->
413 let s2 = Types.neg (typ s2) in
414 Patterns.cap (pat s1) (Patterns.constr s2)
415 | IDiff _ ->
416 raise (Patterns.Error "Difference not allowed in patterns")
417 | ITimes (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
418 | IXml (s1,s2) -> Patterns.xml (pat_node s1) (pat_node s2)
419 | IOptional _ ->
420 raise (Patterns.Error "Optional field not allowed in record patterns")
421 | IRecord (o,r) ->
422 let pats = ref [] in
423 let aux l s =
424 if IdSet.is_empty (fv_slot s) then typ_node s
425 else
426 ( pats := Patterns.record l (pat_node s) :: !pats;
427 Types.any_node )
428 in
429 let constr = Types.record' (o,LabelMap.mapi aux r) in
430 List.fold_left Patterns.cap (Patterns.constr constr) !pats
431 (* TODO: can avoid constr when o=true, and all fields have fv *)
432 | ICapture x -> Patterns.capture x
433 | IConstant (x,c) -> Patterns.constant x c
434 | IArrow _ ->
435 raise (Patterns.Error "Arrow not allowed in patterns")
436 | IType _ -> assert false
437
438 and pat_node s : Patterns.node =
439 try SlotTable.find pat_nodes s
440 with Not_found ->
441 let x = Patterns.make (fv_slot s) in
442 SlotTable.add pat_nodes s x;
443 Patterns.define x (pat (descr s));
444 x
445
446 let glb = State.ref "Typer.glb_env" TypeEnv.empty
447
448
449 let register_global_types b =
450 List.iter
451 (fun (v,p) ->
452 if TypeEnv.mem v !glb
453 then raise_loc_generic p.loc ("Multiple definition for type " ^ v)
454 ) b;
455 glb := derecurs_def !glb b;
456 let b = List.map (fun (v,p) -> (v,p,compile (derecurs !glb p))) b in
457 flush_defs ();
458 flush_fv ();
459 List.iter
460 (fun (v,p,s) ->
461 if not (IdSet.is_empty (fv_descr s)) then
462 raise_loc_generic p.loc "Capture variables are not allowed in types";
463 let t = typ s in
464 if (p.loc <> noloc) && (Types.is_empty t) then
465 warning p.loc ("This definition yield an empty type for " ^ v);
466 Types.Print.register_global v t) b
467
468 let dump_global_types ppf =
469 TypeEnv.iter (fun v _ -> Format.fprintf ppf " %s" v) !glb
470
471
472 let typ p =
473 let s = compile_slot (derecurs !glb p) in
474 flush_defs ();
475 flush_fv ();
476 if IdSet.is_empty (fv_slot s) then typ_node s
477 else raise_loc_generic p.loc "Capture variables are not allowed in types"
478
479 let pat p =
480 let s = compile_slot (derecurs !glb p) in
481 flush_defs ();
482 flush_fv ();
483 try pat_node s
484 with Patterns.Error e -> raise_loc_generic p.loc e
485 | Location (loc,exn) when loc = noloc -> raise (Location (p.loc, exn))
486
487
488 (* II. Build skeleton *)
489
490 module Fv = IdSet
491
492 let all_branches = ref []
493
494 (* IDEA: introduce a node Loc in the AST to override nolocs
495 in sub-expressions *)
496
497 let exp loc fv e =
498 fv,
499 { Typed.exp_loc = loc;
500 Typed.exp_typ = Types.empty;
501 Typed.exp_descr = e;
502 }
503
504
505 let rec expr loc = function
506 | LocatedExpr (loc,e) -> expr loc e
507 | Forget (e,t) ->
508 let (fv,e) = expr loc e and t = typ t in
509 exp loc fv (Typed.Forget (e,t))
510 | Var s ->
511 exp loc (Fv.singleton s) (Typed.Var s)
512 | Apply (e1,e2) ->
513 let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
514 exp loc (Fv.cup fv1 fv2) (Typed.Apply (e1,e2))
515 | Abstraction a ->
516 let iface = List.map (fun (t1,t2) -> (typ t1, typ t2))
517 a.fun_iface in
518 let t = List.fold_left
519 (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
520 Types.any iface in
521 let iface = List.map
522 (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
523 iface in
524 let (fv0,body) = branches a.fun_body in
525 let fv = match a.fun_name with
526 | None -> fv0
527 | Some f -> Fv.remove f fv0 in
528 let e = Typed.Abstraction
529 { Typed.fun_name = a.fun_name;
530 Typed.fun_iface = iface;
531 Typed.fun_body = body;
532 Typed.fun_typ = t;
533 Typed.fun_fv = fv
534 } in
535 exp loc fv e
536 | Cst c ->
537 exp loc Fv.empty (Typed.Cst c)
538 | Pair (e1,e2) ->
539 let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
540 exp loc (Fv.cup fv1 fv2) (Typed.Pair (e1,e2))
541 | Xml (e1,e2) ->
542 let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
543 exp loc (Fv.cup fv1 fv2) (Typed.Xml (e1,e2))
544 | Dot (e,l) ->
545 let (fv,e) = expr loc e in
546 exp loc fv (Typed.Dot (e,l))
547 | RemoveField (e,l) ->
548 let (fv,e) = expr loc e in
549 exp loc fv (Typed.RemoveField (e,l))
550 | RecordLitt r ->
551 let fv = ref Fv.empty in
552 let r = LabelMap.map
553 (fun e ->
554 let (fv2,e) = expr loc e
555 in fv := Fv.cup !fv fv2; e)
556 r in
557 exp loc !fv (Typed.RecordLitt r)
558 | Op (op,le) ->
559 let (fvs,ltes) = List.split (List.map (expr loc) le) in
560 let fv = List.fold_left Fv.cup Fv.empty fvs in
561 exp loc fv (Typed.Op (op,ltes))
562 | Match (e,b) ->
563 let (fv1,e) = expr loc e
564 and (fv2,b) = branches b in
565 exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b))
566 | Map (e,b) ->
567 let (fv1,e) = expr loc e
568 and (fv2,b) = branches b in
569 exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b))
570 | Ttree (e,b) ->
571 let b = b @ [ mknoloc (Internal Types.any), MatchFail ] in
572 let (fv1,e) = expr loc e
573 and (fv2,b) = branches b in
574 exp loc (Fv.cup fv1 fv2) (Typed.Ttree (e, b))
575 | MatchFail ->
576 exp loc (Fv.empty) Typed.MatchFail
577 | Try (e,b) ->
578 let (fv1,e) = expr loc e
579 and (fv2,b) = branches b in
580 exp loc (Fv.cup fv1 fv2) (Typed.Try (e, b))
581
582
583 and branches b =
584 let fv = ref Fv.empty in
585 let accept = ref Types.empty in
586 let branch (p,e) =
587 let (fv2,e) = expr noloc e in
588 let br_loc = merge_loc p.loc e.Typed.exp_loc in
589 let p = pat p in
590 let fv2 = Fv.diff fv2 (Patterns.fv p) in
591 fv := Fv.cup !fv fv2;
592 accept := Types.cup !accept (Types.descr (Patterns.accept p));
593 let br =
594 {
595 Typed.br_loc = br_loc;
596 Typed.br_used = br_loc = noloc;
597 Typed.br_pat = p;
598 Typed.br_body = e } in
599 all_branches := br :: !all_branches;
600 br in
601 let b = List.map branch b in
602 (!fv,
603 {
604 Typed.br_typ = Types.empty;
605 Typed.br_branches = b;
606 Typed.br_accept = !accept;
607 Typed.br_compiled = None;
608 }
609 )
610
611 let expr = expr noloc
612
613 let let_decl p e =
614 let (_,e) = expr e in
615 { Typed.let_pat = pat p;
616 Typed.let_body = e;
617 Typed.let_compiled = None }
618
619 (* III. Type-checks *)
620
621 let int_cup_record = Types.cup Types.Int.any Types.Record.any
622
623
624 type env = Types.descr Env.t
625
626 let match_fail = ref Types.empty
627
628 open Typed
629
630
631 let check loc t s msg =
632 if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
633
634 let rec type_check env e constr precise =
635 (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
636 Types.Print.print_descr constr precise;
637 *)
638 let d = type_check' e.exp_loc env e.exp_descr constr precise in
639 e.exp_typ <- Types.cup e.exp_typ d;
640 d
641
642 and type_check' loc env e constr precise = match e with
643 | Forget (e,t) ->
644 let t = Types.descr t in
645 ignore (type_check env e t false);
646 t
647 | Abstraction a ->
648 let t =
649 try Types.Arrow.check_strenghten a.fun_typ constr
650 with Not_found ->
651 raise_loc loc
652 (ShouldHave
653 (constr, "but the interface of the abstraction is not compatible"))
654 in
655 let env = match a.fun_name with
656 | None -> env
657 | Some f -> Env.add f a.fun_typ env in
658 List.iter
659 (fun (t1,t2) ->
660 ignore (type_check_branches loc env t1 a.fun_body t2 false)
661 ) a.fun_iface;
662 t
663
664 | Match (e,b) ->
665 let t = type_check env e b.br_accept true in
666 type_check_branches loc env t b constr precise
667
668 | Try (e,b) ->
669 let te = type_check env e constr precise in
670 let tb = type_check_branches loc env Types.any b constr precise in
671 Types.cup te tb
672
673 | Pair (e1,e2) ->
674 type_check_pair loc env e1 e2 constr precise
675 | Xml (e1,e2) ->
676 type_check_pair ~kind:`XML loc env e1 e2 constr precise
677
678 | RecordLitt r ->
679 (* try to get rid of precise = true for values of fields *)
680 if not (Types.Record.has_record constr) then
681 raise_loc loc (ShouldHave (constr,"but it is a record."));
682 let (rconstr,res) =
683 List.fold_left
684 (fun (rconstr,res) (l,e) ->
685 (* could compute (split l e) once... *)
686 let pi = Types.Record.project_opt rconstr l in
687 if Types.is_empty pi then
688 raise_loc loc
689 (ShouldHave (constr,(Printf.sprintf
690 "Field %s is not allowed here."
691 (LabelPool.value l)
692 )
693 ));
694 let t = type_check env e pi true in
695 let rconstr = Types.Record.condition rconstr l t in
696 let res = if precise then (l,Types.cons t) :: res else res in
697 (rconstr,res)
698 ) (constr, []) (LabelMap.get r)
699 in
700 if not (Types.Record.has_empty_record rconstr) then
701 raise_loc loc
702 (ShouldHave (constr,"More field should be present"));
703 if precise then
704 Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res)
705 else constr
706 | Map (e,b) ->
707 let t = type_check env e (Sequence.star b.br_accept) true in
708
709 let constr' = Sequence.approx (Types.cap Sequence.any constr) in
710 let exact = Types.subtype (Sequence.star constr') constr in
711 (* Note:
712 - could be more precise by integrating the decomposition
713 of constr inside Sequence.map.
714 *)
715 let res =
716 Sequence.map
717 (fun t ->
718 type_check_branches loc env t b constr' (precise || (not exact)))
719 t in
720 if not exact then check loc res constr "";
721 if precise then res else constr
722 | Op ("@", [e1;e2]) ->
723 let constr' = Sequence.star
724 (Sequence.approx (Types.cap Sequence.any constr)) in
725 let exact = Types.subtype constr' constr in
726 if exact then
727 let t1 = type_check env e1 constr' precise
728 and t2 = type_check env e2 constr' precise in
729 if precise then Sequence.concat t1 t2 else constr
730 else
731 (* Note:
732 the knownledge of t1 may makes it useless to
733 check t2 with 'precise' ... *)
734 let t1 = type_check env e1 constr' true
735 and t2 = type_check env e2 constr' true in
736 let res = Sequence.concat t1 t2 in
737 check loc res constr "";
738 if precise then res else constr
739 | Apply (e1,e2) ->
740 (*
741 let constr' = Sequence.star
742 (Sequence.approx (Types.cap Sequence.any constr)) in
743 let t1 = type_check env e1 (Types.cup Types.Arrow.any constr') true in
744 let t1_fun = Types.Arrow.get t1 in
745
746 let has_fun = not (Types.Arrow.is_empty t1_fun)
747 and has_seq = not (Types.subtype t1 Types.Arrow.any) in
748
749 let constr' =
750 Types.cap
751 (if has_fun then Types.Arrow.domain t1_fun else Types.any)
752 (if has_seq then constr' else Types.any)
753 in
754 let need_arg = has_fun && Types.Arrow.need_arg t1_fun in
755 let precise = need_arg || has_seq in
756 let t2 = type_check env e2 constr' precise in
757 let res = Types.cup
758 (if has_fun then
759 if need_arg then Types.Arrow.apply t1_fun t2
760 else Types.Arrow.apply_noarg t1_fun
761 else Types.empty)
762 (if has_seq then Sequence.concat t1 t2
763 else Types.empty)
764 in
765 check loc res constr "";
766 res
767 *)
768 let t1 = type_check env e1 Types.Arrow.any true in
769 let t1 = Types.Arrow.get t1 in
770 let dom = Types.Arrow.domain t1 in
771 let res =
772 if Types.Arrow.need_arg t1 then
773 let t2 = type_check env e2 dom true in
774 Types.Arrow.apply t1 t2
775 else
776 (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
777 in
778 check loc res constr "";
779 res
780 | Op ("flatten", [e]) ->
781 let constr' = Sequence.star
782 (Sequence.approx (Types.cap Sequence.any constr)) in
783 let sconstr' = Sequence.star constr' in
784 let exact = Types.subtype constr' constr in
785 if exact then
786 let t = type_check env e sconstr' precise in
787 if precise then Sequence.flatten t else constr
788 else
789 let t = type_check env e sconstr' true in
790 let res = Sequence.flatten t in
791 check loc res constr "";
792 if precise then res else constr
793 | Op ("atom_of", [e]) ->
794 let t = type_check env e Sequence.string false in
795 Types.atom Atoms.any
796 | _ ->
797 let t : Types.descr = compute_type' loc env e in
798 check loc t constr "";
799 t
800
801 and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise =
802 let rects = Types.Product.get ~kind constr in
803 if Types.Product.is_empty rects then
804 (match kind with
805 | `Normal -> raise_loc loc (ShouldHave (constr,"but it is a pair."))
806 | `XML -> raise_loc loc (ShouldHave (constr,"but it is an XML element.")));
807 let pi1 = Types.Product.pi1 rects in
808
809 let t1 = type_check env e1 (Types.Product.pi1 rects)
810 (precise || (Types.Product.need_second rects))in
811 let rects = Types.Product.restrict_1 rects t1 in
812 let t2 = type_check env e2 (Types.Product.pi2 rects) precise in
813 if precise then
814 match kind with
815 | `Normal -> Types.times (Types.cons t1) (Types.cons t2)
816 | `XML -> Types.xml (Types.cons t1) (Types.cons t2)
817 else
818 constr
819
820
821 and compute_type env e =
822 type_check env e Types.any true
823
824 and compute_type' loc env = function
825 | Var s ->
826 (try Env.find s env
827 with Not_found -> raise_loc loc (UnboundId (Id.value s))
828 )
829 | Cst c -> Types.constant c
830 | Dot (e,l) ->
831 let t = type_check env e Types.Record.any true in
832 (try (Types.Record.project t l)
833 with Not_found -> raise_loc loc (WrongLabel(t,l)))
834 | RemoveField (e,l) ->
835 let t = type_check env e Types.Record.any true in
836 Types.Record.remove_field t l
837 | Op (op, el) ->
838 let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in
839 type_op loc op args
840 | Ttree (e,b) ->
841 let t = type_check env e Sequence.any true in
842 let r =
843 Sequence.map_tree
844 (fun t ->
845 let res = type_check_branches loc env t b Sequence.any true in
846 let resid = !match_fail in
847 match_fail := Types.empty;
848 (res,resid)
849 ) t
850 in
851 r
852
853 (* We keep these cases here to allow comparison and benchmarking ...
854 Just comment the corresponding cases in type_check' to
855 activate these ones.
856 *)
857 | Map (e,b) ->
858 let t = compute_type env e in
859 Sequence.map (fun t -> type_check_branches loc env t b Types.any true) t
860 | Pair (e1,e2) ->
861 let t1 = compute_type env e1
862 and t2 = compute_type env e2 in
863 Types.times (Types.cons t1) (Types.cons t2)
864 | RecordLitt r ->
865 let r = LabelMap.map (fun e -> Types.cons (compute_type env e)) r in
866 Types.record' (false,r)
867 | _ -> assert false
868
869 and type_check_branches loc env targ brs constr precise =
870 if Types.is_empty targ then Types.empty
871 else (
872 brs.br_typ <- Types.cup brs.br_typ targ;
873 branches_aux loc env targ
874 (if precise then Types.empty else constr)
875 constr precise brs.br_branches
876 )
877
878 and branches_aux loc env targ tres constr precise = function
879 | [] -> raise_loc loc (NonExhaustive targ)
880 | { br_body = { exp_descr = MatchFail } } :: _ ->
881 match_fail := Types.cup !match_fail targ;
882 tres
883 | b :: rem ->
884 let p = b.br_pat in
885 let acc = Types.descr (Patterns.accept p) in
886
887 let targ' = Types.cap targ acc in
888 if Types.is_empty targ'
889 then branches_aux loc env targ tres constr precise rem
890 else
891 ( b.br_used <- true;
892 let res = Patterns.filter targ' p in
893 let env' = List.fold_left
894 (fun env (x,t) -> Env.add x (Types.descr t) env)
895 env res in
896 let t = type_check env' b.br_body constr precise in
897 let tres = if precise then Types.cup t tres else tres in
898 let targ'' = Types.diff targ acc in
899 if (Types.non_empty targ'') then
900 branches_aux loc env targ'' tres constr precise rem
901 else
902 tres
903 )
904
905 and type_let_decl env l =
906 let acc = Types.descr (Patterns.accept l.let_pat) in
907 let t = type_check env l.let_body acc true in
908 let res = Patterns.filter t l.let_pat in
909 List.map (fun (x,t) -> (x, Types.descr t)) res
910
911 and type_rec_funs env l =
912 let types =
913 List.fold_left
914 (fun accu -> function {let_body={exp_descr=Abstraction a}} as l ->
915 let t = a.fun_typ in
916 let acc = Types.descr (Patterns.accept l.let_pat) in
917 if not (Types.subtype t acc) then
918 raise_loc l.let_body.exp_loc (NonExhaustive (Types.diff t acc));
919 let res = Patterns.filter t l.let_pat in
920 List.fold_left (fun accu (x,t) -> (x, Types.descr t)::accu) accu res
921 | _ -> assert false) [] l
922 in
923 let env' = List.fold_left (fun env (x,t) -> Env.add x t env) env types in
924 List.iter
925 (function { let_body = { exp_descr = Abstraction a } } as l ->
926 ignore (type_check env' l.let_body Types.any false)
927 | _ -> assert false) l;
928 types
929
930
931 and type_op loc op args =
932 match (op,args) with
933 | "+", [loc1,t1; loc2,t2] ->
934 check loc1 t1 int_cup_record
935 "The first argument of + must be an integer or a record";
936 let int = Types.Int.get t1 in
937 let int = if Intervals.is_empty int then None else Some int in
938 let r = if Types.Record.has_record t1 then Some t1 else None in
939 (match (int,r) with
940 | Some t1, None ->
941 if not (Types.Int.is_int t2) then
942 raise_loc loc2
943 (Constraint
944 (t2,Types.Int.any,
945 "The second argument of + must be an integer"));
946 Types.Int.put
947 (Intervals.add t1 (Types.Int.get t2));
948 | None, Some r1 ->
949 check loc2 t2 Types.Record.any
950 "The second argument of + must be a record";
951 Types.Record.merge r1 t2
952 | None, None ->
953 Types.empty
954 | Some t1, Some r1 ->
955 check loc2 t2 int_cup_record
956 "The second argument of + must be an integer or a record";
957 Types.cup
958 (Types.Int.put (Intervals.add t1 (Types.Int.get t2)))
959 (Types.Record.merge r1 t2)
960 )
961 | "-", [loc1,t1; loc2,t2] ->
962 type_int_binop Intervals.sub loc1 t1 loc2 t2
963 | ("*" | "/" | "mod"), [loc1,t1; loc2,t2] ->
964 type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
965 | "@", [loc1,t1; loc2,t2] ->
966 check loc1 t1 Sequence.any
967 "The first argument of @ must be a sequence";
968 Sequence.concat t1 t2
969 | "flatten", [loc1,t1] ->
970 check loc1 t1 Sequence.seqseq
971 "The argument of flatten must be a sequence of sequences";
972 Sequence.flatten t1
973 | "load_xml", [loc1,t1] ->
974 check loc1 t1 Sequence.string
975 "The argument of load_xml must be a string (filename)";
976 Types.any
977 | "load_file", [loc1,t1] ->
978 check loc1 t1 Sequence.string
979 "The argument of load_file must be a string (filename)";
980 Sequence.string
981 | "load_html", [loc1,t1] ->
982 check loc1 t1 Sequence.string
983 "The argument of load_html must be a string (filename)";
984 Types.any
985 | "raise", [loc1,t1] ->
986 Types.empty
987 | "print_xml", [loc1,t1] ->
988 Sequence.string
989 | "print", [loc1,t1] ->
990 check loc1 t1 Sequence.string
991 "The argument of print must be a string";
992 Sequence.nil_type
993 | "dump_to_file", [loc1,t1; loc2,t2] ->
994 check loc1 t1 Sequence.string
995 "The argument of dump_to_file must be a string (filename)";
996 check loc2 t2 Sequence.string
997 "The argument of dump_to_file must be a string (value to dump)";
998 Sequence.nil_type
999 | "int_of", [loc1,t1] ->
1000 check loc1 t1 Sequence.string
1001 "The argument of int_of must be a string";
1002 if not (Types.subtype t1 Builtin.intstr) then
1003 warning loc "This application of int_of may fail";
1004 Types.interval Intervals.any
1005 | "string_of", [loc1,t1] ->
1006 Sequence.string
1007 | "=", [loc1,t1; loc2,t2] ->
1008 (* could prevent comparision of functional value here... *)
1009 (* could also handle the case when t1 and t2 are the same
1010 singleton type *)
1011 if Types.is_empty (Types.cap t1 t2) then
1012 Builtin.false_type
1013 else
1014 Builtin.bool
1015 | ("<=" | "<" | ">" | ">=" ), [loc1,t1; loc2,t2] ->
1016 (* could prevent comparision of functional value here... *)
1017 Builtin.bool
1018 | _ -> assert false
1019
1020 and type_int_binop f loc1 t1 loc2 t2 =
1021 if not (Types.Int.is_int t1) then
1022 raise_loc loc1
1023 (Constraint
1024 (t1,Types.Int.any,
1025 "The first argument must be an integer"));
1026 if not (Types.Int.is_int t2) then
1027 raise_loc loc2
1028 (Constraint
1029 (t2,Types.Int.any,
1030 "The second argument must be an integer"));
1031 Types.Int.put
1032 (f (Types.Int.get t1) (Types.Int.get t2))
1033
1034
1035
1036
1037 let report_unused_branches () =
1038 List.iter
1039 (fun b ->
1040 if not b.br_used then
1041 warning b.br_loc "This branch is not used"
1042 )
1043 !all_branches;
1044 all_branches := []
1045

CVS Admin">CVS Admin
ViewVC Help
Powered by ViewVC 1.1.5