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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 86 - (show annotations)
Tue Jul 10 17:05:01 2007 UTC (5 years, 10 months ago) by abate
File size: 23256 byte(s)
[r2002-11-08 22:16:27 by cvscast] Empty log message

Original author: cvscast
Date: 2002-11-08 22:16:27+00:00
1 (* I. Transform the abstract syntax of types and patterns into
2 the internal form *)
3
4 open Location
5 open Ast
6
7 exception Pattern of string
8 exception NonExhaustive of Types.descr
9 exception MultipleLabel of Types.label
10 exception Constraint of Types.descr * Types.descr * string
11 exception ShouldHave of Types.descr * string
12 exception WrongLabel of Types.descr * Types.label
13 exception UnboundId of string
14
15 let raise_loc loc exn = raise (Location (loc,exn))
16
17 (* Internal representation as a graph (desugar recursive types and regexp),
18 to compute freevars, etc... *)
19
20 type ti = {
21 id : int;
22 mutable loc' : loc;
23 mutable fv : string SortedList.t option;
24 mutable descr': descr;
25 mutable type_node: Types.node option;
26 mutable pat_node: Patterns.node option
27 }
28 and descr =
29 [ `Alias of string * ti
30 | `Type of Types.descr
31 | `Or of ti * ti
32 | `And of ti * ti * bool
33 | `Diff of ti * ti
34 | `Times of ti * ti
35 | `Arrow of ti * ti
36 | `Record of Types.label * bool * ti
37 | `Capture of Patterns.capture
38 | `Constant of Patterns.capture * Types.const
39 ]
40
41
42
43 module S = struct type t = string let compare = compare end
44 module StringMap = Map.Make(S)
45 module StringSet = Set.Make(S)
46
47 let mk' =
48 let counter = ref 0 in
49 fun loc ->
50 incr counter;
51 let rec x = {
52 id = !counter;
53 loc' = loc;
54 fv = None;
55 descr' = `Alias ("__dummy__", x);
56 type_node = None;
57 pat_node = None
58 } in
59 x
60
61 let cons loc d =
62 let x = mk' loc in
63 x.descr' <- d;
64 x
65
66 (* Note:
67 Compilation of Regexp is implemented as a ``rewriting'' of
68 the parsed syntax, in order to be able to print its result
69 (for debugging for instance)
70
71 It would be possible (and a little more efficient) to produce
72 directly ti nodes.
73 *)
74
75 module Regexp = struct
76 let defs = ref []
77 let name =
78 let c = ref 0 in
79 fun () ->
80 incr c;
81 "#" ^ (string_of_int !c)
82
83 let rec seq_vars accu = function
84 | Epsilon | Elem _ -> accu
85 | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
86 | Star r | WeakStar r -> seq_vars accu r
87 | SeqCapture (v,r) -> seq_vars (StringSet.add v accu) r
88
89 let uniq_id = let r = ref 0 in fun () -> incr r; !r
90
91 type flat = [ `Epsilon
92 | `Elem of int * Ast.ppat (* the int arg is used to
93 to stop generic comparison *)
94 | `Seq of flat * flat
95 | `Alt of flat * flat
96 | `Star of flat
97 | `WeakStar of flat ]
98
99 let rec propagate vars : regexp -> flat = function
100 | Epsilon -> `Epsilon
101 | Elem x -> let p = vars x in `Elem (uniq_id (),p)
102 | Seq (r1,r2) -> `Seq (propagate vars r1,propagate vars r2)
103 | Alt (r1,r2) -> `Alt (propagate vars r1, propagate vars r2)
104 | Star r -> `Star (propagate vars r)
105 | WeakStar r -> `WeakStar (propagate vars r)
106 | SeqCapture (v,x) ->
107 let v= mk noloc (Capture v) in
108 propagate (fun p -> mk noloc (And (vars p,v,true))) x
109
110 let cup r1 r2 =
111 match (r1,r2) with
112 | (_, `Empty) -> r1
113 | (`Empty, _) -> r2
114 | (`Res t1, `Res t2) -> `Res (mk noloc (Or (t1,t2)))
115
116 (*TODO: review this compilation schema to avoid explosion when
117 coding (Optional x) by (Or(Epsilon,x)); memoization ... *)
118
119 module Memo = Map.Make(struct type t = flat list let compare = compare end)
120 module Coind = Set.Make(struct type t = flat list let compare = compare end)
121 let memo = ref Memo.empty
122
123 let rec compile fin e seq : [`Res of Ast.ppat | `Empty] =
124 if Coind.mem seq !e then `Empty
125 else (
126 e := Coind.add seq !e;
127 match seq with
128 | [] ->
129 `Res fin
130 | `Epsilon :: rest ->
131 compile fin e rest
132 | `Elem (_,p) :: rest ->
133 `Res (mk noloc (Prod (p, guard_compile fin rest)))
134 | `Seq (r1,r2) :: rest ->
135 compile fin e (r1 :: r2 :: rest)
136 | `Alt (r1,r2) :: rest ->
137 cup (compile fin e (r1::rest)) (compile fin e (r2::rest))
138 | `Star r :: rest ->
139 cup (compile fin e (r::seq)) (compile fin e rest)
140 | `WeakStar r :: rest ->
141 cup (compile fin e rest) (compile fin e (r::seq))
142 )
143 and guard_compile fin seq =
144 try Memo.find seq !memo
145 with
146 Not_found ->
147 let n = name () in
148 let v = mk noloc (PatVar n) in
149 memo := Memo.add seq v !memo;
150 let d = compile fin (ref Coind.empty) seq in
151 (match d with
152 | `Empty -> assert false
153 | `Res d -> defs := (n,d) :: !defs);
154 v
155
156
157 let constant_nil v t =
158 mk noloc (And (t, (mk noloc (Constant (v, Types.Atom Sequence.nil_atom))), true))
159
160 let compile regexp queue : ppat =
161 let vars = seq_vars StringSet.empty regexp in
162 let fin = StringSet.fold constant_nil vars queue in
163 let n = guard_compile fin [propagate (fun p -> p) regexp] in
164 memo := Memo.empty;
165 let d = !defs in
166 defs := [];
167 mk noloc (Recurs (n,d))
168 end
169
170 let compile_regexp = Regexp.compile
171
172
173 let rec compile env { loc = loc; descr = d } : ti =
174 match (d : Ast.ppat') with
175 | PatVar s ->
176 (try StringMap.find s env
177 with Not_found ->
178 raise_loc loc (Pattern ("Undefined type variable " ^ s))
179 )
180 | Recurs (t, b) -> compile (compile_many env b) t
181 | Regexp (r,q) -> compile env (Regexp.compile r q)
182 | Internal t -> cons loc (`Type t)
183 | Or (t1,t2) -> cons loc (`Or (compile env t1, compile env t2))
184 | And (t1,t2,e) -> cons loc (`And (compile env t1, compile env t2,e))
185 | Diff (t1,t2) -> cons loc (`Diff (compile env t1, compile env t2))
186 | Prod (t1,t2) -> cons loc (`Times (compile env t1, compile env t2))
187 | Arrow (t1,t2) -> cons loc (`Arrow (compile env t1, compile env t2))
188 | Record (l,o,t) -> cons loc (`Record (l,o,compile env t))
189 | Constant (x,v) -> cons loc (`Constant (x,v))
190 | Capture x -> cons loc (`Capture x)
191
192 and compile_many env b =
193 let b = List.map (fun (v,t) -> (v,t,mk' t.loc)) b in
194 let env =
195 List.fold_left (fun env (v,t,x) -> StringMap.add v x env) env b in
196 List.iter (fun (v,t,x) -> x.descr' <- `Alias (v, compile env t)) b;
197 env
198
199
200 let comp_fv_seen = ref []
201 let comp_fv_res = ref []
202 let rec comp_fv s =
203 if List.memq s !comp_fv_seen then ()
204 else (
205 comp_fv_seen := s :: !comp_fv_seen;
206 (match s.descr' with
207 | `Alias (_,x) -> comp_fv x
208 | `Or (s1,s2)
209 | `And (s1,s2,_)
210 | `Diff (s1,s2)
211 | `Times (s1,s2)
212 | `Arrow (s1,s2) -> comp_fv s1; comp_fv s2
213 | `Record (l,opt,s) -> comp_fv s
214 | `Type _ -> ()
215 | `Capture x
216 | `Constant (x,_) -> comp_fv_res := x :: !comp_fv_res);
217 if (!comp_fv_res = []) then s.fv <- Some [];
218 (* TODO: check that the above line is correct *)
219 )
220
221
222
223 let fv s =
224 match s.fv with
225 | Some l -> l
226 | None ->
227 comp_fv s;
228 let l = SortedList.from_list !comp_fv_res in
229 comp_fv_res := [];
230 comp_fv_seen := [];
231 s.fv <- Some l;
232 l
233
234 let rec typ seen s : Types.descr =
235 match s.descr' with
236 | `Alias (v,x) ->
237 if List.memq s seen then
238 raise_loc s.loc'
239 (Pattern
240 ("Unguarded recursion on variable " ^ v ^ " in this type"))
241 else typ (s :: seen) x
242 | `Type t -> t
243 | `Or (s1,s2) -> Types.cup (typ seen s1) (typ seen s2)
244 | `And (s1,s2,_) -> Types.cap (typ seen s1) (typ seen s2)
245 | `Diff (s1,s2) -> Types.diff (typ seen s1) (typ seen s2)
246 | `Times (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
247 | `Arrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
248 | `Record (l,o,s) -> Types.record l o (typ_node s)
249 | `Capture _ | `Constant _ -> assert false
250
251 and typ_node s : Types.node =
252 match s.type_node with
253 | Some x -> x
254 | None ->
255 let x = Types.make () in
256 s.type_node <- Some x;
257 let t = typ [] s in
258 Types.define x t;
259 x
260
261 let type_node s =
262 let s = typ_node s in
263 let s = Types.internalize s in
264 (* Types.define s (Types.normalize (Types.descr s)); *)
265 s
266
267 let rec pat seen s : Patterns.descr =
268 if fv s = [] then Patterns.constr (type_node s) else
269 match s.descr' with
270 | `Alias (v,x) ->
271 if List.memq s seen then
272 raise_loc s.loc'
273 (Pattern
274 ("Unguarded recursion on variable " ^ v ^ " in this pattern"))
275 else pat (s :: seen) x
276 | `Or (s1,s2) -> Patterns.cup (pat seen s1) (pat seen s2)
277 | `And (s1,s2,e) -> Patterns.cap (pat seen s1) (pat seen s2) e
278 | `Diff (s1,s2) when fv s2 = [] ->
279 let s2 = Types.cons (Types.neg (Types.descr (type_node s2)))in
280 Patterns.cap (pat seen s1) (Patterns.constr s2) true
281 | `Diff _ ->
282 raise_loc s.loc' (Pattern "Difference not allowed in patterns")
283 | `Times (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
284 | `Record (l,false,s) -> Patterns.record l (pat_node s)
285 | `Record _ ->
286 raise_loc s.loc'
287 (Pattern "Optional field not allowed in record patterns")
288 | `Capture x -> Patterns.capture x
289 | `Constant (x,c) -> Patterns.constant x c
290 | `Arrow _ ->
291 raise_loc s.loc' (Pattern "Arrow not allowed in patterns")
292 | `Type _ -> assert false
293
294 and pat_node s : Patterns.node =
295 match s.pat_node with
296 | Some x -> x
297 | None ->
298 let x = Patterns.make (fv s) in
299 s.pat_node <- Some x;
300 let t = pat [] s in
301 Patterns.define x t;
302 x
303
304 let global_types = ref StringMap.empty
305
306 let mk_typ e =
307 if fv e = [] then type_node e
308 else raise_loc e.loc' (Pattern "Capture variables are not allowed in types")
309
310
311 let typ e =
312 mk_typ (compile !global_types e)
313
314 let pat e =
315 let e = compile !global_types e in
316 pat_node e
317
318 let register_global_types b =
319 let env = compile_many !global_types b in
320 List.iter (fun (v,_) ->
321 let d = Types.descr (mk_typ (StringMap.find v env)) in
322 (* let d = Types.normalize d in*)
323 Types.Print.register_global v d;
324 ()
325 ) b;
326 global_types := env
327
328
329 (* II. Build skeleton *)
330
331 module Fv = StringSet
332
333 let rec expr { loc = loc; descr = d } =
334 let (fv,td) =
335 match d with
336 | DebugTyper t -> (Fv.empty, Typed.DebugTyper (typ t))
337 | Forget (e,t) ->
338 let (fv,e) = expr e and t = typ t in
339 (fv, Typed.Forget (e,t))
340 | Var s -> (Fv.singleton s, Typed.Var s)
341 | Apply (e1,e2) ->
342 let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
343 (Fv.union fv1 fv2, Typed.Apply (e1,e2))
344 | Abstraction a ->
345 let iface = List.map (fun (t1,t2) -> (typ t1, typ t2)) a.fun_iface in
346 let t = List.fold_left
347 (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
348 Types.any iface in
349 let iface = List.map
350 (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
351 iface in
352 let (fv0,body) = branches a.fun_body in
353 let fv = match a.fun_name with
354 | None -> fv0
355 | Some f -> Fv.remove f fv0 in
356 (fv,
357 Typed.Abstraction
358 { Typed.fun_name = a.fun_name;
359 Typed.fun_iface = iface;
360 Typed.fun_body = body;
361 Typed.fun_typ = t;
362 Typed.fun_fv = Fv.elements fv
363 }
364 )
365 | Cst c -> (Fv.empty, Typed.Cst c)
366 | Pair (e1,e2) ->
367 let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
368 (Fv.union fv1 fv2, Typed.Pair (e1,e2))
369 | Dot (e,l) ->
370 let (fv,e) = expr e in
371 (fv, Typed.Dot (e,l))
372 | RecordLitt r ->
373 let fv = ref Fv.empty in
374 let r = List.sort (fun (l1,_) (l2,_) -> compare l1 l2) r in
375 let r = List.map
376 (fun (l,e) ->
377 let (fv2,e) = expr e in fv := Fv.union !fv fv2; (l,e))
378 r in
379 let rec check = function
380 | (l1,_) :: (l2,_) :: _ when l1 = l2 ->
381 raise_loc loc (MultipleLabel l1)
382 | _ :: rem -> check rem
383 | _ -> () in
384 check r;
385 (!fv, Typed.RecordLitt r)
386 | Op (op,le) ->
387 let (fvs,ltes) = List.split (List.map expr le) in
388 let fv = List.fold_left Fv.union Fv.empty fvs in
389 (fv, Typed.Op (op,ltes))
390 | Match (e,b) ->
391 let (fv1,e) = expr e
392 and (fv2,b) = branches b in
393 (Fv.union fv1 fv2, Typed.Match (e, b))
394 | Map (e,b) ->
395 let (fv1,e) = expr e
396 and (fv2,b) = branches b in
397 (Fv.union fv1 fv2, Typed.Map (e, b))
398 | Try (e,b) ->
399 let (fv1,e) = expr e
400 and (fv2,b) = branches b in
401 (Fv.union fv1 fv2, Typed.Try (e, b))
402 in
403 fv,
404 { Typed.exp_loc = loc;
405 Typed.exp_typ = Types.empty;
406 Typed.exp_descr = td;
407 }
408
409 and branches b =
410 let fv = ref Fv.empty in
411 let accept = ref Types.empty in
412 let b = List.map
413 (fun (p,e) ->
414 let (fv2,e) = expr e in
415 let p = pat p in
416 let fv2 = List.fold_right Fv.remove (Patterns.fv p) fv2 in
417 fv := Fv.union !fv fv2;
418 accept := Types.cup !accept (Types.descr (Patterns.accept p));
419 { Typed.br_used = false;
420 Typed.br_pat = p;
421 Typed.br_body = e }
422 ) b in
423 (!fv,
424 {
425 Typed.br_typ = Types.empty;
426 Typed.br_branches = b;
427 Typed.br_accept = !accept;
428 Typed.br_compiled = None;
429 }
430 )
431
432 let let_decl p e =
433 let (_,e) = expr e in
434 { Typed.let_pat = pat p;
435 Typed.let_body = e;
436 Typed.let_compiled = None }
437
438 (* III. Type-checks *)
439
440 module Env = StringMap
441 type env = Types.descr Env.t
442
443 open Typed
444
445 let warning loc msg =
446 Format.fprintf Format.std_formatter
447 "Warning %a:@\n%s@\n" Location.print_loc loc msg
448
449 let check loc t s msg =
450 if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
451
452 let rec type_check env e constr precise =
453 (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
454 Types.Print.print_descr constr precise;
455 *)
456 let d = type_check' e.exp_loc env e.exp_descr constr precise in
457 e.exp_typ <- Types.cup e.exp_typ d;
458 d
459
460 and type_check' loc env e constr precise = match e with
461 | Forget (e,t) ->
462 let t = Types.descr t in
463 ignore (type_check env e t false);
464 t
465 | Abstraction a ->
466 let t =
467 try Types.Arrow.check_strenghten a.fun_typ constr
468 with Not_found ->
469 raise_loc loc
470 (ShouldHave
471 (constr, "but the interface of the abstraction is not compatible"))
472 in
473 let env = match a.fun_name with
474 | None -> env
475 | Some f -> Env.add f a.fun_typ env in
476 List.iter
477 (fun (t1,t2) ->
478 ignore (type_check_branches loc env t1 a.fun_body t2 false)
479 ) a.fun_iface;
480 t
481
482 | Match (e,b) ->
483 let t = type_check env e b.br_accept true in
484 type_check_branches loc env t b constr precise
485
486 | Try (e,b) ->
487 let te = type_check env e constr precise in
488 let tb = type_check_branches loc env Types.any b constr precise in
489 Types.cup te tb
490
491 | Pair (e1,e2) ->
492 let rects = Types.Product.get constr in
493 if Types.Product.is_empty rects then
494 raise_loc loc (ShouldHave (constr,"but it is a pair."));
495 let pi1 = Types.Product.pi1 rects in
496
497 let t1 = type_check env e1 (Types.Product.pi1 rects)
498 (precise || (Types.Product.need_second rects))in
499 let rects = Types.Product.restrict_1 rects t1 in
500 let t2 = type_check env e2 (Types.Product.pi2 rects) precise in
501 if precise then
502 Types.times (Types.cons t1) (Types.cons t2)
503 else
504 constr
505
506 | RecordLitt r ->
507 let rconstr = Types.Record.get constr in
508 if Types.Record.is_empty rconstr then
509 raise_loc loc (ShouldHave (constr,"but it is a record."));
510
511 let (rconstr,res) =
512 List.fold_left
513 (fun (rconstr,res) (l,e) ->
514 let rconstr = Types.Record.restrict_label_present rconstr l in
515 let pi = Types.Record.project_field rconstr l in
516 if Types.Record.is_empty rconstr then
517 raise_loc loc
518 (ShouldHave (constr,(Printf.sprintf
519 "Field %s is not allowed here."
520 (Types.LabelPool.value l)
521 )
522 ));
523 let t = type_check env e pi true in
524 let rconstr = Types.Record.restrict_field rconstr l t in
525
526 let res =
527 if precise
528 then Types.cap res (Types.record l false (Types.cons t))
529 else res in
530 (rconstr,res)
531 ) (rconstr, if precise then Types.Record.any else constr) r
532 in
533 res
534
535 | Map (e,b) ->
536 let t = type_check env e (Sequence.star b.br_accept) true in
537
538 let constr' = Sequence.approx (Types.cap Sequence.any constr) in
539 let exact = Types.subtype (Sequence.star constr') constr in
540 (* Note:
541 - could be more precise by integrating the decomposition
542 of constr inside Sequence.map.
543 *)
544 let res =
545 Sequence.map
546 (fun t ->
547 type_check_branches loc env t b constr' (precise || (not exact)))
548 t in
549 if not exact then check loc res constr "";
550 if precise then res else constr
551 | Op ("@", [e1;e2]) ->
552 let constr' = Sequence.star
553 (Sequence.approx (Types.cap Sequence.any constr)) in
554 let exact = Types.subtype constr' constr in
555 if exact then
556 let t1 = type_check env e1 constr' precise
557 and t2 = type_check env e2 constr' precise in
558 if precise then Sequence.concat t1 t2 else constr
559 else
560 (* Note:
561 the knownledge of t1 may makes it useless to
562 check t2 with 'precise' ... *)
563 let t1 = type_check env e1 constr' true
564 and t2 = type_check env e2 constr' true in
565 let res = Sequence.concat t1 t2 in
566 check loc res constr "";
567 if precise then res else constr
568 | Apply (e1,e2) ->
569 let constr' = Sequence.star
570 (Sequence.approx (Types.cap Sequence.any constr)) in
571 let t1 = type_check env e1 (Types.cup Types.Arrow.any constr') true in
572 let t1_fun = Types.Arrow.get t1 in
573
574 let has_fun = not (Types.Arrow.is_empty t1_fun)
575 and has_seq = not (Types.subtype t1 Types.Arrow.any) in
576
577 let constr' =
578 Types.cap
579 (if has_fun then Types.Arrow.domain t1_fun else Types.any)
580 (if has_seq then constr' else Types.any)
581 in
582 let need_arg = has_fun && Types.Arrow.need_arg t1_fun in
583 let precise = need_arg || has_seq in
584 let t2 = type_check env e2 constr' precise in
585 let res = Types.cup
586 (if has_fun then
587 if need_arg then Types.Arrow.apply t1_fun t2
588 else Types.Arrow.apply_noarg t1_fun
589 else Types.empty)
590 (if has_seq then Sequence.concat t1 t2
591 else Types.empty)
592 in
593 check loc res constr "";
594 res
595 (*
596 let t1 = type_check env e1 Types.Arrow.any true in
597 let t1 = Types.Arrow.get t1 in
598 let dom = Types.Arrow.domain t1 in
599 if Types.Arrow.need_arg t1 then
600 let t2 = type_check env e2 dom true in
601 Types.Arrow.apply t1 t2
602 else
603 (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
604 *)
605
606 | Op ("flatten", [e]) ->
607 let constr' = Sequence.star
608 (Sequence.approx (Types.cap Sequence.any constr)) in
609 let sconstr' = Sequence.star constr' in
610 let exact = Types.subtype constr' constr in
611 if exact then
612 let t = type_check env e sconstr' precise in
613 if precise then Sequence.flatten t else constr
614 else
615 let t = type_check env e sconstr' true in
616 let res = Sequence.flatten t in
617 check loc res constr "";
618 if precise then res else constr
619 | _ ->
620 let t : Types.descr = compute_type' loc env e in
621 check loc t constr "";
622 t
623
624 and compute_type env e =
625 type_check env e Types.any true
626
627 and compute_type' loc env = function
628 | DebugTyper t -> Types.descr t
629 | Var s ->
630 (try Env.find s env
631 with Not_found -> raise_loc loc (UnboundId s)
632 )
633 | Cst c -> Types.constant c
634 | Dot (e,l) ->
635 let t = type_check env e Types.Record.any true in
636 (try (Types.Record.project t l)
637 with Not_found -> raise_loc loc (WrongLabel(t,l)))
638 | Op (op, el) ->
639 let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in
640 type_op loc op args
641 | Map (e,b) ->
642 let t = compute_type env e in
643 Sequence.map (fun t -> type_check_branches loc env t b Types.any true) t
644
645 (* We keep these cases here to allow comparison and benchmarking ...
646 Just comment the corresponding cases in type_check' to
647 activate these ones.
648 *)
649 | Pair (e1,e2) ->
650 let t1 = compute_type env e1
651 and t2 = compute_type env e2 in
652 Types.times (Types.cons t1) (Types.cons t2)
653 | RecordLitt r ->
654 List.fold_left
655 (fun accu (l,e) ->
656 let t = compute_type env e in
657 let t = Types.record l false (Types.cons t) in
658 Types.cap accu t
659 ) Types.Record.any r
660
661
662 | _ -> assert false
663
664 and type_check_branches loc env targ brs constr precise =
665 if Types.is_empty targ then Types.empty
666 else (
667 brs.br_typ <- Types.cup brs.br_typ targ;
668 branches_aux loc env targ
669 (if precise then Types.empty else constr)
670 constr precise brs.br_branches
671 )
672
673 and branches_aux loc env targ tres constr precise = function
674 | [] -> raise_loc loc (NonExhaustive targ)
675 | b :: rem ->
676 let p = b.br_pat in
677 let acc = Types.descr (Patterns.accept p) in
678
679 let targ' = Types.cap targ acc in
680 if Types.is_empty targ'
681 then branches_aux loc env targ tres constr precise rem
682 else
683 ( b.br_used <- true;
684 let res = Patterns.filter targ' p in
685 let env' = List.fold_left
686 (fun env (x,t) -> Env.add x (Types.descr t) env)
687 env res in
688 let t = type_check env' b.br_body constr precise in
689 let tres = if precise then Types.cup t tres else tres in
690 let targ'' = Types.diff targ acc in
691 if (Types.non_empty targ'') then
692 branches_aux loc env targ'' tres constr precise rem
693 else
694 tres
695 )
696
697 and type_let_decl env l =
698 let acc = Types.descr (Patterns.accept l.let_pat) in
699 let t = type_check env l.let_body acc true in
700 let res = Patterns.filter t l.let_pat in
701 List.map (fun (x,t) -> (x, Types.descr t)) res
702
703 and type_rec_funs env l =
704 let types =
705 List.fold_left
706 (fun accu -> function {let_body={exp_descr=Abstraction a}} as l ->
707 let t = a.fun_typ in
708 let acc = Types.descr (Patterns.accept l.let_pat) in
709 if not (Types.subtype t acc) then
710 raise_loc l.let_body.exp_loc (NonExhaustive (Types.diff t acc));
711 let res = Patterns.filter t l.let_pat in
712 List.fold_left (fun accu (x,t) -> (x, Types.descr t)::accu) accu res
713 | _ -> assert false) [] l
714 in
715 let env' = List.fold_left (fun env (x,t) -> Env.add x t env) env types in
716 List.iter
717 (function { let_body = { exp_descr = Abstraction a } } as l ->
718 ignore (type_check env' l.let_body Types.any false)
719 | _ -> assert false) l;
720 types
721
722
723 and type_op loc op args =
724 match (op,args) with
725 | "+", [loc1,t1; loc2,t2] ->
726 type_int_binop Intervals.add loc1 t1 loc2 t2
727 | "-", [loc1,t1; loc2,t2] ->
728 type_int_binop Intervals.sub loc1 t1 loc2 t2
729 | ("*" | "/"), [loc1,t1; loc2,t2] ->
730 type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
731 | "@", [loc1,t1; loc2,t2] ->
732 check loc1 t1 Sequence.any
733 "The first argument of @ must be a sequence";
734 Sequence.concat t1 t2
735 | "flatten", [loc1,t1] ->
736 check loc1 t1 Sequence.seqseq
737 "The argument of flatten must be a sequence of sequences";
738 Sequence.flatten t1
739 | "load_xml", [loc1,t1] ->
740 check loc1 t1 Sequence.string
741 "The argument of load_xml must be a string (filename)";
742 Types.any
743 | "raise", [loc1,t1] ->
744 Types.empty
745 | "print_xml", [loc1,t1] ->
746 Sequence.string
747 | "int_of", [loc1,t1] ->
748 check loc1 t1 Sequence.string
749 "The argument of int_of must a string";
750 if not (Types.subtype t1 Builtin.intstr) then
751 warning loc "This application of int_of may fail";
752 Types.interval Intervals.any
753 | _ -> assert false
754
755 and type_int_binop f loc1 t1 loc2 t2 =
756 if not (Types.Int.is_int t1) then
757 raise_loc loc1
758 (Constraint
759 (t1,Types.Int.any,
760 "The first argument must be an integer"));
761 if not (Types.Int.is_int t2) then
762 raise_loc loc2
763 (Constraint
764 (t2,Types.Int.any,
765 "The second argument must be an integer"));
766 Types.Int.put
767 (f (Types.Int.get t1) (Types.Int.get t2));
768
769

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