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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 188 - (hide annotations)
Tue Jul 10 17:13:41 2007 UTC (5 years, 10 months ago) by abate
File size: 27833 byte(s)
[r2002-12-20 23:15:22 by cvscast] Empty log message

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

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