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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 124 - (show annotations)
Tue Jul 10 17:08:19 2007 UTC (5 years, 10 months ago) by abate
File size: 24902 byte(s)
[r2002-11-13 23:21:38 by cvscast] Empty log message

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

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