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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 239 - (show annotations)
Tue Jul 10 17:18:10 2007 UTC (5 years, 10 months ago) by abate
File size: 27887 byte(s)
[r2003-03-14 16:29:56 by cvscast] Empty log message

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

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