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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 361 - (show annotations)
Tue Jul 10 17:28:05 2007 UTC (5 years, 10 months ago) by abate
File size: 34168 byte(s)
[r2003-05-16 13:32:07 by cvscast] Bug fix in type_check_pair

Original author: cvscast
Date: 2003-05-16 13:32:07+00:00
1 (* TODO:
2 - rewrite type-checking of operators to propagate constraint
3 - optimize computation of pattern free variables
4 - check whether it is worth using recursive hash-consing internally
5 *)
6
7
8 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 (* I. Transform the abstract syntax of types and patterns into
15 the internal form *)
16
17 open Location
18 open Ast
19 open Ident
20
21 module S = struct type t = string let compare = compare end
22 module StringSet = Set.Make(S)
23 module TypeEnv = Map.Make(S)
24 module Env = Map.Make(Id)
25
26
27 exception NonExhaustive of Types.descr
28 exception Constraint of Types.descr * Types.descr * string
29 exception ShouldHave of Types.descr * string
30 exception ShouldHave2 of Types.descr * string * Types.descr
31 exception WrongLabel of Types.descr * label
32 exception UnboundId of string
33
34 let raise_loc loc exn = raise (Location (loc,exn))
35
36
37 (* Eliminate Recursion, propagate Sequence Capture Variables *)
38
39 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
45 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
72 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
94 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
118 module DerecursTable = Hashtbl.Make(
119 struct
120 type t = derecurs
121 let hash = hash_derecurs
122 let equal = equal_derecurs
123 end
124 )
125
126 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
134
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 | WeakStar p -> PWeakStar (derecurs_regexp vars env p)
169 | SeqCapture (x,p) -> derecurs_regexp (fun p -> PAnd (vars p, PCapture x)) env p
170
171
172 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
178 (* Stratification and recursive hash-consing *)
179
180 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 | IOptional of descr
189 | 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 mutable d : descr option
198 }
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 let equal s1 s2 =
265 (s1 == s2) ||
266 (incr gen; rank := 0;
267 let e = equal_slot s1 s2 in
268 (* if e then Printf.eprintf "Recursive hash-consig: Equal\n"; *)
269 e)
270 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 | IType _ -> IdSet.empty
281 | 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
291
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
301 let todo_fv = ref []
302
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 todo_fv := s :: !todo_fv;
311 s
312
313 let flush_fv () =
314 List.iter compute_fv !todo_fv;
315 todo_fv := []
316
317 let compile_slot_hash = DerecursTable.create 67
318 let compile_hash = DerecursTable.create 67
319
320 let defs = ref []
321
322 let rec compile p =
323 try DerecursTable.find compile_hash p
324 with Not_found ->
325 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 let s = mk () in
371 defs := (s,p) :: !defs;
372 DerecursTable.add compile_slot_hash p s;
373 s
374
375
376 let rec flush_defs () =
377 match !defs with
378 | [] -> ()
379 | (s,p)::t -> defs := t; s.d <- Some (compile p); flush_defs ()
380
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 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 flush_defs ();
459 flush_fv ();
460 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 warning p.loc ("This definition yields an empty type for " ^ v);
467 Types.Print.register_global v t) b
468
469 let dump_global_types ppf =
470 TypeEnv.iter (fun v _ -> Format.fprintf ppf " %s" v) !glb
471
472
473 let typ p =
474 let s = compile_slot (derecurs !glb p) in
475 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 let s = compile_slot (derecurs !glb p) in
482 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
488
489 (* II. Build skeleton *)
490
491 module Fv = IdSet
492
493 let all_branches = ref []
494
495 (* IDEA: introduce a node Loc in the AST to override nolocs
496 in sub-expressions *)
497
498 let exp loc fv e =
499 fv,
500 { Typed.exp_loc = loc;
501 Typed.exp_typ = Types.empty;
502 Typed.exp_descr = e;
503 }
504
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 | Xtrans (e,b) ->
572 let b = b @ [ mknoloc (Internal Types.any), MatchFail ] in
573 let (fv1,e) = expr loc e
574 and (fv2,b) = branches b in
575 exp loc (Fv.cup fv1 fv2) (Typed.Xtrans (e, b))
576 | 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
584 and branches b =
585 let fv = ref Fv.empty in
586 let accept = ref Types.empty in
587 let branch (p,e) =
588 let (fv2,e) = expr noloc e in
589 let br_loc = merge_loc p.loc e.Typed.exp_loc in
590 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 (!fv,
604 {
605 Typed.br_typ = Types.empty;
606 Typed.br_branches = b;
607 Typed.br_accept = !accept;
608 Typed.br_compiled = None;
609 }
610 )
611
612 let expr = expr noloc
613
614 let let_decl p e =
615 let (_,e) = expr e in
616 { Typed.let_pat = pat p;
617 Typed.let_body = e;
618 Typed.let_compiled = None }
619
620 (* III. Type-checks *)
621
622 let int_cup_record = Types.cup Types.Int.any Types.Record.any
623
624
625 type env = Types.descr Env.t
626
627 let match_fail = ref Types.empty
628
629 open Typed
630
631
632 let check loc t s msg =
633 if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
634
635 let rec type_check env e constr precise =
636 (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
637 Types.Print.print_descr constr precise;
638 *)
639 let d = type_check' e.exp_loc env e.exp_descr constr precise in
640 e.exp_typ <- Types.cup e.exp_typ d;
641 d
642
643 and type_check' loc env e constr precise = match e with
644 | Forget (e,t) ->
645 let t = Types.descr t in
646 ignore (type_check env e t false);
647 t
648 | 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 ignore (type_check_branches loc env t1 a.fun_body t2 false)
662 ) a.fun_iface;
663 t
664
665 | Match (e,b) ->
666 let t = type_check env e b.br_accept true in
667 type_check_branches loc env t b constr precise
668
669 | Try (e,b) ->
670 let te = type_check env e constr precise in
671 let tb = type_check_branches loc env Types.any b constr precise in
672 Types.cup te tb
673
674 | 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
679 | RecordLitt r ->
680 (* try to get rid of precise = true for values of fields *)
681 (* also: the use equivalent of need_second to optimize... *)
682 let precise = true in
683 if not (Types.Record.has_record constr) then
684 raise_loc loc (ShouldHave (constr,"but it is a record."));
685 let (rconstr,res) =
686 List.fold_left
687 (fun (rconstr,res) (l,e) ->
688 (* could compute (split l e) once... *)
689 let pi = Types.Record.project_opt rconstr l in
690 if Types.is_empty pi then
691 raise_loc loc
692 (ShouldHave (constr,(Printf.sprintf
693 "Field %s is not allowed here."
694 (LabelPool.value l)
695 )
696 ));
697 let t = type_check env e pi true in
698 let rconstr = Types.Record.condition rconstr l t in
699 let res = if precise then (l,Types.cons t) :: res else res in
700 (rconstr,res)
701 ) (constr, []) (LabelMap.get r)
702 in
703 if not (Types.Record.has_empty_record rconstr) then
704 raise_loc loc
705 (ShouldHave (constr,"More field should be present"));
706 let t =
707 Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res)
708 in
709 check loc t constr "";
710 t
711 (*
712 if precise then
713 Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res)
714 else constr
715 *)
716 | 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 (* 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 type_check_branches loc env t b constr' (precise || (not exact)))
729 t in
730 if not exact then check loc res constr "";
731 if precise then res else constr
732 | 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 | Apply (e1,e2) ->
750 (*
751 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 *)
778 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 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 | 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 | Op ("atom_of", [e]) ->
804 let t = type_check env e Sequence.string false in
805 Types.atom Atoms.any
806 | _ ->
807 let t : Types.descr = compute_type' loc env e in
808 check loc t constr "";
809 t
810
811 and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise =
812 let rects = Types.Product.normal ~kind constr in
813 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 let need_s = Types.Product.need_second rects in
818 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
824 if precise then
825 match kind with
826 | `Normal -> Types.times (Types.cons t1) (Types.cons t2)
827 | `XML -> Types.xml (Types.cons t1) (Types.cons t2)
828 else
829 constr
830
831
832 and compute_type env e =
833 type_check env e Types.any true
834
835 and compute_type' loc env = function
836 | Var s ->
837 (try Env.find s env
838 with Not_found -> raise_loc loc (UnboundId (Id.value s))
839 )
840 | Cst c -> Types.constant c
841 | 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 | RemoveField (e,l) ->
846 let t = type_check env e Types.Record.any true in
847 Types.Record.remove_field t l
848 | 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 | Xtrans (e,b) ->
852 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
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 | 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 | 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 let r = LabelMap.map (fun e -> Types.cons (compute_type env e)) r in
877 Types.record' (false,r)
878 | _ -> assert false
879
880 and type_check_branches loc env targ brs constr precise =
881 if Types.is_empty targ then Types.empty
882 else (
883 brs.br_typ <- Types.cup brs.br_typ targ;
884 branches_aux loc env targ
885 (if precise then Types.empty else constr)
886 constr precise brs.br_branches
887 )
888
889 and branches_aux loc env targ tres constr precise = function
890 | [] -> raise_loc loc (NonExhaustive targ)
891 | { br_body = { exp_descr = MatchFail } } :: _ ->
892 match_fail := Types.cup !match_fail targ;
893 tres
894 | 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 then branches_aux loc env targ tres constr precise rem
901 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 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 let targ'' = Types.diff targ acc in
910 if (Types.non_empty targ'') then
911 branches_aux loc env targ'' tres constr precise rem
912 else
913 tres
914 )
915
916 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 and type_op loc op args =
943 match (op,args) with
944 | "+", [loc1,t1; loc2,t2] ->
945 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 if not (Types.Int.is_int t2) then
953 raise_loc loc2
954 (Constraint
955 (t2,Types.Int.any,
956 "The second argument of + must be an integer"));
957 Types.Int.put
958 (Intervals.add t1 (Types.Int.get t2));
959 | None, Some r1 ->
960 check loc2 t2 Types.Record.any
961 "The second argument of + must be a record";
962 Types.Record.merge r1 t2
963 | None, None ->
964 Types.empty
965 | Some t1, Some r1 ->
966 check loc2 t2 int_cup_record
967 "The second argument of + must be an integer or a record";
968 Types.cup
969 (Types.Int.put (Intervals.add t1 (Types.Int.get t2)))
970 (Types.Record.merge r1 t2)
971 )
972 | "-", [loc1,t1; loc2,t2] ->
973 type_int_binop Intervals.sub loc1 t1 loc2 t2
974 | ("*" | "/" | "mod"), [loc1,t1; loc2,t2] ->
975 type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
976 | "@", [loc1,t1; loc2,t2] ->
977 check loc1 t1 Sequence.any
978 "The first argument of @ must be a sequence";
979 Sequence.concat t1 t2
980 | "flatten", [loc1,t1] ->
981 check loc1 t1 Sequence.seqseq
982 "The argument of flatten must be a sequence of sequences";
983 Sequence.flatten t1
984 | "load_xml", [loc1,t1] ->
985 check loc1 t1 Sequence.string
986 "The argument of load_xml must be a string (filename)";
987 Types.any
988 | "load_file", [loc1,t1] ->
989 check loc1 t1 Sequence.string
990 "The argument of load_file must be a string (filename)";
991 Sequence.string
992 | "load_html", [loc1,t1] ->
993 check loc1 t1 Sequence.string
994 "The argument of load_html must be a string (filename)";
995 Types.any
996 | "raise", [loc1,t1] ->
997 Types.empty
998 | "print_xml", [loc1,t1] ->
999 Sequence.string
1000 | "print", [loc1,t1] ->
1001 check loc1 t1 Sequence.string
1002 "The argument of print must be a string";
1003 Sequence.nil_type
1004 | "dump_to_file", [loc1,t1; loc2,t2] ->
1005 check loc1 t1 Sequence.string
1006 "The argument of dump_to_file must be a string (filename)";
1007 check loc2 t2 Sequence.string
1008 "The argument of dump_to_file must be a string (value to dump)";
1009 Sequence.nil_type
1010 | "int_of", [loc1,t1] ->
1011 check loc1 t1 Sequence.string
1012 "The argument of int_of must be a string";
1013 if not (Types.subtype t1 Builtin.intstr) then
1014 warning loc "This application of int_of may fail";
1015 Types.interval Intervals.any
1016 | "string_of", [loc1,t1] ->
1017 Sequence.string
1018 | "=", [loc1,t1; loc2,t2] ->
1019 (* could prevent comparision of functional value here... *)
1020 (* could also handle the case when t1 and t2 are the same
1021 singleton type *)
1022 if Types.is_empty (Types.cap t1 t2) then
1023 Builtin.false_type
1024 else
1025 Builtin.bool
1026 | ("<=" | "<" | ">" | ">=" ), [loc1,t1; loc2,t2] ->
1027 (* could prevent comparision of functional value here... *)
1028 Builtin.bool
1029 | _ -> assert false
1030
1031 and type_int_binop f loc1 t1 loc2 t2 =
1032 if not (Types.Int.is_int t1) then
1033 raise_loc loc1
1034 (Constraint
1035 (t1,Types.Int.any,
1036 "The first argument must be an integer"));
1037 if not (Types.Int.is_int t2) then
1038 raise_loc loc2
1039 (Constraint
1040 (t2,Types.Int.any,
1041 "The second argument must be an integer"));
1042 Types.Int.put
1043 (f (Types.Int.get t1) (Types.Int.get t2))
1044
1045
1046
1047
1048 let report_unused_branches () =
1049 List.iter
1050 (fun b ->
1051 if not b.br_used then
1052 warning b.br_loc "This branch is not used"
1053 )
1054 !all_branches;
1055 all_branches := []
1056

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