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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 243 - (hide annotations)
Tue Jul 10 17:18:44 2007 UTC (5 years, 10 months ago) by abate
File size: 28979 byte(s)
[r2003-03-15 10:59:53 by cvscast] map pour les chars et les atoms

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

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