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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 172 - (show annotations)
Tue Jul 10 17:12:31 2007 UTC (5 years, 10 months ago) by abate
File size: 27699 byte(s)
[r2002-12-05 15:47:05 by cvscast] Empty log message

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

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