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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 130 - (hide annotations)
Tue Jul 10 17:09:02 2007 UTC (5 years, 10 months ago) by abate
File size: 25230 byte(s)
[r2002-11-16 11:53:47 by cvscast] Empty log message

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

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