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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 427 - (show annotations)
Tue Jul 10 17:33:51 2007 UTC (5 years, 10 months ago) by abate
File size: 29140 byte(s)
[r2003-05-25 12:20:16 by cvscast] No warning for embedded unused branches

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

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