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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 274 - (hide annotations)
Tue Jul 10 17:21:27 2007 UTC (5 years, 10 months ago) by abate
File size: 29847 byte(s)
[r2003-03-22 23:21:32 by cvscast] Empty log message

Original author: cvscast
Date: 2003-03-22 23:21:32+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 249 let v= mk_loc !re_loc (Capture v) in
120     propagate (fun p -> mk_loc !re_loc (And (vars p,v))) x
121 abate 5
122 abate 249 let dummy_pat = mknoloc (PatVar "DUMMY")
123 abate 172 let cup r1 r2 =
124     if r1 == dummy_pat then r2 else
125     if r2 == dummy_pat then r1 else
126 abate 249 mk_loc !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 abate 249 mk_loc !re_loc (Prod (p, guard_compile fin rest))
147 abate 172 | 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 249 let v = mk_loc !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 249 mk_loc !re_loc
229     (And (t, (mk_loc !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 249 mk_loc !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 263 | Ttree (e,b) ->
516     let b = b @ [ (mknoloc (Internal Types.any)), mknoloc MatchFail ] in
517     let (fv1,e) = expr loc glb e
518     and (fv2,b) = branches loc glb b in
519     (Fv.cup fv1 fv2, Typed.Ttree (e, b))
520     | MatchFail -> (Fv.empty, Typed.MatchFail)
521 abate 64 | Try (e,b) ->
522 abate 122 let (fv1,e) = expr loc glb e
523     and (fv2,b) = branches loc glb b in
524 abate 225 (Fv.cup fv1 fv2, Typed.Try (e, b))
525 abate 5 in
526 abate 6 fv,
527     { Typed.exp_loc = loc;
528 abate 5 Typed.exp_typ = Types.empty;
529     Typed.exp_descr = td;
530     }
531    
532 abate 122 and branches loc glb b =
533 abate 6 let fv = ref Fv.empty in
534 abate 19 let accept = ref Types.empty in
535 abate 6 let b = List.map
536     (fun (p,e) ->
537 abate 122 let (fv2,e) = expr loc glb e in
538 abate 107 let p = pat glb p in
539 abate 225 let fv2 = Fv.diff fv2 (Patterns.fv p) in
540     fv := Fv.cup !fv fv2;
541 abate 19 accept := Types.cup !accept (Types.descr (Patterns.accept p));
542 abate 6 { Typed.br_used = false;
543 abate 19 Typed.br_pat = p;
544 abate 6 Typed.br_body = e }
545     ) b in
546 abate 19 (!fv,
547     {
548     Typed.br_typ = Types.empty;
549     Typed.br_branches = b;
550 abate 45 Typed.br_accept = !accept;
551     Typed.br_compiled = None;
552 abate 19 }
553     )
554 abate 5
555 abate 122 let expr = expr noloc
556    
557 abate 107 let let_decl glb p e =
558     let (_,e) = expr glb e in
559     { Typed.let_pat = pat glb p;
560 abate 66 Typed.let_body = e;
561     Typed.let_compiled = None }
562    
563     (* III. Type-checks *)
564    
565 abate 242 let int_cup_record = Types.cup Types.Int.any Types.Record.any
566    
567    
568 abate 66 type env = Types.descr Env.t
569 abate 6
570 abate 263 let match_fail = ref Types.empty
571    
572 abate 6 open Typed
573    
574 abate 66 let warning loc msg =
575 abate 130 Format.fprintf !Location.warning_ppf "Warning %a:@\n%a%s@\n"
576     Location.print_loc loc
577     Location.html_hilight loc
578     msg
579 abate 17
580     let check loc t s msg =
581     if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
582    
583 abate 19 let rec type_check env e constr precise =
584 abate 31 (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
585 abate 37 Types.Print.print_descr constr precise;
586     *)
587 abate 19 let d = type_check' e.exp_loc env e.exp_descr constr precise in
588 abate 6 e.exp_typ <- Types.cup e.exp_typ d;
589     d
590    
591 abate 19 and type_check' loc env e constr precise = match e with
592 abate 54 | Forget (e,t) ->
593     let t = Types.descr t in
594     ignore (type_check env e t false);
595     t
596 abate 19 | Abstraction a ->
597     let t =
598     try Types.Arrow.check_strenghten a.fun_typ constr
599     with Not_found ->
600     raise_loc loc
601     (ShouldHave
602     (constr, "but the interface of the abstraction is not compatible"))
603     in
604     let env = match a.fun_name with
605     | None -> env
606     | Some f -> Env.add f a.fun_typ env in
607     List.iter
608     (fun (t1,t2) ->
609 abate 65 ignore (type_check_branches loc env t1 a.fun_body t2 false)
610 abate 19 ) a.fun_iface;
611     t
612 abate 64
613 abate 19 | Match (e,b) ->
614     let t = type_check env e b.br_accept true in
615 abate 65 type_check_branches loc env t b constr precise
616 abate 30
617 abate 64 | Try (e,b) ->
618     let te = type_check env e constr precise in
619 abate 65 let tb = type_check_branches loc env Types.any b constr precise in
620 abate 64 Types.cup te tb
621    
622 abate 110 | Pair (e1,e2) ->
623     type_check_pair loc env e1 e2 constr precise
624     | Xml (e1,e2) ->
625     type_check_pair ~kind:`XML loc env e1 e2 constr precise
626 abate 159
627 abate 29 | RecordLitt r ->
628 abate 243 (* try to get rid of precise = true for values of fields *)
629 abate 242 if not (Types.Record.has_record constr) then
630 abate 29 raise_loc loc (ShouldHave (constr,"but it is a record."));
631     let (rconstr,res) =
632 abate 242 List.fold_left
633 abate 29 (fun (rconstr,res) (l,e) ->
634 abate 242 (* could compute (split l e) once... *)
635     let pi = Types.Record.project_opt rconstr l in
636     if Types.is_empty pi then
637 abate 29 raise_loc loc
638     (ShouldHave (constr,(Printf.sprintf
639     "Field %s is not allowed here."
640 abate 233 (LabelPool.value l)
641 abate 29 )
642     ));
643     let t = type_check env e pi true in
644 abate 242 let rconstr = Types.Record.condition rconstr l t in
645     let res = if precise then (l,Types.cons t) :: res else res in
646 abate 29 (rconstr,res)
647 abate 242 ) (constr, []) (LabelMap.get r)
648 abate 29 in
649 abate 242 if not (Types.Record.has_empty_record rconstr) then
650     raise_loc loc
651     (ShouldHave (constr,"More field should be present"));
652     if precise then
653     Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res)
654     else constr
655 abate 31 | Map (e,b) ->
656     let t = type_check env e (Sequence.star b.br_accept) true in
657    
658     let constr' = Sequence.approx (Types.cap Sequence.any constr) in
659     let exact = Types.subtype (Sequence.star constr') constr in
660 abate 54 (* Note:
661     - could be more precise by integrating the decomposition
662     of constr inside Sequence.map.
663     *)
664     let res =
665     Sequence.map
666     (fun t ->
667 abate 65 type_check_branches loc env t b constr' (precise || (not exact)))
668 abate 54 t in
669     if not exact then check loc res constr "";
670     if precise then res else constr
671 abate 31 | Op ("@", [e1;e2]) ->
672     let constr' = Sequence.star
673     (Sequence.approx (Types.cap Sequence.any constr)) in
674     let exact = Types.subtype constr' constr in
675     if exact then
676     let t1 = type_check env e1 constr' precise
677     and t2 = type_check env e2 constr' precise in
678     if precise then Sequence.concat t1 t2 else constr
679     else
680     (* Note:
681     the knownledge of t1 may makes it useless to
682     check t2 with 'precise' ... *)
683     let t1 = type_check env e1 constr' true
684     and t2 = type_check env e2 constr' true in
685     let res = Sequence.concat t1 t2 in
686     check loc res constr "";
687     if precise then res else constr
688 abate 86 | Apply (e1,e2) ->
689 abate 110 (*
690 abate 86 let constr' = Sequence.star
691     (Sequence.approx (Types.cap Sequence.any constr)) in
692     let t1 = type_check env e1 (Types.cup Types.Arrow.any constr') true in
693     let t1_fun = Types.Arrow.get t1 in
694    
695     let has_fun = not (Types.Arrow.is_empty t1_fun)
696     and has_seq = not (Types.subtype t1 Types.Arrow.any) in
697    
698     let constr' =
699     Types.cap
700     (if has_fun then Types.Arrow.domain t1_fun else Types.any)
701     (if has_seq then constr' else Types.any)
702     in
703     let need_arg = has_fun && Types.Arrow.need_arg t1_fun in
704     let precise = need_arg || has_seq in
705     let t2 = type_check env e2 constr' precise in
706     let res = Types.cup
707     (if has_fun then
708     if need_arg then Types.Arrow.apply t1_fun t2
709     else Types.Arrow.apply_noarg t1_fun
710     else Types.empty)
711     (if has_seq then Sequence.concat t1 t2
712     else Types.empty)
713     in
714     check loc res constr "";
715     res
716 abate 110 *)
717 abate 86 let t1 = type_check env e1 Types.Arrow.any true in
718     let t1 = Types.Arrow.get t1 in
719     let dom = Types.Arrow.domain t1 in
720 abate 110 let res =
721     if Types.Arrow.need_arg t1 then
722     let t2 = type_check env e2 dom true in
723     Types.Arrow.apply t1 t2
724     else
725     (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
726     in
727     check loc res constr "";
728     res
729 abate 32 | Op ("flatten", [e]) ->
730     let constr' = Sequence.star
731     (Sequence.approx (Types.cap Sequence.any constr)) in
732     let sconstr' = Sequence.star constr' in
733     let exact = Types.subtype constr' constr in
734     if exact then
735     let t = type_check env e sconstr' precise in
736     if precise then Sequence.flatten t else constr
737     else
738     let t = type_check env e sconstr' true in
739     let res = Sequence.flatten t in
740     check loc res constr "";
741     if precise then res else constr
742 abate 19 | _ ->
743     let t : Types.descr = compute_type' loc env e in
744     check loc t constr "";
745     t
746    
747 abate 110 and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise =
748     let rects = Types.Product.get ~kind constr in
749     if Types.Product.is_empty rects then
750     (match kind with
751     | `Normal -> raise_loc loc (ShouldHave (constr,"but it is a pair."))
752     | `XML -> raise_loc loc (ShouldHave (constr,"but it is an XML element.")));
753     let pi1 = Types.Product.pi1 rects in
754    
755     let t1 = type_check env e1 (Types.Product.pi1 rects)
756     (precise || (Types.Product.need_second rects))in
757     let rects = Types.Product.restrict_1 rects t1 in
758     let t2 = type_check env e2 (Types.Product.pi2 rects) precise in
759     if precise then
760     match kind with
761     | `Normal -> Types.times (Types.cons t1) (Types.cons t2)
762     | `XML -> Types.xml (Types.cons t1) (Types.cons t2)
763     else
764     constr
765    
766    
767 abate 19 and compute_type env e =
768     type_check env e Types.any true
769    
770 abate 6 and compute_type' loc env = function
771 abate 36 | Var s ->
772     (try Env.find s env
773 abate 225 with Not_found -> raise_loc loc (UnboundId (Id.value s))
774 abate 36 )
775 abate 6 | Cst c -> Types.constant c
776 abate 26 | Dot (e,l) ->
777     let t = type_check env e Types.Record.any true in
778     (try (Types.Record.project t l)
779     with Not_found -> raise_loc loc (WrongLabel(t,l)))
780 abate 240 | RemoveField (e,l) ->
781     let t = type_check env e Types.Record.any true in
782     Types.Record.remove_field t l
783 abate 16 | Op (op, el) ->
784     let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in
785     type_op loc op args
786 abate 263 | Ttree (e,b) ->
787     let t = type_check env e Sequence.any true in
788     let r =
789     Sequence.map_tree
790     (fun t ->
791     let res = type_check_branches loc env t b Sequence.any true in
792     let resid = !match_fail in
793     match_fail := Types.empty;
794     (res,resid)
795     ) t
796     in
797     r
798 abate 30
799     (* We keep these cases here to allow comparison and benchmarking ...
800     Just comment the corresponding cases in type_check' to
801     activate these ones.
802     *)
803 abate 263 | Map (e,b) ->
804     let t = compute_type env e in
805     Sequence.map (fun t -> type_check_branches loc env t b Types.any true) t
806 abate 30 | Pair (e1,e2) ->
807     let t1 = compute_type env e1
808     and t2 = compute_type env e2 in
809     Types.times (Types.cons t1) (Types.cons t2)
810     | RecordLitt r ->
811 abate 233 let r = LabelMap.map (fun e -> Types.cons (compute_type env e)) r in
812 abate 159 Types.record' (false,r)
813 abate 19 | _ -> assert false
814 abate 6
815 abate 65 and type_check_branches loc env targ brs constr precise =
816 abate 6 if Types.is_empty targ then Types.empty
817 abate 9 else (
818     brs.br_typ <- Types.cup brs.br_typ targ;
819 abate 65 branches_aux loc env targ
820 abate 19 (if precise then Types.empty else constr)
821     constr precise brs.br_branches
822 abate 9 )
823 abate 6
824 abate 65 and branches_aux loc env targ tres constr precise = function
825     | [] -> raise_loc loc (NonExhaustive targ)
826 abate 263 | { br_body = { exp_descr = MatchFail } } :: _ ->
827     match_fail := Types.cup !match_fail targ;
828     tres
829 abate 6 | b :: rem ->
830     let p = b.br_pat in
831     let acc = Types.descr (Patterns.accept p) in
832    
833     let targ' = Types.cap targ acc in
834     if Types.is_empty targ'
835 abate 65 then branches_aux loc env targ tres constr precise rem
836 abate 6 else
837     ( b.br_used <- true;
838     let res = Patterns.filter targ' p in
839     let env' = List.fold_left
840     (fun env (x,t) -> Env.add x (Types.descr t) env)
841     env res in
842 abate 19 let t = type_check env' b.br_body constr precise in
843     let tres = if precise then Types.cup t tres else tres in
844 abate 9 let targ'' = Types.diff targ acc in
845     if (Types.non_empty targ'') then
846 abate 65 branches_aux loc env targ'' tres constr precise rem
847 abate 9 else
848     tres
849 abate 6 )
850 abate 16
851 abate 66 and type_let_decl env l =
852     let acc = Types.descr (Patterns.accept l.let_pat) in
853     let t = type_check env l.let_body acc true in
854     let res = Patterns.filter t l.let_pat in
855     List.map (fun (x,t) -> (x, Types.descr t)) res
856    
857     and type_rec_funs env l =
858     let types =
859     List.fold_left
860     (fun accu -> function {let_body={exp_descr=Abstraction a}} as l ->
861     let t = a.fun_typ in
862     let acc = Types.descr (Patterns.accept l.let_pat) in
863     if not (Types.subtype t acc) then
864     raise_loc l.let_body.exp_loc (NonExhaustive (Types.diff t acc));
865     let res = Patterns.filter t l.let_pat in
866     List.fold_left (fun accu (x,t) -> (x, Types.descr t)::accu) accu res
867     | _ -> assert false) [] l
868     in
869     let env' = List.fold_left (fun env (x,t) -> Env.add x t env) env types in
870     List.iter
871     (function { let_body = { exp_descr = Abstraction a } } as l ->
872     ignore (type_check env' l.let_body Types.any false)
873     | _ -> assert false) l;
874     types
875    
876    
877 abate 16 and type_op loc op args =
878     match (op,args) with
879 abate 51 | "+", [loc1,t1; loc2,t2] ->
880 abate 242 check loc1 t1 int_cup_record
881     "The first argument of + must be an integer or a record";
882     let int = Types.Int.get t1 in
883     let int = if Intervals.is_empty int then None else Some int in
884     let r = if Types.Record.has_record t1 then Some t1 else None in
885     (match (int,r) with
886     | Some t1, None ->
887     if not (Types.Int.is_int t2) then
888     raise_loc loc2
889     (Constraint
890     (t2,Types.Int.any,
891     "The second argument of + must be an integer"));
892     Types.Int.put
893     (Intervals.add t1 (Types.Int.get t2));
894     | None, Some r1 ->
895     check loc2 t2 Types.Record.any
896     "The second argument of + must be a record";
897     Types.Record.merge r1 t2
898     | None, None ->
899     Types.empty
900     | Some t1, Some r1 ->
901     check loc2 t2 int_cup_record
902     "The second argument of + must be an integer or a record";
903     Types.cup
904     (Types.Int.put (Intervals.add t1 (Types.Int.get t2)))
905     (Types.Record.merge r1 t2)
906     )
907 abate 51 | "-", [loc1,t1; loc2,t2] ->
908     type_int_binop Intervals.sub loc1 t1 loc2 t2
909 abate 210 | ("*" | "/" | "mod"), [loc1,t1; loc2,t2] ->
910 abate 16 type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
911 abate 51 | "@", [loc1,t1; loc2,t2] ->
912 abate 17 check loc1 t1 Sequence.any
913     "The first argument of @ must be a sequence";
914     Sequence.concat t1 t2
915 abate 51 | "flatten", [loc1,t1] ->
916 abate 17 check loc1 t1 Sequence.seqseq
917     "The argument of flatten must be a sequence of sequences";
918     Sequence.flatten t1
919 abate 58 | "load_xml", [loc1,t1] ->
920     check loc1 t1 Sequence.string
921     "The argument of load_xml must be a string (filename)";
922     Types.any
923 abate 259 | "load_file", [loc1,t1] ->
924     check loc1 t1 Sequence.string
925     "The argument of load_file must be a string (filename)";
926     Sequence.string
927 abate 188 | "load_html", [loc1,t1] ->
928     check loc1 t1 Sequence.string
929     "The argument of load_html must be a string (filename)";
930     Types.any
931 abate 64 | "raise", [loc1,t1] ->
932     Types.empty
933 abate 76 | "print_xml", [loc1,t1] ->
934     Sequence.string
935 abate 124 | "print", [loc1,t1] ->
936     check loc1 t1 Sequence.string
937 abate 126 "The argument of print must be a string";
938     Sequence.nil_type
939     | "dump_to_file", [loc1,t1; loc2,t2] ->
940     check loc1 t1 Sequence.string
941     "The argument of dump_to_file must be a string (filename)";
942     check loc2 t2 Sequence.string
943     "The argument of dump_to_file must be a string (value to dump)";
944     Sequence.nil_type
945 abate 66 | "int_of", [loc1,t1] ->
946     check loc1 t1 Sequence.string
947 abate 126 "The argument of int_of must be a string";
948 abate 66 if not (Types.subtype t1 Builtin.intstr) then
949     warning loc "This application of int_of may fail";
950     Types.interval Intervals.any
951 abate 133 | "string_of", [loc1,t1] ->
952     Sequence.string
953 abate 239 | "=", [loc1,t1; loc2,t2] ->
954 abate 237 (* could prevent comparision of functional value here... *)
955     (* could also handle the case when t1 and t2 are the same
956     singleton type *)
957     if Types.is_empty (Types.cap t1 t2) then
958     Builtin.false_type
959     else
960     Builtin.bool
961 abate 239 | ("<=" | "<" | ">" | ">=" ), [loc1,t1; loc2,t2] ->
962     (* could prevent comparision of functional value here... *)
963     Builtin.bool
964 abate 16 | _ -> assert false
965    
966     and type_int_binop f loc1 t1 loc2 t2 =
967     if not (Types.Int.is_int t1) then
968     raise_loc loc1
969     (Constraint
970     (t1,Types.Int.any,
971     "The first argument must be an integer"));
972     if not (Types.Int.is_int t2) then
973     raise_loc loc2
974     (Constraint
975 abate 37 (t2,Types.Int.any,
976 abate 16 "The second argument must be an integer"));
977     Types.Int.put
978     (f (Types.Int.get t1) (Types.Int.get t2));
979    
980    

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