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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 316 - (hide annotations)
Tue Jul 10 17:24:41 2007 UTC (5 years, 10 months ago) by abate
File size: 33529 byte(s)
[r2003-05-10 18:31:04 by cvscast] Special nodes to locate expressions

Original author: cvscast
Date: 2003-05-10 18:31:04+00:00
1 abate 237 (* TODO:
2 abate 276 - rewrite type-checking of operators to propagate constraint
3 abate 278 - optimize computation of pattern free variables
4     - check whether it is worth using recursive hash-consing internally
5 abate 276 *)
6 abate 237
7 abate 276
8 abate 5 (* I. Transform the abstract syntax of types and patterns into
9     the internal form *)
10    
11     open Location
12     open Ast
13 abate 225 open Ident
14 abate 5
15 abate 140 module S = struct type t = string let compare = compare end
16 abate 277 module StringSet = Set.Make(S)
17 abate 225 module TypeEnv = Map.Make(S)
18 abate 278 module Env = Map.Make(Id)
19 abate 140
20 abate 277
21 abate 9 exception NonExhaustive of Types.descr
22     exception Constraint of Types.descr * Types.descr * string
23 abate 19 exception ShouldHave of Types.descr * string
24 abate 233 exception WrongLabel of Types.descr * label
25 abate 36 exception UnboundId of string
26 abate 5
27 abate 9 let raise_loc loc exn = raise (Location (loc,exn))
28    
29 abate 5
30 abate 278 (* Eliminate Recursion, propagate Sequence Capture Variables *)
31 abate 5
32 abate 278 let rec seq_vars accu = function
33     | Epsilon | Elem _ -> accu
34     | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
35     | Star r | WeakStar r -> seq_vars accu r
36     | SeqCapture (v,r) -> seq_vars (IdSet.add v accu) r
37 abate 71
38 abate 278 type derecurs_slot = {
39     ploc : Location.loc;
40     pid : int;
41     mutable ploop : bool;
42     mutable pdescr : derecurs option
43     } and derecurs =
44     | PAlias of derecurs_slot
45     | PType of Types.descr
46     | POr of derecurs * derecurs
47     | PAnd of derecurs * derecurs
48     | PDiff of derecurs * derecurs
49     | PTimes of derecurs * derecurs
50     | PXml of derecurs * derecurs
51     | PArrow of derecurs * derecurs
52     | POptional of derecurs
53     | PRecord of bool * derecurs label_map
54     | PCapture of id
55     | PConstant of id * Types.const
56     | PRegexp of derecurs_regexp * derecurs
57     and derecurs_regexp =
58     | PEpsilon
59     | PElem of derecurs
60     | PSeq of derecurs_regexp * derecurs_regexp
61     | PAlt of derecurs_regexp * derecurs_regexp
62     | PStar of derecurs_regexp
63     | PWeakStar of derecurs_regexp
64 abate 71
65 abate 278 let rec hash_derecurs = function
66     | PAlias s -> s.pid
67     | PType t -> 1 + 17 * (Types.hash_descr t)
68     | POr (p1,p2) -> 2 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
69     | PAnd (p1,p2) -> 3 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
70     | PDiff (p1,p2) -> 4 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
71     | PTimes (p1,p2) -> 5 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
72     | PXml (p1,p2) -> 6 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
73     | PArrow (p1,p2) -> 7 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
74     | POptional p -> 8 + 17 * (hash_derecurs p)
75     | PRecord (o,r) -> (if o then 9 else 10) + 17 * (LabelMap.hash hash_derecurs r)
76     | PCapture x -> 11 + 17 * (Id.hash x)
77     | PConstant (x,c) -> 12 + 17 * (Id.hash x) + 257 * (Types.hash_const c)
78     | PRegexp (p,q) -> 13 + 17 * (hash_derecurs_regexp p) + 257 * (hash_derecurs q)
79     and hash_derecurs_regexp = function
80     | PEpsilon -> 1
81     | PElem p -> 2 + 17 * (hash_derecurs p)
82     | PSeq (p1,p2) -> 3 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2)
83     | PAlt (p1,p2) -> 4 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2)
84     | PStar p -> 5 + 17 * (hash_derecurs_regexp p)
85     | PWeakStar p -> 6 + 17 * (hash_derecurs_regexp p)
86 abate 107
87 abate 278 let rec equal_derecurs p1 p2 = (p1 == p2) || match p1,p2 with
88     | PAlias s1, PAlias s2 -> s1 == s2
89     | PType t1, PType t2 -> Types.equal_descr t1 t2
90     | POr (p1,q1), POr (p2,q2)
91     | PAnd (p1,q1), PAnd (p2,q2)
92     | PDiff (p1,q1), PDiff (p2,q2)
93     | PTimes (p1,q1), PTimes (p2,q2)
94     | PXml (p1,q1), PXml (p2,q2)
95     | PArrow (p1,q1), PArrow (p2,q2) -> (equal_derecurs p1 p2) && (equal_derecurs q1 q2)
96     | POptional p1, POptional p2 -> equal_derecurs p1 p2
97     | PRecord (o1,r1), PRecord (o2,r2) -> (o1 == o2) && (LabelMap.equal equal_derecurs r1 r2)
98     | PCapture x1, PCapture x2 -> Id.equal x1 x2
99     | PConstant (x1,c1), PConstant (x2,c2) -> (Id.equal x1 x2) && (Types.equal_const c1 c2)
100     | PRegexp (p1,q1), PRegexp (p2,q2) -> (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2)
101     | _ -> false
102     and equal_derecurs_regexp r1 r2 = match r1,r2 with
103     | PEpsilon, PEpsilon -> true
104     | PElem p1, PElem p2 -> equal_derecurs p1 p2
105     | PSeq (p1,q1), PSeq (p2,q2)
106     | PAlt (p1,q1), PAlt (p2,q2) -> (equal_derecurs_regexp p1 p2) && (equal_derecurs_regexp q1 q2)
107     | PStar p1, PStar p2
108     | PWeakStar p1, PWeakStar p2 -> equal_derecurs_regexp p1 p2
109     | _ -> false
110 abate 5
111 abate 278 module DerecursTable = Hashtbl.Make(
112     struct
113     type t = derecurs
114     let hash = hash_derecurs
115     let equal = equal_derecurs
116     end
117     )
118 abate 5
119 abate 278 module RE = Hashtbl.Make(
120     struct
121     type t = derecurs_regexp * derecurs
122     let hash (p,q) = (hash_derecurs_regexp p) + 17 * (hash_derecurs q)
123     let equal (p1,q1) (p2,q2) = (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2)
124     end
125     )
126 abate 71
127 abate 278
128     let counter = State.ref "Typer.counter - derecurs" 0
129     let mk_slot loc =
130     incr counter;
131     { ploop = false; ploc = loc; pid = !counter; pdescr = None }
132    
133     let rec derecurs env p = match p.descr with
134     | PatVar v ->
135     (try PAlias (TypeEnv.find v env)
136     with Not_found -> raise_loc_generic p.loc ("Undefined type/pattern " ^ v))
137     | Recurs (p,b) -> derecurs (derecurs_def env b) p
138     | Internal t -> PType t
139     | Or (p1,p2) -> POr (derecurs env p1, derecurs env p2)
140     | And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2)
141     | Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2)
142     | Prod (p1,p2) -> PTimes (derecurs env p1, derecurs env p2)
143     | XmlT (p1,p2) -> PXml (derecurs env p1, derecurs env p2)
144     | Arrow (p1,p2) -> PArrow (derecurs env p1, derecurs env p2)
145     | Optional p -> POptional (derecurs env p)
146     | Record (o,r) -> PRecord (o, LabelMap.map (derecurs env) r)
147     | Capture x -> PCapture x
148     | Constant (x,c) -> PConstant (x,c)
149     | Regexp (r,q) ->
150     let constant_nil t v = PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in
151     let vars = seq_vars IdSet.empty r in
152     let q = IdSet.fold constant_nil (derecurs env q) vars in
153     let r = derecurs_regexp (fun p -> p) env r in
154     PRegexp (r, q)
155     and derecurs_regexp vars env = function
156     | Epsilon -> PEpsilon
157     | Elem p -> PElem (vars (derecurs env p))
158     | Seq (p1,p2) -> PSeq (derecurs_regexp vars env p1, derecurs_regexp vars env p2)
159     | Alt (p1,p2) -> PAlt (derecurs_regexp vars env p1, derecurs_regexp vars env p2)
160     | Star p -> PStar (derecurs_regexp vars env p)
161     | WeakStar p -> PStar (derecurs_regexp vars env p)
162     | SeqCapture (x,p) -> derecurs_regexp (fun p -> PAnd (vars p, PCapture x)) env p
163 abate 71
164 abate 140
165 abate 278 and derecurs_def env b =
166     let b = List.map (fun (v,p) -> (v,p,mk_slot p.loc)) b in
167     let env = List.fold_left (fun env (v,p,s) -> TypeEnv.add v s env) env b in
168     List.iter (fun (v,p,s) -> s.pdescr <- Some (derecurs env p)) b;
169     env
170 abate 5
171 abate 278 (* Stratification and recursive hash-consing *)
172 abate 5
173 abate 277 type descr =
174     | IType of Types.descr
175     | IOr of descr * descr
176     | IAnd of descr * descr
177     | IDiff of descr * descr
178     | ITimes of slot * slot
179     | IXml of slot * slot
180     | IArrow of slot * slot
181 abate 278 | IOptional of descr
182 abate 277 | IRecord of bool * slot label_map
183     | ICapture of id
184     | IConstant of id * Types.const
185     and slot = {
186     mutable fv : fv option;
187     mutable hash : int option;
188     mutable rank1: int; mutable rank2: int;
189     mutable gen1 : int; mutable gen2: int;
190 abate 278 mutable d : descr option
191 abate 277 }
192    
193     let descr s =
194     match s.d with
195     | Some d -> d
196     | None -> assert false
197    
198     let gen = ref 0
199     let rank = ref 0
200    
201     let rec hash_descr = function
202     | IType x -> Types.hash_descr x
203     | IOr (d1,d2) -> 1 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
204     | IAnd (d1,d2) -> 2 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
205     | IDiff (d1,d2) -> 3 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
206     | IOptional d -> 4 + 17 * (hash_descr d)
207     | ITimes (s1,s2) -> 5 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
208     | IXml (s1,s2) -> 6 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
209     | IArrow (s1,s2) -> 7 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
210     | IRecord (o,r) -> (if o then 8 else 9) + 17 * (LabelMap.hash hash_slot r)
211     | ICapture x -> 10 + 17 * (Id.hash x)
212     | IConstant (x,y) -> 11 + 17 * (Id.hash x) + 257 * (Types.hash_const y)
213     and hash_slot s =
214     if s.gen1 = !gen then 13 * s.rank1
215     else (
216     incr rank;
217     s.rank1 <- !rank; s.gen1 <- !gen;
218     hash_descr (descr s)
219     )
220    
221     let rec equal_descr d1 d2 =
222     match (d1,d2) with
223     | IType x1, IType x2 -> Types.equal_descr x1 x2
224     | IOr (x1,y1), IOr (x2,y2)
225     | IAnd (x1,y1), IAnd (x2,y2)
226     | IDiff (x1,y1), IDiff (x2,y2) -> (equal_descr x1 x2) && (equal_descr y1 y2)
227     | IOptional x1, IOptional x2 -> equal_descr x1 x2
228     | ITimes (x1,y1), ITimes (x2,y2)
229     | IXml (x1,y1), IXml (x2,y2)
230     | IArrow (x1,y1), IArrow (x2,y2) -> (equal_slot x1 x2) && (equal_slot y1 y2)
231     | IRecord (o1,r1), IRecord (o2,r2) -> (o1 = o2) && (LabelMap.equal equal_slot r1 r2)
232     | ICapture x1, ICapture x2 -> Id.equal x1 x2
233     | IConstant (x1,y1), IConstant (x2,y2) -> (Id.equal x1 x2) && (Types.equal_const y1 y2)
234     | _ -> false
235     and equal_slot s1 s2 =
236     ((s1.gen1 = !gen) && (s2.gen2 = !gen) && (s1.rank1 = s2.rank2))
237     ||
238     ((s1.gen1 <> !gen) && (s2.gen2 <> !gen) && (
239     incr rank;
240     s1.rank1 <- !rank; s1.gen1 <- !gen;
241     s2.rank2 <- !rank; s2.gen2 <- !gen;
242     equal_descr (descr s1) (descr s2)
243     ))
244    
245     module Arg = struct
246     type t = slot
247    
248     let hash s =
249     match s.hash with
250     | Some h -> h
251     | None ->
252     incr gen; rank := 0;
253     let h = hash_slot s in
254     s.hash <- Some h;
255     h
256    
257 abate 278 let equal s1 s2 =
258     (s1 == s2) ||
259     (incr gen; rank := 0;
260     let e = equal_slot s1 s2 in
261     (* if e then Printf.eprintf "Equal\n"; *)
262     e)
263 abate 277 end
264     module SlotTable = Hashtbl.Make(Arg)
265    
266     let rec fv_slot s =
267     match s.fv with
268     | Some x -> x
269     | None ->
270     if s.gen1 = !gen then IdSet.empty
271     else (s.gen1 <- !gen; fv_descr (descr s))
272     and fv_descr = function
273 abate 278 | IType _ -> IdSet.empty
274 abate 277 | IOr (d1,d2)
275     | IAnd (d1,d2)
276     | IDiff (d1,d2) -> IdSet.cup (fv_descr d1) (fv_descr d2)
277     | IOptional d -> fv_descr d
278     | ITimes (s1,s2)
279     | IXml (s1,s2)
280     | IArrow (s1,s2) -> IdSet.cup (fv_slot s1) (fv_slot s2)
281     | IRecord (o,r) -> List.fold_left IdSet.cup IdSet.empty (LabelMap.map_to_list fv_slot r)
282     | ICapture x | IConstant (x,_) -> IdSet.singleton x
283 abate 278
284 abate 277
285     let compute_fv s =
286     match s.fv with
287     | Some x -> ()
288     | None ->
289     incr gen;
290     let x = fv_slot s in
291     s.fv <- Some x
292    
293 abate 278
294     let todo_fv = ref []
295 abate 277
296     let mk () =
297     let s =
298     { d = None;
299     fv = None;
300     hash = None;
301     rank1 = 0; rank2 = 0;
302     gen1 = 0; gen2 = 0 } in
303 abate 278 todo_fv := s :: !todo_fv;
304 abate 277 s
305 abate 278
306     let flush_fv () =
307     List.iter compute_fv !todo_fv;
308     todo_fv := []
309 abate 277
310 abate 278 let compile_slot_hash = DerecursTable.create 67
311     let compile_hash = DerecursTable.create 67
312    
313 abate 277 let defs = ref []
314 abate 278
315     let rec compile p =
316     try DerecursTable.find compile_hash p
317 abate 277 with Not_found ->
318 abate 278 let c = real_compile p in
319     DerecursTable.replace compile_hash p c;
320     c
321     and real_compile = function
322     | PAlias v ->
323     if v.ploop then
324     raise_loc_generic v.ploc ("Unguarded recursion on type/pattern");
325     v.ploop <- true;
326     let r = match v.pdescr with Some x -> compile x | _ -> assert false in
327     v.ploop <- false;
328     r
329     | PType t -> IType t
330     | POr (t1,t2) -> IOr (compile t1, compile t2)
331     | PAnd (t1,t2) -> IAnd (compile t1, compile t2)
332     | PDiff (t1,t2) -> IDiff (compile t1, compile t2)
333     | PTimes (t1,t2) -> ITimes (compile_slot t1, compile_slot t2)
334     | PXml (t1,t2) -> IXml (compile_slot t1, compile_slot t2)
335     | PArrow (t1,t2) -> IArrow (compile_slot t1, compile_slot t2)
336     | POptional t -> IOptional (compile t)
337     | PRecord (o,r) -> IRecord (o, LabelMap.map compile_slot r)
338     | PConstant (x,v) -> IConstant (x,v)
339     | PCapture x -> ICapture x
340     | PRegexp (r,q) -> compile_regexp r q
341     and compile_regexp r q =
342     let memo = RE.create 17 in
343     let rec aux accu r q =
344     if RE.mem memo (r,q) then accu
345     else (
346     RE.add memo (r,q) ();
347     match r with
348     | PEpsilon -> (match q with PRegexp (r,q) -> aux accu r q | _ -> (compile q) :: accu)
349     | PElem p -> ITimes (compile_slot p, compile_slot q) :: accu
350     | PSeq (r1,r2) -> aux accu r1 (PRegexp (r2,q))
351     | PAlt (r1,r2) -> aux (aux accu r1 q) r2 q
352     | PStar r1 -> aux (aux accu r1 (PRegexp (r,q))) PEpsilon q
353     | PWeakStar r1 -> aux (aux accu PEpsilon q) r1 (PRegexp (r,q))
354     )
355     in
356     let accu = aux [] r q in
357     match accu with
358     | [] -> assert false
359     | p::l -> List.fold_left (fun acc p -> IOr (p,acc)) p l
360     and compile_slot p =
361     try DerecursTable.find compile_slot_hash p
362     with Not_found ->
363 abate 277 let s = mk () in
364 abate 278 defs := (s,p) :: !defs;
365     DerecursTable.add compile_slot_hash p s;
366 abate 277 s
367 abate 278
368 abate 277
369     let rec flush_defs () =
370     match !defs with
371     | [] -> ()
372 abate 278 | (s,p)::t -> defs := t; s.d <- Some (compile p); flush_defs ()
373 abate 277
374     let typ_nodes = SlotTable.create 67
375     let pat_nodes = SlotTable.create 67
376    
377     let rec typ = function
378     | IType t -> t
379     | IOr (s1,s2) -> Types.cup (typ s1) (typ s2)
380     | IAnd (s1,s2) -> Types.cap (typ s1) (typ s2)
381     | IDiff (s1,s2) -> Types.diff (typ s1) (typ s2)
382     | ITimes (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
383     | IXml (s1,s2) -> Types.xml (typ_node s1) (typ_node s2)
384     | IArrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
385     | IOptional s -> Types.Record.or_absent (typ s)
386     | IRecord (o,r) -> Types.record' (o, LabelMap.map typ_node r)
387     | ICapture x | IConstant (x,_) -> assert false
388    
389     and typ_node s : Types.node =
390     try SlotTable.find typ_nodes s
391     with Not_found ->
392     let x = Types.make () in
393     SlotTable.add typ_nodes s x;
394     Types.define x (typ (descr s));
395     x
396    
397     let rec pat d : Patterns.descr =
398     if IdSet.is_empty (fv_descr d)
399     then Patterns.constr (typ d)
400     else pat_aux d
401    
402    
403     and pat_aux = function
404     | IOr (s1,s2) -> Patterns.cup (pat s1) (pat s2)
405     | IAnd (s1,s2) -> Patterns.cap (pat s1) (pat s2)
406     | IDiff (s1,s2) when IdSet.is_empty (fv_descr s2) ->
407     let s2 = Types.neg (typ s2) in
408     Patterns.cap (pat s1) (Patterns.constr s2)
409     | IDiff _ ->
410     raise (Patterns.Error "Difference not allowed in patterns")
411     | ITimes (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
412     | IXml (s1,s2) -> Patterns.xml (pat_node s1) (pat_node s2)
413     | IOptional _ ->
414     raise (Patterns.Error "Optional field not allowed in record patterns")
415     | IRecord (o,r) ->
416     let pats = ref [] in
417     let aux l s =
418     if IdSet.is_empty (fv_slot s) then typ_node s
419     else
420     ( pats := Patterns.record l (pat_node s) :: !pats;
421     Types.any_node )
422     in
423     let constr = Types.record' (o,LabelMap.mapi aux r) in
424     List.fold_left Patterns.cap (Patterns.constr constr) !pats
425     (* TODO: can avoid constr when o=true, and all fields have fv *)
426     | ICapture x -> Patterns.capture x
427     | IConstant (x,c) -> Patterns.constant x c
428     | IArrow _ ->
429     raise (Patterns.Error "Arrow not allowed in patterns")
430     | IType _ -> assert false
431    
432     and pat_node s : Patterns.node =
433     try SlotTable.find pat_nodes s
434     with Not_found ->
435     let x = Patterns.make (fv_slot s) in
436     SlotTable.add pat_nodes s x;
437     Patterns.define x (pat (descr s));
438     x
439    
440     let glb = State.ref "Typer.glb_env" TypeEnv.empty
441    
442    
443     let register_global_types b =
444 abate 278 List.iter
445     (fun (v,p) ->
446     if TypeEnv.mem v !glb
447     then raise_loc_generic p.loc ("Multiple definition for type " ^ v)
448     ) b;
449     glb := derecurs_def !glb b;
450     let b = List.map (fun (v,p) -> (v,p,compile (derecurs !glb p))) b in
451 abate 277 flush_defs ();
452     flush_fv ();
453     List.iter (fun (v,p,s) ->
454     if not (IdSet.is_empty (fv_descr s)) then
455     raise_loc_generic p.loc "Capture variables are not allowed in types";
456     Types.Print.register_global v (typ s)) b
457 abate 278
458     let dump_global_types ppf =
459     TypeEnv.iter (fun v _ -> Format.fprintf ppf " %s" v) !glb
460 abate 277
461    
462     let typ p =
463 abate 278 let s = compile_slot (derecurs !glb p) in
464 abate 277 flush_defs ();
465     flush_fv ();
466     if IdSet.is_empty (fv_slot s) then typ_node s
467     else raise_loc_generic p.loc "Capture variables are not allowed in types"
468    
469     let pat p =
470 abate 278 let s = compile_slot (derecurs !glb p) in
471 abate 277 flush_defs ();
472     flush_fv ();
473     try pat_node s
474     with Patterns.Error e -> raise_loc_generic p.loc e
475     | Location (loc,exn) when loc = noloc -> raise (Location (p.loc, exn))
476 abate 5
477    
478     (* II. Build skeleton *)
479    
480 abate 225 module Fv = IdSet
481 abate 6
482 abate 314 let all_branches = ref []
483    
484 abate 122 (* IDEA: introduce a node Loc in the AST to override nolocs
485     in sub-expressions *)
486    
487 abate 316 let exp loc fv e =
488 abate 6 fv,
489     { Typed.exp_loc = loc;
490 abate 5 Typed.exp_typ = Types.empty;
491 abate 316 Typed.exp_descr = e;
492 abate 5 }
493 abate 316
494    
495     let rec expr loc = function
496     | LocatedExpr (loc,e) -> expr loc e
497     | Forget (e,t) ->
498     let (fv,e) = expr loc e and t = typ t in
499     exp loc fv (Typed.Forget (e,t))
500     | Var s ->
501     exp loc (Fv.singleton s) (Typed.Var s)
502     | Apply (e1,e2) ->
503     let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
504     exp loc (Fv.cup fv1 fv2) (Typed.Apply (e1,e2))
505     | Abstraction a ->
506     let iface = List.map (fun (t1,t2) -> (typ t1, typ t2))
507     a.fun_iface in
508     let t = List.fold_left
509     (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
510     Types.any iface in
511     let iface = List.map
512     (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
513     iface in
514     let (fv0,body) = branches a.fun_body in
515     let fv = match a.fun_name with
516     | None -> fv0
517     | Some f -> Fv.remove f fv0 in
518     let e = Typed.Abstraction
519     { Typed.fun_name = a.fun_name;
520     Typed.fun_iface = iface;
521     Typed.fun_body = body;
522     Typed.fun_typ = t;
523     Typed.fun_fv = fv
524     } in
525     exp loc fv e
526     | Cst c ->
527     exp loc Fv.empty (Typed.Cst c)
528     | Pair (e1,e2) ->
529     let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
530     exp loc (Fv.cup fv1 fv2) (Typed.Pair (e1,e2))
531     | Xml (e1,e2) ->
532     let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
533     exp loc (Fv.cup fv1 fv2) (Typed.Xml (e1,e2))
534     | Dot (e,l) ->
535     let (fv,e) = expr loc e in
536     exp loc fv (Typed.Dot (e,l))
537     | RemoveField (e,l) ->
538     let (fv,e) = expr loc e in
539     exp loc fv (Typed.RemoveField (e,l))
540     | RecordLitt r ->
541     let fv = ref Fv.empty in
542     let r = LabelMap.map
543     (fun e ->
544     let (fv2,e) = expr loc e
545     in fv := Fv.cup !fv fv2; e)
546     r in
547     exp loc !fv (Typed.RecordLitt r)
548     | Op (op,le) ->
549     let (fvs,ltes) = List.split (List.map (expr loc) le) in
550     let fv = List.fold_left Fv.cup Fv.empty fvs in
551     exp loc fv (Typed.Op (op,ltes))
552     | Match (e,b) ->
553     let (fv1,e) = expr loc e
554     and (fv2,b) = branches b in
555     exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b))
556     | Map (e,b) ->
557     let (fv1,e) = expr loc e
558     and (fv2,b) = branches b in
559     exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b))
560     | Ttree (e,b) ->
561     let b = b @ [ mknoloc (Internal Types.any), MatchFail ] in
562     let (fv1,e) = expr loc e
563     and (fv2,b) = branches b in
564     exp loc (Fv.cup fv1 fv2) (Typed.Ttree (e, b))
565     | MatchFail ->
566     exp loc (Fv.empty) Typed.MatchFail
567     | Try (e,b) ->
568     let (fv1,e) = expr loc e
569     and (fv2,b) = branches b in
570     exp loc (Fv.cup fv1 fv2) (Typed.Try (e, b))
571    
572 abate 5
573 abate 316 and branches b =
574 abate 6 let fv = ref Fv.empty in
575 abate 19 let accept = ref Types.empty in
576 abate 314 let branch (p,e) =
577 abate 316 let (fv2,e) = expr noloc e in
578     let br_loc = merge_loc p.loc e.Typed.exp_loc in
579 abate 314 let p = pat p in
580     let fv2 = Fv.diff fv2 (Patterns.fv p) in
581     fv := Fv.cup !fv fv2;
582     accept := Types.cup !accept (Types.descr (Patterns.accept p));
583     let br =
584     {
585     Typed.br_loc = br_loc;
586     Typed.br_used = br_loc = noloc;
587     Typed.br_pat = p;
588     Typed.br_body = e } in
589     all_branches := br :: !all_branches;
590     br in
591     let b = List.map branch b in
592 abate 19 (!fv,
593     {
594     Typed.br_typ = Types.empty;
595     Typed.br_branches = b;
596 abate 45 Typed.br_accept = !accept;
597     Typed.br_compiled = None;
598 abate 19 }
599     )
600 abate 5
601 abate 122 let expr = expr noloc
602    
603 abate 277 let let_decl p e =
604     let (_,e) = expr e in
605     { Typed.let_pat = pat p;
606 abate 66 Typed.let_body = e;
607     Typed.let_compiled = None }
608    
609     (* III. Type-checks *)
610    
611 abate 242 let int_cup_record = Types.cup Types.Int.any Types.Record.any
612    
613    
614 abate 66 type env = Types.descr Env.t
615 abate 6
616 abate 263 let match_fail = ref Types.empty
617    
618 abate 6 open Typed
619    
620 abate 66 let warning loc msg =
621 abate 130 Format.fprintf !Location.warning_ppf "Warning %a:@\n%a%s@\n"
622     Location.print_loc loc
623     Location.html_hilight loc
624     msg
625 abate 17
626     let check loc t s msg =
627     if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
628    
629 abate 19 let rec type_check env e constr precise =
630 abate 31 (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
631 abate 37 Types.Print.print_descr constr precise;
632     *)
633 abate 19 let d = type_check' e.exp_loc env e.exp_descr constr precise in
634 abate 6 e.exp_typ <- Types.cup e.exp_typ d;
635     d
636    
637 abate 19 and type_check' loc env e constr precise = match e with
638 abate 54 | Forget (e,t) ->
639     let t = Types.descr t in
640     ignore (type_check env e t false);
641     t
642 abate 19 | Abstraction a ->
643     let t =
644     try Types.Arrow.check_strenghten a.fun_typ constr
645     with Not_found ->
646     raise_loc loc
647     (ShouldHave
648     (constr, "but the interface of the abstraction is not compatible"))
649     in
650     let env = match a.fun_name with
651     | None -> env
652     | Some f -> Env.add f a.fun_typ env in
653     List.iter
654     (fun (t1,t2) ->
655 abate 65 ignore (type_check_branches loc env t1 a.fun_body t2 false)
656 abate 19 ) a.fun_iface;
657     t
658 abate 64
659 abate 19 | Match (e,b) ->
660     let t = type_check env e b.br_accept true in
661 abate 65 type_check_branches loc env t b constr precise
662 abate 30
663 abate 64 | Try (e,b) ->
664     let te = type_check env e constr precise in
665 abate 65 let tb = type_check_branches loc env Types.any b constr precise in
666 abate 64 Types.cup te tb
667    
668 abate 110 | Pair (e1,e2) ->
669     type_check_pair loc env e1 e2 constr precise
670     | Xml (e1,e2) ->
671     type_check_pair ~kind:`XML loc env e1 e2 constr precise
672 abate 159
673 abate 29 | RecordLitt r ->
674 abate 243 (* try to get rid of precise = true for values of fields *)
675 abate 242 if not (Types.Record.has_record constr) then
676 abate 29 raise_loc loc (ShouldHave (constr,"but it is a record."));
677     let (rconstr,res) =
678 abate 242 List.fold_left
679 abate 29 (fun (rconstr,res) (l,e) ->
680 abate 242 (* could compute (split l e) once... *)
681     let pi = Types.Record.project_opt rconstr l in
682     if Types.is_empty pi then
683 abate 29 raise_loc loc
684     (ShouldHave (constr,(Printf.sprintf
685     "Field %s is not allowed here."
686 abate 233 (LabelPool.value l)
687 abate 29 )
688     ));
689     let t = type_check env e pi true in
690 abate 242 let rconstr = Types.Record.condition rconstr l t in
691     let res = if precise then (l,Types.cons t) :: res else res in
692 abate 29 (rconstr,res)
693 abate 242 ) (constr, []) (LabelMap.get r)
694 abate 29 in
695 abate 242 if not (Types.Record.has_empty_record rconstr) then
696     raise_loc loc
697     (ShouldHave (constr,"More field should be present"));
698     if precise then
699     Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res)
700     else constr
701 abate 31 | Map (e,b) ->
702     let t = type_check env e (Sequence.star b.br_accept) true in
703    
704     let constr' = Sequence.approx (Types.cap Sequence.any constr) in
705     let exact = Types.subtype (Sequence.star constr') constr in
706 abate 54 (* Note:
707     - could be more precise by integrating the decomposition
708     of constr inside Sequence.map.
709     *)
710     let res =
711     Sequence.map
712     (fun t ->
713 abate 65 type_check_branches loc env t b constr' (precise || (not exact)))
714 abate 54 t in
715     if not exact then check loc res constr "";
716     if precise then res else constr
717 abate 31 | Op ("@", [e1;e2]) ->
718     let constr' = Sequence.star
719     (Sequence.approx (Types.cap Sequence.any constr)) in
720     let exact = Types.subtype constr' constr in
721     if exact then
722     let t1 = type_check env e1 constr' precise
723     and t2 = type_check env e2 constr' precise in
724     if precise then Sequence.concat t1 t2 else constr
725     else
726     (* Note:
727     the knownledge of t1 may makes it useless to
728     check t2 with 'precise' ... *)
729     let t1 = type_check env e1 constr' true
730     and t2 = type_check env e2 constr' true in
731     let res = Sequence.concat t1 t2 in
732     check loc res constr "";
733     if precise then res else constr
734 abate 86 | Apply (e1,e2) ->
735 abate 110 (*
736 abate 86 let constr' = Sequence.star
737     (Sequence.approx (Types.cap Sequence.any constr)) in
738     let t1 = type_check env e1 (Types.cup Types.Arrow.any constr') true in
739     let t1_fun = Types.Arrow.get t1 in
740    
741     let has_fun = not (Types.Arrow.is_empty t1_fun)
742     and has_seq = not (Types.subtype t1 Types.Arrow.any) in
743    
744     let constr' =
745     Types.cap
746     (if has_fun then Types.Arrow.domain t1_fun else Types.any)
747     (if has_seq then constr' else Types.any)
748     in
749     let need_arg = has_fun && Types.Arrow.need_arg t1_fun in
750     let precise = need_arg || has_seq in
751     let t2 = type_check env e2 constr' precise in
752     let res = Types.cup
753     (if has_fun then
754     if need_arg then Types.Arrow.apply t1_fun t2
755     else Types.Arrow.apply_noarg t1_fun
756     else Types.empty)
757     (if has_seq then Sequence.concat t1 t2
758     else Types.empty)
759     in
760     check loc res constr "";
761     res
762 abate 110 *)
763 abate 86 let t1 = type_check env e1 Types.Arrow.any true in
764     let t1 = Types.Arrow.get t1 in
765     let dom = Types.Arrow.domain t1 in
766 abate 110 let res =
767     if Types.Arrow.need_arg t1 then
768     let t2 = type_check env e2 dom true in
769     Types.Arrow.apply t1 t2
770     else
771     (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
772     in
773     check loc res constr "";
774     res
775 abate 32 | Op ("flatten", [e]) ->
776     let constr' = Sequence.star
777     (Sequence.approx (Types.cap Sequence.any constr)) in
778     let sconstr' = Sequence.star constr' in
779     let exact = Types.subtype constr' constr in
780     if exact then
781     let t = type_check env e sconstr' precise in
782     if precise then Sequence.flatten t else constr
783     else
784     let t = type_check env e sconstr' true in
785     let res = Sequence.flatten t in
786     check loc res constr "";
787     if precise then res else constr
788 abate 19 | _ ->
789     let t : Types.descr = compute_type' loc env e in
790     check loc t constr "";
791     t
792    
793 abate 110 and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise =
794     let rects = Types.Product.get ~kind constr in
795     if Types.Product.is_empty rects then
796     (match kind with
797     | `Normal -> raise_loc loc (ShouldHave (constr,"but it is a pair."))
798     | `XML -> raise_loc loc (ShouldHave (constr,"but it is an XML element.")));
799     let pi1 = Types.Product.pi1 rects in
800    
801     let t1 = type_check env e1 (Types.Product.pi1 rects)
802     (precise || (Types.Product.need_second rects))in
803     let rects = Types.Product.restrict_1 rects t1 in
804     let t2 = type_check env e2 (Types.Product.pi2 rects) precise in
805     if precise then
806     match kind with
807     | `Normal -> Types.times (Types.cons t1) (Types.cons t2)
808     | `XML -> Types.xml (Types.cons t1) (Types.cons t2)
809     else
810     constr
811    
812    
813 abate 19 and compute_type env e =
814     type_check env e Types.any true
815    
816 abate 6 and compute_type' loc env = function
817 abate 36 | Var s ->
818     (try Env.find s env
819 abate 225 with Not_found -> raise_loc loc (UnboundId (Id.value s))
820 abate 36 )
821 abate 6 | Cst c -> Types.constant c
822 abate 26 | Dot (e,l) ->
823     let t = type_check env e Types.Record.any true in
824     (try (Types.Record.project t l)
825     with Not_found -> raise_loc loc (WrongLabel(t,l)))
826 abate 240 | RemoveField (e,l) ->
827     let t = type_check env e Types.Record.any true in
828     Types.Record.remove_field t l
829 abate 16 | Op (op, el) ->
830     let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in
831     type_op loc op args
832 abate 263 | Ttree (e,b) ->
833     let t = type_check env e Sequence.any true in
834     let r =
835     Sequence.map_tree
836     (fun t ->
837     let res = type_check_branches loc env t b Sequence.any true in
838     let resid = !match_fail in
839     match_fail := Types.empty;
840     (res,resid)
841     ) t
842     in
843     r
844 abate 30
845     (* We keep these cases here to allow comparison and benchmarking ...
846     Just comment the corresponding cases in type_check' to
847     activate these ones.
848     *)
849 abate 263 | Map (e,b) ->
850     let t = compute_type env e in
851     Sequence.map (fun t -> type_check_branches loc env t b Types.any true) t
852 abate 30 | Pair (e1,e2) ->
853     let t1 = compute_type env e1
854     and t2 = compute_type env e2 in
855     Types.times (Types.cons t1) (Types.cons t2)
856     | RecordLitt r ->
857 abate 233 let r = LabelMap.map (fun e -> Types.cons (compute_type env e)) r in
858 abate 159 Types.record' (false,r)
859 abate 19 | _ -> assert false
860 abate 6
861 abate 65 and type_check_branches loc env targ brs constr precise =
862 abate 6 if Types.is_empty targ then Types.empty
863 abate 9 else (
864     brs.br_typ <- Types.cup brs.br_typ targ;
865 abate 65 branches_aux loc env targ
866 abate 19 (if precise then Types.empty else constr)
867     constr precise brs.br_branches
868 abate 9 )
869 abate 6
870 abate 65 and branches_aux loc env targ tres constr precise = function
871     | [] -> raise_loc loc (NonExhaustive targ)
872 abate 263 | { br_body = { exp_descr = MatchFail } } :: _ ->
873     match_fail := Types.cup !match_fail targ;
874     tres
875 abate 6 | b :: rem ->
876     let p = b.br_pat in
877     let acc = Types.descr (Patterns.accept p) in
878    
879     let targ' = Types.cap targ acc in
880     if Types.is_empty targ'
881 abate 65 then branches_aux loc env targ tres constr precise rem
882 abate 6 else
883     ( b.br_used <- true;
884     let res = Patterns.filter targ' p in
885     let env' = List.fold_left
886     (fun env (x,t) -> Env.add x (Types.descr t) env)
887     env res in
888 abate 19 let t = type_check env' b.br_body constr precise in
889     let tres = if precise then Types.cup t tres else tres in
890 abate 9 let targ'' = Types.diff targ acc in
891     if (Types.non_empty targ'') then
892 abate 65 branches_aux loc env targ'' tres constr precise rem
893 abate 9 else
894     tres
895 abate 6 )
896 abate 16
897 abate 66 and type_let_decl env l =
898     let acc = Types.descr (Patterns.accept l.let_pat) in
899     let t = type_check env l.let_body acc true in
900     let res = Patterns.filter t l.let_pat in
901     List.map (fun (x,t) -> (x, Types.descr t)) res
902    
903     and type_rec_funs env l =
904     let types =
905     List.fold_left
906     (fun accu -> function {let_body={exp_descr=Abstraction a}} as l ->
907     let t = a.fun_typ in
908     let acc = Types.descr (Patterns.accept l.let_pat) in
909     if not (Types.subtype t acc) then
910     raise_loc l.let_body.exp_loc (NonExhaustive (Types.diff t acc));
911     let res = Patterns.filter t l.let_pat in
912     List.fold_left (fun accu (x,t) -> (x, Types.descr t)::accu) accu res
913     | _ -> assert false) [] l
914     in
915     let env' = List.fold_left (fun env (x,t) -> Env.add x t env) env types in
916     List.iter
917     (function { let_body = { exp_descr = Abstraction a } } as l ->
918     ignore (type_check env' l.let_body Types.any false)
919     | _ -> assert false) l;
920     types
921    
922    
923 abate 16 and type_op loc op args =
924     match (op,args) with
925 abate 51 | "+", [loc1,t1; loc2,t2] ->
926 abate 242 check loc1 t1 int_cup_record
927     "The first argument of + must be an integer or a record";
928     let int = Types.Int.get t1 in
929     let int = if Intervals.is_empty int then None else Some int in
930     let r = if Types.Record.has_record t1 then Some t1 else None in
931     (match (int,r) with
932     | Some t1, None ->
933     if not (Types.Int.is_int t2) then
934     raise_loc loc2
935     (Constraint
936     (t2,Types.Int.any,
937     "The second argument of + must be an integer"));
938     Types.Int.put
939     (Intervals.add t1 (Types.Int.get t2));
940     | None, Some r1 ->
941     check loc2 t2 Types.Record.any
942     "The second argument of + must be a record";
943     Types.Record.merge r1 t2
944     | None, None ->
945     Types.empty
946     | Some t1, Some r1 ->
947     check loc2 t2 int_cup_record
948     "The second argument of + must be an integer or a record";
949     Types.cup
950     (Types.Int.put (Intervals.add t1 (Types.Int.get t2)))
951     (Types.Record.merge r1 t2)
952     )
953 abate 51 | "-", [loc1,t1; loc2,t2] ->
954     type_int_binop Intervals.sub loc1 t1 loc2 t2
955 abate 210 | ("*" | "/" | "mod"), [loc1,t1; loc2,t2] ->
956 abate 16 type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
957 abate 51 | "@", [loc1,t1; loc2,t2] ->
958 abate 17 check loc1 t1 Sequence.any
959     "The first argument of @ must be a sequence";
960     Sequence.concat t1 t2
961 abate 51 | "flatten", [loc1,t1] ->
962 abate 17 check loc1 t1 Sequence.seqseq
963     "The argument of flatten must be a sequence of sequences";
964     Sequence.flatten t1
965 abate 58 | "load_xml", [loc1,t1] ->
966     check loc1 t1 Sequence.string
967     "The argument of load_xml must be a string (filename)";
968     Types.any
969 abate 259 | "load_file", [loc1,t1] ->
970     check loc1 t1 Sequence.string
971     "The argument of load_file must be a string (filename)";
972     Sequence.string
973 abate 188 | "load_html", [loc1,t1] ->
974     check loc1 t1 Sequence.string
975     "The argument of load_html must be a string (filename)";
976     Types.any
977 abate 64 | "raise", [loc1,t1] ->
978     Types.empty
979 abate 76 | "print_xml", [loc1,t1] ->
980     Sequence.string
981 abate 124 | "print", [loc1,t1] ->
982     check loc1 t1 Sequence.string
983 abate 126 "The argument of print must be a string";
984     Sequence.nil_type
985     | "dump_to_file", [loc1,t1; loc2,t2] ->
986     check loc1 t1 Sequence.string
987     "The argument of dump_to_file must be a string (filename)";
988     check loc2 t2 Sequence.string
989     "The argument of dump_to_file must be a string (value to dump)";
990     Sequence.nil_type
991 abate 66 | "int_of", [loc1,t1] ->
992     check loc1 t1 Sequence.string
993 abate 126 "The argument of int_of must be a string";
994 abate 66 if not (Types.subtype t1 Builtin.intstr) then
995     warning loc "This application of int_of may fail";
996     Types.interval Intervals.any
997 abate 133 | "string_of", [loc1,t1] ->
998     Sequence.string
999 abate 239 | "=", [loc1,t1; loc2,t2] ->
1000 abate 237 (* could prevent comparision of functional value here... *)
1001     (* could also handle the case when t1 and t2 are the same
1002     singleton type *)
1003     if Types.is_empty (Types.cap t1 t2) then
1004     Builtin.false_type
1005     else
1006     Builtin.bool
1007 abate 239 | ("<=" | "<" | ">" | ">=" ), [loc1,t1; loc2,t2] ->
1008     (* could prevent comparision of functional value here... *)
1009     Builtin.bool
1010 abate 16 | _ -> assert false
1011    
1012     and type_int_binop f loc1 t1 loc2 t2 =
1013     if not (Types.Int.is_int t1) then
1014     raise_loc loc1
1015     (Constraint
1016     (t1,Types.Int.any,
1017     "The first argument must be an integer"));
1018     if not (Types.Int.is_int t2) then
1019     raise_loc loc2
1020     (Constraint
1021 abate 37 (t2,Types.Int.any,
1022 abate 16 "The second argument must be an integer"));
1023     Types.Int.put
1024 abate 314 (f (Types.Int.get t1) (Types.Int.get t2))
1025 abate 16
1026    
1027 abate 314
1028    
1029     let report_unused_branches () =
1030     List.iter
1031     (fun b ->
1032     if not b.br_used then
1033     warning b.br_loc "This branch is not used"
1034     )
1035     !all_branches;
1036     all_branches := []
1037    

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