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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 364 - (hide annotations)
Tue Jul 10 17:28:25 2007 UTC (5 years, 10 months ago) by abate
File size: 33961 byte(s)
[r2003-05-18 13:30:38 by cvscast] New pretty-printer for types

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

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