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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 225 - (show annotations)
Tue Jul 10 17:16:34 2007 UTC (5 years, 10 months ago) by abate
File size: 27671 byte(s)
[r2003-03-08 15:10:01 by cvscast] Empty log message

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

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