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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


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

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

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