]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_kernel/nCicTypeChecker.ml
trust implemented, but in the nCicTypeChecker!
[helm.git] / helm / software / components / ng_kernel / nCicTypeChecker.ml
1 (*
2     ||M||  This file is part of HELM, an Hypertextual, Electronic        
3     ||A||  Library of Mathematics, developed at the Computer Science     
4     ||T||  Department, University of Bologna, Italy.                     
5     ||I||                                                                
6     ||T||  HELM is free software; you can redistribute it and/or         
7     ||A||  modify it under the terms of the GNU General Public License   
8     \   /  version 2 or (at your option) any later version.      
9      \ /   This software is distributed as is, NO WARRANTY.     
10       V_______________________________________________________________ *)
11
12 (* $Id: nCicReduction.ml 8250 2008-03-25 17:56:20Z tassi $ *)
13
14 module C = NCic 
15 module R = NCicReduction
16 module Ref = NReference
17 module S = NCicSubstitution 
18 module U = NCicUtils
19 module E = NCicEnvironment
20 module PP = NCicPp
21
22 exception TypeCheckerFailure of string Lazy.t
23 exception AssertFailure of string Lazy.t
24
25 type recf_entry = 
26   | Evil of int (* rno *) 
27   | UnfFix of bool list (* fixed arguments *) 
28   | Safe
29 ;;
30
31 let is_dangerous i l = 
32   List.exists (function (j,Evil _) when j=i -> true | _ -> false) l
33 ;;
34
35 let is_unfolded i l = 
36   List.exists (function (j,UnfFix _) when j=i -> true | _ -> false) l
37 ;;
38
39 let is_safe i l =
40   List.exists (function (j,Safe) when j=i -> true | _ -> false) l
41 ;;
42
43 let get_recno i l = 
44   try match List.assoc i l with Evil rno -> rno | _ -> assert false
45   with Not_found -> assert false
46 ;;
47
48 let get_fixed_args i l = 
49   try match List.assoc i l with UnfFix fa -> fa | _ -> assert false
50   with Not_found -> assert false
51 ;;
52
53 let shift_k e (c,rf,x) = e::c,List.map (fun (k,v) -> k+1,v) rf,x+1;;
54
55 let string_of_recfuns ~subst ~metasenv ~context l = 
56   let pp = PP.ppterm ~subst ~metasenv ~context in
57   let safe, rest = List.partition (function (_,Safe) -> true | _ -> false) l in
58   let dang,unf = List.partition (function (_,UnfFix _)-> false | _->true)rest in
59   "\n\tsafes: "^String.concat "," (List.map (fun (i,_)->pp (C.Rel i)) safe) ^
60   "\n\tfix  : "^String.concat "," 
61    (List.map 
62      (function (i,UnfFix l)-> pp(C.Rel i)^"/"^String.concat "," (List.map
63        string_of_bool l)
64      | _ ->assert false) unf) ^
65   "\n\trec  : "^String.concat "," 
66    (List.map 
67      (function (i,Evil rno)->pp(C.Rel i)^"/"^string_of_int rno
68      | _ -> assert false) dang)
69 ;;
70
71 let fixed_args bos j n nn =
72  let rec aux k acc = function
73   | C.Appl (C.Rel i::args) when i-k > n && i-k <= nn ->
74      let rec combine l1 l2 =
75       match l1,l2 with
76          [],[] -> []
77        | he1::tl1, he2::tl2 -> (he1,he2)::combine tl1 tl2
78        | he::tl, [] -> (false,C.Rel ~-1)::combine tl [] (* dummy term *)
79        | [],_::_ -> assert false
80      in
81      let lefts, _ = HExtlib.split_nth (min j (List.length args)) args in
82       List.map (fun ((b,x),i) -> b && x = C.Rel (k-i)) 
83        (HExtlib.list_mapi (fun x i -> x,i) (combine acc lefts))
84   | t -> U.fold (fun _ k -> k+1) k aux acc t    
85  in
86   List.fold_left (aux 0) 
87    (let rec f = function 0 -> [] | n -> true :: f (n-1) in f j) bos
88 ;;
89
90 let rec list_iter_default2 f l1 def l2 = 
91   match l1,l2 with
92     | [], _ -> ()
93     | a::ta, b::tb -> f a b; list_iter_default2 f ta def tb 
94     | a::ta, [] -> f a def; list_iter_default2 f ta def [] 
95 ;;
96
97 let rec split_prods ~subst context n te =
98   match (n, R.whd ~subst context te) with
99    | (0, _) -> context,te
100    | (n, C.Prod (name,so,ta)) when n > 0 ->
101        split_prods ~subst ((name,(C.Decl so))::context) (n - 1) ta
102    | (_, _) -> raise (AssertFailure (lazy "split_prods"))
103 ;;
104
105 let debruijn ?(cb=fun _ _ -> ()) uri number_of_types context = 
106  let rec aux k t =
107   let res =
108    match t with
109     | C.Meta (i,(s,C.Ctx l)) ->
110        let l1 = U.sharing_map (aux (k-s)) l in
111        if l1 == l then t else C.Meta (i,(s,C.Ctx l1))
112     | C.Meta _ -> t
113     | C.Const (Ref.Ref (_,uri1,(Ref.Fix (no,_) | Ref.CoFix no))) 
114     | C.Const (Ref.Ref (_,uri1,Ref.Ind no)) when NUri.eq uri uri1 ->
115        C.Rel (k + number_of_types - no)
116     | t -> U.map (fun _ k -> k+1) k aux t
117   in
118    cb t res; res
119  in
120   aux (List.length context)
121 ;;
122
123 let sort_of_prod ~metasenv ~subst context (name,s) (t1, t2) =
124    let t1 = R.whd ~subst context t1 in
125    let t2 = R.whd ~subst ((name,C.Decl s)::context) t2 in
126    match t1, t2 with
127    | C.Sort s1, C.Sort C.Prop -> t2
128    | C.Sort (C.Type u1), C.Sort (C.Type u2) -> C.Sort (C.Type (max u1 u2)) 
129    | C.Sort _,C.Sort (C.Type _) -> t2
130    | C.Sort (C.Type _) , C.Sort C.CProp -> t1
131    | C.Sort _, C.Sort C.CProp -> t2
132    | C.Meta _, C.Sort _
133    | C.Meta _, C.Meta _
134    | C.Sort _, C.Meta _ when U.is_closed t2 -> t2
135    | _ -> 
136       raise (TypeCheckerFailure (lazy (Printf.sprintf
137         "Prod: expected two sorts, found = %s, %s" 
138          (PP.ppterm ~subst ~metasenv ~context t1) 
139          (PP.ppterm ~subst ~metasenv ~context t2))))
140 ;;
141
142 let eat_prods ~subst ~metasenv context he ty_he args_with_ty = 
143   let rec aux ty_he = function 
144   | [] -> ty_he
145   | (arg, ty_arg)::tl ->
146       match R.whd ~subst context ty_he with 
147       | C.Prod (n,s,t) ->
148 (*
149           prerr_endline (PP.ppterm ~subst ~metasenv ~context s ^ " - Vs - "
150             ^ PP.ppterm ~subst ~metasenv ~context ty_arg);
151           prerr_endline (PP.ppterm ~subst ~metasenv ~context
152              (S.subst ~avoid_beta_redexes:true arg t));
153 *)
154           if R.are_convertible ~subst ~metasenv context ty_arg s then
155             aux (S.subst ~avoid_beta_redexes:true arg t) tl
156           else
157             raise 
158               (TypeCheckerFailure 
159                 (lazy (Printf.sprintf
160                   ("Appl: wrong application of %s: the parameter %s has type"^^
161                    "\n%s\nbut it should have type \n%s\nContext:\n%s\n")
162                   (PP.ppterm ~subst ~metasenv ~context he)
163                   (PP.ppterm ~subst ~metasenv ~context arg)
164                   (PP.ppterm ~subst ~metasenv ~context ty_arg)
165                   (PP.ppterm ~subst ~metasenv ~context s)
166                   (PP.ppcontext ~subst ~metasenv context))))
167        | _ ->
168           raise 
169             (TypeCheckerFailure
170               (lazy (Printf.sprintf
171                 "Appl: %s is not a function, it cannot be applied"
172                 (PP.ppterm ~subst ~metasenv ~context
173                  (let res = List.length tl in
174                   let eaten = List.length args_with_ty - res in
175                    (C.Appl
176                     (he::List.map fst
177                      (fst (HExtlib.split_nth eaten args_with_ty)))))))))
178   in
179     aux ty_he args_with_ty
180 ;;
181
182 (* instantiate_parameters ps (x1:T1)...(xn:Tn)C                             *)
183 (* returns ((x_|ps|:T_|ps|)...(xn:Tn)C){ps_1 / x1 ; ... ; ps_|ps| / x_|ps|} *)
184 let rec instantiate_parameters params c =
185   match c, params with
186   | c,[] -> c
187   | C.Prod (_,_,ta), he::tl -> instantiate_parameters tl (S.subst he ta)
188   | t,l -> raise (AssertFailure (lazy "1"))
189 ;;
190
191 let specialize_inductive_type_constrs ~subst context ty_term =
192   match R.whd ~subst context ty_term with
193   | C.Const (Ref.Ref (_,uri,Ref.Ind i) as ref)  
194   | C.Appl (C.Const (Ref.Ref (_,uri,Ref.Ind i) as ref) :: _ ) as ty ->
195       let args = match ty with C.Appl (_::tl) -> tl | _ -> [] in
196       let is_ind, leftno, itl, attrs, i = E.get_checked_indtys ref in
197       let left_args,_ = HExtlib.split_nth leftno args in
198       let _,_,_,cl = List.nth itl i in
199       List.map 
200         (fun (rel,name,ty) -> rel, name, instantiate_parameters left_args ty) cl
201   | _ -> assert false
202 ;;
203
204 let specialize_and_abstract_constrs ~subst r_uri r_len context ty_term =
205   let cl = specialize_inductive_type_constrs ~subst context ty_term in
206   let len = List.length context in
207   let context_dcl = 
208     match E.get_checked_obj r_uri with
209     | _,_,_,_, NCic.Inductive (_,_,tys,_) -> 
210         context @ List.map (fun (_,name,arity,_) -> name,C.Decl arity) tys
211     | _ -> assert false
212   in
213   context_dcl,
214   List.map (fun (_,id,ty) -> id, debruijn r_uri r_len context ty) cl,
215   len, len + r_len
216 ;;
217
218 exception DoesOccur;;
219
220 let does_not_occur ~subst context n nn t = 
221   let rec aux (context,n,nn as k) _ = function
222     | C.Rel m when m > n && m <= nn -> raise DoesOccur
223     | C.Rel m ->
224         (try (match List.nth context (m-1) with
225           | _,C.Def (bo,_) -> aux k () (S.lift m bo)
226           | _ -> ())
227          with Failure _ -> assert false)
228     | C.Meta (_,(_,(C.Irl 0 | C.Ctx []))) -> (* closed meta *) ()
229     | C.Meta (mno,(s,l)) ->
230          (try
231            let _,_,term,_ = U.lookup_subst mno subst in
232            aux (context,n+s,nn+s) () (S.subst_meta (0,l) term)
233           with CicUtil.Subst_not_found _ -> match l with
234           | C.Irl len -> if not (n >= s+len || s > nn) then raise DoesOccur
235           | C.Ctx lc -> List.iter (aux (context,n+s,nn+s) ()) lc)
236     | t -> U.fold (fun e (ctx,n,nn) -> (e::ctx,n+1,nn+1)) k aux () t
237   in
238    try aux (context,n,nn) () t; true
239    with DoesOccur -> false
240 ;;
241
242 (*CSC l'indice x dei tipi induttivi e' t.c. n < x <= nn *)
243 (*CSC questa funzione e' simile alla are_all_occurrences_positive, ma fa *)
244 (*CSC dei controlli leggermente diversi. Viene invocata solamente dalla  *)
245 (*CSC strictly_positive                                                  *)
246 (*CSC definizione (giusta???) tratta dalla mail di Hugo ;-)              *)
247 let rec weakly_positive ~subst context n nn uri te =
248 (*CSC: Che schifo! Bisogna capire meglio e trovare una soluzione ragionevole!*)
249   let dummy = C.Sort (C.Type ~-1) in
250   (*CSC: mettere in cicSubstitution *)
251   let rec subst_inductive_type_with_dummy _ = function
252     | C.Const (Ref.Ref (_,uri',Ref.Ind 0)) when NUri.eq uri' uri -> dummy
253     | C.Appl ((C.Const (Ref.Ref (_,uri',Ref.Ind 0)))::tl) 
254         when NUri.eq uri' uri -> dummy
255     | t -> U.map (fun _ x->x) () subst_inductive_type_with_dummy t
256   in
257   match R.whd context te with
258    | C.Const (Ref.Ref (_,uri',Ref.Ind _))
259    | C.Appl ((C.Const (Ref.Ref (_,uri',Ref.Ind _)))::_) 
260       when NUri.eq uri' uri -> true
261    | C.Prod (name,source,dest) when
262       does_not_occur ~subst ((name,C.Decl source)::context) 0 1 dest ->
263        (* dummy abstraction, so we behave as in the anonimous case *)
264        strictly_positive ~subst context n nn
265         (subst_inductive_type_with_dummy () source) &&
266        weakly_positive ~subst ((name,C.Decl source)::context)
267         (n + 1) (nn + 1) uri dest
268    | C.Prod (name,source,dest) ->
269        does_not_occur ~subst context n nn
270         (subst_inductive_type_with_dummy () source)&&
271        weakly_positive ~subst ((name,C.Decl source)::context)
272         (n + 1) (nn + 1) uri dest
273    | _ ->
274      raise (TypeCheckerFailure (lazy "Malformed inductive constructor type"))
275
276 and strictly_positive ~subst context n nn te =
277   match R.whd context te with
278    | t when does_not_occur ~subst context n nn t -> true
279    | C.Rel _ -> true
280    | C.Prod (name,so,ta) ->
281       does_not_occur ~subst context n nn so &&
282        strictly_positive ~subst ((name,C.Decl so)::context) (n+1) (nn+1) ta
283    | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
284       List.for_all (does_not_occur ~subst context n nn) tl
285    | C.Appl (C.Const (Ref.Ref (_,uri,Ref.Ind i) as r)::tl) -> 
286       let _,paramsno,tyl,_,i = E.get_checked_indtys r in
287       let _,name,ity,cl = List.nth tyl i in
288       let ok = List.length tyl = 1 in
289       let params, arguments = HExtlib.split_nth paramsno tl in
290       let lifted_params = List.map (S.lift 1) params in
291       let cl =
292         List.map (fun (_,_,te) -> instantiate_parameters lifted_params te) cl 
293       in
294       ok &&
295       List.for_all (does_not_occur ~subst context n nn) arguments &&
296       List.for_all 
297        (weakly_positive ~subst ((name,C.Decl ity)::context) (n+1) (nn+1) uri) cl
298    | _ -> false
299        
300 (* the inductive type indexes are s.t. n < x <= nn *)
301 and are_all_occurrences_positive ~subst context uri indparamsno i n nn te =
302   match R.whd context te with
303   |  C.Appl ((C.Rel m)::tl) as reduct when m = i ->
304       let last =
305        List.fold_left
306         (fun k x ->
307           if k = 0 then 0
308           else
309            match R.whd context x with
310            |  C.Rel m when m = n - (indparamsno - k) -> k - 1
311            | y -> raise (TypeCheckerFailure (lazy 
312               ("Argument "^string_of_int (indparamsno - k + 1) ^ " (of " ^
313               string_of_int indparamsno ^ " fixed) is not homogeneous in "^
314               "appl:\n"^ PP.ppterm ~context ~subst ~metasenv:[] reduct))))
315         indparamsno tl
316       in
317        if last = 0 then
318         List.for_all (does_not_occur ~subst context n nn) tl
319        else
320         raise (TypeCheckerFailure
321          (lazy ("Non-positive occurence in mutual inductive definition(s) [2]"^
322           NUri.string_of_uri uri)))
323   | C.Rel m when m = i ->
324       if indparamsno = 0 then
325        true
326       else
327         raise (TypeCheckerFailure
328          (lazy ("Non-positive occurence in mutual inductive definition(s) [3]"^
329           NUri.string_of_uri uri)))
330   | C.Prod (name,source,dest) when
331       does_not_occur ~subst ((name,C.Decl source)::context) 0 1 dest ->
332       strictly_positive ~subst context n nn source &&
333        are_all_occurrences_positive ~subst 
334         ((name,C.Decl source)::context) uri indparamsno
335         (i+1) (n + 1) (nn + 1) dest
336    | C.Prod (name,source,dest) ->
337        if not (does_not_occur ~subst context n nn source) then
338          raise (TypeCheckerFailure (lazy ("Non-positive occurrence in "^
339          PP.ppterm ~context ~metasenv:[] ~subst te)));
340        are_all_occurrences_positive ~subst ((name,C.Decl source)::context)
341         uri indparamsno (i+1) (n + 1) (nn + 1) dest
342    | _ ->
343      raise
344       (TypeCheckerFailure (lazy ("Malformed inductive constructor type " ^
345         (NUri.string_of_uri uri))))
346 ;;
347
348 exception NotGuarded of string Lazy.t;;
349
350 let rec typeof ~subst ~metasenv context term =
351   let rec typeof_aux context = 
352     fun t -> (*prerr_endline (PP.ppterm ~metasenv ~subst ~context t);*)
353     match t with
354     | C.Rel n ->
355        (try
356          match List.nth context (n - 1) with
357          | (_,C.Decl ty) -> S.lift n ty
358          | (_,C.Def (_,ty)) -> S.lift n ty
359         with Failure _ -> raise (TypeCheckerFailure (lazy "unbound variable")))
360     | C.Sort (C.Type i) -> C.Sort (C.Type (i+1))
361     | C.Sort s -> C.Sort (C.Type 0)
362     | C.Implicit _ -> raise (AssertFailure (lazy "Implicit found"))
363     | C.Meta (n,l) as t -> 
364        let canonical_ctx,ty =
365         try
366          let _,c,_,ty = U.lookup_subst n subst in c,ty
367         with U.Subst_not_found _ -> try
368          let _,_,c,ty = U.lookup_meta n metasenv in c,ty
369         with U.Meta_not_found _ ->
370          raise (AssertFailure (lazy (Printf.sprintf
371           "%s not found" (PP.ppterm ~subst ~metasenv ~context t))))
372        in
373         check_metasenv_consistency t ~subst ~metasenv context canonical_ctx l;
374         S.subst_meta l ty
375     | C.Const ref -> type_of_constant ref
376     | C.Prod (name,s,t) ->
377        let sort1 = typeof_aux context s in
378        let sort2 = typeof_aux ((name,(C.Decl s))::context) t in
379        sort_of_prod ~metasenv ~subst context (name,s) (sort1,sort2)
380     | C.Lambda (n,s,t) ->
381        let sort = typeof_aux context s in
382        (match R.whd ~subst context sort with
383        | C.Meta _ | C.Sort _ -> ()
384        | _ ->
385          raise
386            (TypeCheckerFailure (lazy (Printf.sprintf
387              ("Not well-typed lambda-abstraction: " ^^
388              "the source %s should be a type; instead it is a term " ^^ 
389              "of type %s") (PP.ppterm ~subst ~metasenv ~context s)
390              (PP.ppterm ~subst ~metasenv ~context sort)))));
391        let ty = typeof_aux ((n,(C.Decl s))::context) t in
392          C.Prod (n,s,ty)
393     | C.LetIn (n,ty,t,bo) ->
394        let ty_t = typeof_aux context t in
395        let _ = typeof_aux context ty in
396        if not (R.are_convertible ~subst ~metasenv context ty ty_t) then
397          raise 
398           (TypeCheckerFailure 
399             (lazy (Printf.sprintf
400               "The type of %s is %s but it is expected to be %s" 
401                 (PP.ppterm ~subst ~metasenv ~context t) 
402                 (PP.ppterm ~subst ~metasenv ~context ty_t) 
403                 (PP.ppterm ~subst ~metasenv ~context ty))))
404        else
405          let ty_bo = typeof_aux  ((n,C.Def (t,ty))::context) bo in
406          S.subst ~avoid_beta_redexes:true t ty_bo
407     | C.Appl (he::(_::_ as args)) ->
408        let ty_he = typeof_aux context he in
409        let args_with_ty = List.map (fun t -> t, typeof_aux context t) args in
410 (*
411        prerr_endline ("HEAD: " ^ PP.ppterm ~subst ~metasenv ~context ty_he);
412        prerr_endline ("TARGS: " ^ String.concat " | " (List.map (PP.ppterm
413        ~subst ~metasenv ~context) (List.map snd args_with_ty)));
414        prerr_endline ("ARGS: " ^ String.concat " | " (List.map (PP.ppterm
415        ~subst ~metasenv ~context) (List.map fst args_with_ty)));
416 *)
417        eat_prods ~subst ~metasenv context he ty_he args_with_ty
418    | C.Appl _ -> raise (AssertFailure (lazy "Appl of length < 2"))
419    | C.Match (Ref.Ref (_,_,Ref.Ind tyno) as r,outtype,term,pl) ->
420       let outsort = typeof_aux context outtype in
421       let inductive,leftno,itl,_,_ = E.get_checked_indtys r in
422       let constructorsno =
423         let _,_,_,cl = List.nth itl tyno in List.length cl
424       in
425       let parameters, arguments =
426         let ty = R.whd ~subst context (typeof_aux context term) in
427         let r',tl =
428          match ty with
429             C.Const (Ref.Ref (_,_,Ref.Ind _) as r') -> r',[]
430           | C.Appl (C.Const (Ref.Ref (_,_,Ref.Ind _) as r') :: tl) -> r',tl
431           | _ ->
432              raise 
433                (TypeCheckerFailure (lazy (Printf.sprintf
434                  "Case analysis: analysed term %s is not an inductive one"
435                  (PP.ppterm ~subst ~metasenv ~context term)))) in
436         if not (Ref.eq r r') then
437          raise
438           (TypeCheckerFailure (lazy (Printf.sprintf
439             ("Case analysys: analysed term type is %s, but is expected " ^^
440              "to be (an application of) %s")
441             (PP.ppterm ~subst ~metasenv ~context ty) 
442             (PP.ppterm ~subst ~metasenv ~context (C.Const r')))))
443         else
444          try HExtlib.split_nth leftno tl
445          with
446           Failure _ ->
447            raise (TypeCheckerFailure (lazy (Printf.sprintf 
448            "%s is partially applied" 
449            (PP.ppterm  ~subst ~metasenv ~context ty)))) in
450       (* let's control if the sort elimination is allowed: [(I q1 ... qr)|B] *)
451       let sort_of_ind_type =
452         if parameters = [] then C.Const r
453         else C.Appl ((C.Const r)::parameters) in
454       let type_of_sort_of_ind_ty = typeof_aux context sort_of_ind_type in
455       check_allowed_sort_elimination ~subst ~metasenv r context
456        sort_of_ind_type type_of_sort_of_ind_ty outsort;
457       (* let's check if the type of branches are right *)
458       if List.length pl <> constructorsno then
459        raise (TypeCheckerFailure (lazy ("Wrong number of cases in a match")));
460       let j,branches_ok,p_ty, exp_p_ty =
461         List.fold_left
462           (fun (j,b,old_p_ty,old_exp_p_ty) p ->
463             if b then
464               let cons = 
465                 let cons = Ref.mk_constructor j r in
466                 if parameters = [] then C.Const cons
467                 else C.Appl (C.Const cons::parameters)
468               in
469               let ty_p = typeof_aux context p in
470               let ty_cons = typeof_aux context cons in
471               let ty_branch = 
472                 type_of_branch ~subst context leftno outtype cons ty_cons 0 
473               in
474               j+1, R.are_convertible ~subst ~metasenv context ty_p ty_branch,
475               ty_p, ty_branch
476             else
477               j,false,old_p_ty,old_exp_p_ty
478           ) (1,true,C.Sort C.Prop,C.Sort C.Prop) pl
479       in
480       if not branches_ok then
481         raise
482          (TypeCheckerFailure 
483           (lazy (Printf.sprintf ("Branch for constructor %s :=\n%s\n"^^
484           "has type %s\nnot convertible with %s") 
485           (PP.ppterm  ~subst ~metasenv ~context
486             (C.Const (Ref.mk_constructor (j-1) r)))
487           (PP.ppterm ~metasenv ~subst ~context (List.nth pl (j-2)))
488           (PP.ppterm ~metasenv ~subst ~context p_ty) 
489           (PP.ppterm ~metasenv ~subst ~context exp_p_ty)))); 
490       let res = outtype::arguments@[term] in
491       R.head_beta_reduce (C.Appl res)
492     | C.Match _ -> assert false
493
494   and type_of_branch ~subst context leftno outty cons tycons liftno = 
495     match R.whd ~subst context tycons with
496     | C.Const (Ref.Ref (_,_,Ref.Ind _)) -> C.Appl [S.lift liftno outty ; cons]
497     | C.Appl (C.Const (Ref.Ref (_,_,Ref.Ind _))::tl) ->
498         let _,arguments = HExtlib.split_nth leftno tl in
499         C.Appl (S.lift liftno outty::arguments@[cons])
500     | C.Prod (name,so,de) ->
501         let cons =
502          match S.lift 1 cons with
503          | C.Appl l -> C.Appl (l@[C.Rel 1])
504          | t -> C.Appl [t ; C.Rel 1]
505         in
506          C.Prod (name,so,
507            type_of_branch ~subst ((name,(C.Decl so))::context) 
508             leftno outty cons de (liftno+1))
509     | _ -> raise (AssertFailure (lazy "type_of_branch"))
510
511   (* check_metasenv_consistency checks that the "canonical" context of a
512      metavariable is consitent - up to relocation via the relocation list l -
513      with the actual context *)
514   and check_metasenv_consistency 
515     ~subst ~metasenv term context canonical_context l 
516   =
517    match l with
518     | shift, C.Irl n ->
519        let context = snd (HExtlib.split_nth shift context) in
520         let rec compare = function
521          | 0,_,[] -> ()
522          | 0,_,_::_
523          | _,_,[] ->
524             raise (AssertFailure (lazy (Printf.sprintf
525              "Local and canonical context %s have different lengths"
526              (PP.ppterm ~subst ~context ~metasenv term))))
527          | m,[],_::_ ->
528             raise (TypeCheckerFailure (lazy (Printf.sprintf
529              "Unbound variable -%d in %s" m 
530              (PP.ppterm ~subst ~metasenv ~context term))))
531          | m,t::tl,ct::ctl ->
532             (match t,ct with
533                 (_,C.Decl t1), (_,C.Decl t2)
534               | (_,C.Def (t1,_)), (_,C.Def (t2,_))
535               | (_,C.Def (_,t1)), (_,C.Decl t2) ->
536                  if not (R.are_convertible ~subst ~metasenv tl t1 t2) then
537                   raise 
538                       (TypeCheckerFailure 
539                         (lazy (Printf.sprintf 
540                       ("Not well typed metavariable local context for %s: " ^^ 
541                        "%s expected, which is not convertible with %s")
542                       (PP.ppterm ~subst ~metasenv ~context term) 
543                       (PP.ppterm ~subst ~metasenv ~context t2) 
544                       (PP.ppterm ~subst ~metasenv ~context t1))))
545               | _,_ ->
546                raise 
547                    (TypeCheckerFailure (lazy (Printf.sprintf 
548                     ("Not well typed metavariable local context for %s: " ^^ 
549                      "a definition expected, but a declaration found")
550                     (PP.ppterm ~subst ~metasenv ~context term)))));
551             compare (m - 1,tl,ctl)
552         in
553          compare (n,context,canonical_context)
554     | shift, lc_kind ->
555        (* we avoid useless lifting by shortening the context*)
556        let l,context = (0,lc_kind), snd (HExtlib.split_nth shift context) in
557        let lifted_canonical_context = 
558          let rec lift_metas i = function
559            | [] -> []
560            | (n,C.Decl t)::tl ->
561                (n,C.Decl (S.subst_meta l (S.lift i t)))::(lift_metas (i+1) tl)
562            | (n,C.Def (t,ty))::tl ->
563                (n,C.Def ((S.subst_meta l (S.lift i t)),
564                           S.subst_meta l (S.lift i ty)))::(lift_metas (i+1) tl)
565          in
566           lift_metas 1 canonical_context in
567        let l = U.expand_local_context lc_kind in
568        try
569         List.iter2 
570         (fun t ct -> 
571           match (t,ct) with
572           | t, (_,C.Def (ct,_)) ->
573              (*CSC: the following optimization is to avoid a possibly expensive
574                     reduction that can be easily avoided and that is quite
575                     frequent. However, this is better handled using levels to
576                     control reduction *)
577              let optimized_t =
578               match t with
579               | C.Rel n ->
580                   (try
581                     match List.nth context (n - 1) with
582                     | (_,C.Def (te,_)) -> S.lift n te
583                     | _ -> t
584                     with Failure _ -> t)
585               | _ -> t
586              in
587              if not (R.are_convertible ~subst ~metasenv context optimized_t ct)
588              then
589                raise 
590                  (TypeCheckerFailure 
591                    (lazy (Printf.sprintf 
592                      ("Not well typed metavariable local context: " ^^ 
593                       "expected a term convertible with %s, found %s")
594                      (PP.ppterm ~subst ~metasenv ~context ct) 
595                      (PP.ppterm ~subst ~metasenv ~context t))))
596           | t, (_,C.Decl ct) ->
597               let type_t = typeof_aux context t in
598               if not (R.are_convertible ~subst ~metasenv context type_t ct) then
599                 raise (TypeCheckerFailure 
600                  (lazy (Printf.sprintf 
601                   ("Not well typed metavariable local context: "^^
602                   "expected a term of type %s, found %s of type %s") 
603                   (PP.ppterm ~subst ~metasenv ~context ct) 
604                   (PP.ppterm ~subst ~metasenv ~context t) 
605                   (PP.ppterm ~subst ~metasenv ~context type_t))))
606         ) l lifted_canonical_context 
607        with
608         Invalid_argument _ ->
609           raise (AssertFailure (lazy (Printf.sprintf
610            "Local and canonical context %s have different lengths"
611            (PP.ppterm ~subst ~metasenv ~context term))))
612
613   and is_non_informative context paramsno c =
614    let rec aux context c =
615      match R.whd context c with
616       | C.Prod (n,so,de) ->
617          let s = typeof_aux context so in
618          s = C.Sort C.Prop && aux ((n,(C.Decl so))::context) de
619       | _ -> true in
620    let context',dx = split_prods ~subst:[] context paramsno c in
621     aux context' dx
622
623   and check_allowed_sort_elimination ~subst ~metasenv r =
624    let mkapp he arg =
625      match he with
626      | C.Appl l -> C.Appl (l @ [arg])
627      | t -> C.Appl [t;arg] in
628    let rec aux context ind arity1 arity2 =
629     let arity1 = R.whd ~subst context arity1 in
630     let arity2 = R.whd ~subst context arity2 in
631       match arity1,arity2 with
632        | C.Prod (name,so1,de1), C.Prod (_,so2,de2) ->
633           if not (R.are_convertible ~subst ~metasenv context so1 so2) then
634            raise (TypeCheckerFailure (lazy (Printf.sprintf
635             "In outtype: expected %s, found %s"
636             (PP.ppterm ~subst ~metasenv ~context so1)
637             (PP.ppterm ~subst ~metasenv ~context so2)
638             )));
639           aux ((name, C.Decl so1)::context)
640            (mkapp (S.lift 1 ind) (C.Rel 1)) de1 de2
641        | C.Sort _, C.Prod (name,so,ta) ->
642           if not (R.are_convertible ~subst ~metasenv context so ind) then
643            raise (TypeCheckerFailure (lazy (Printf.sprintf
644             "In outtype: expected %s, found %s"
645             (PP.ppterm ~subst ~metasenv ~context ind)
646             (PP.ppterm ~subst ~metasenv ~context so)
647             )));
648           (match arity1,ta with
649             | (C.Sort (C.CProp | C.Type _), C.Sort _)
650             | (C.Sort C.Prop, C.Sort C.Prop) -> ()
651             | (C.Sort C.Prop, C.Sort (C.CProp | C.Type _)) ->
652         (* TODO: we should pass all these parameters since we
653          * have them already *)
654                 let inductive,leftno,itl,_,i = E.get_checked_indtys r in
655                 let itl_len = List.length itl in
656                 let _,name,ty,cl = List.nth itl i in
657                 let cl_len = List.length cl in
658                  (* is it a singleton or empty non recursive and non informative
659                     definition? *)
660                  if not
661                   (cl_len = 0 ||
662                    (itl_len = 1 && cl_len = 1 &&
663                     is_non_informative [name,C.Decl ty] leftno
664                      (let _,_,x = List.nth cl 0 in x)))
665                  then
666                   raise (TypeCheckerFailure (lazy
667                    ("Sort elimination not allowed")));
668           | _,_ -> ())
669        | _,_ -> ()
670    in
671     aux 
672
673  in 
674    typeof_aux context term
675
676 and check_mutual_inductive_defs uri ~metasenv ~subst is_ind leftno tyl = 
677   (* let's check if the arity of the inductive types are well formed *)
678   List.iter (fun (_,_,x,_) -> ignore (typeof ~subst ~metasenv [] x)) tyl;
679   (* let's check if the types of the inductive constructors are well formed. *)
680   let len = List.length tyl in
681   let tys = List.rev (List.map (fun (_,n,ty,_) -> (n,(C.Decl ty))) tyl) in
682   ignore
683    (List.fold_right
684     (fun (_,_,_,cl) i ->
685        List.iter
686          (fun (_,name,te) -> 
687            let debruijnedte = debruijn uri len [] te in
688            ignore (typeof ~subst ~metasenv tys debruijnedte);
689            (* let's check also the positivity conditions *)
690            if 
691              not
692                (are_all_occurrences_positive ~subst tys uri leftno i 0 len
693                   debruijnedte) 
694            then
695              raise
696                (TypeCheckerFailure
697                  (lazy ("Non positive occurence in "^NUri.string_of_uri uri))))
698          cl;
699         i + 1)
700     tyl 1)
701
702 and eat_lambdas ~subst ~metasenv context n te =
703   match (n, R.whd ~subst context te) with
704   | (0, _) -> (te, context)
705   | (n, C.Lambda (name,so,ta)) when n > 0 ->
706       eat_lambdas ~subst ~metasenv ((name,(C.Decl so))::context) (n - 1) ta
707    | (n, te) ->
708       raise (AssertFailure (lazy (Printf.sprintf "eat_lambdas (%d, %s)" n 
709         (PP.ppterm ~subst ~metasenv ~context te))))
710
711 and eat_or_subst_lambdas ~subst ~metasenv n te to_be_subst args
712      (context, recfuns, x as k) 
713 =
714   match n, R.whd ~subst context te, to_be_subst, args with
715   | (n, C.Lambda (name,so,ta),true::to_be_subst,arg::args) when n > 0 ->
716       eat_or_subst_lambdas ~subst ~metasenv (n - 1) (S.subst arg ta)
717        to_be_subst args k
718   | (n, C.Lambda (name,so,ta),false::to_be_subst,arg::args) when n > 0 ->
719       eat_or_subst_lambdas ~subst ~metasenv (n - 1) ta to_be_subst args
720        (shift_k (name,(C.Decl so)) k)
721   | (_, te, _, _) -> te, k
722
723 and guarded_by_destructors r_uri r_len ~subst ~metasenv context recfuns t = 
724  let recursor f k t = U.fold shift_k k (fun k () -> f k) () t in
725  let rec aux (context, recfuns, x as k) t = 
726 (*
727    prerr_endline ("GB:\n" ^ 
728      PP.ppcontext ~subst ~metasenv context^
729      PP.ppterm ~metasenv ~subst ~context t^
730        string_of_recfuns ~subst ~metasenv ~context recfuns);
731 *)
732   try
733   match t with
734   | C.Rel m as t when is_dangerous m recfuns -> 
735       raise (NotGuarded (lazy 
736         (PP.ppterm ~subst ~metasenv ~context t ^ 
737          " is a partial application of a fix")))
738   | C.Appl ((C.Rel m)::tl) as t when is_dangerous m recfuns ->
739      let rec_no = get_recno m recfuns in
740      if not (List.length tl > rec_no) then 
741        raise (NotGuarded (lazy 
742          (PP.ppterm ~context ~subst ~metasenv t ^ 
743          " is a partial application of a fix")))
744      else
745        let rec_arg = List.nth tl rec_no in
746        if not (is_really_smaller r_uri r_len ~subst ~metasenv k rec_arg) then 
747          raise (NotGuarded (lazy (Printf.sprintf ("Recursive call %s, %s is not"
748           ^^ " smaller.\ncontext:\n%s") (PP.ppterm ~context ~subst ~metasenv
749           t) (PP.ppterm ~context ~subst ~metasenv rec_arg)
750           (PP.ppcontext ~subst ~metasenv context))));
751        List.iter (aux k) tl
752   | C.Appl ((C.Rel m)::tl) when is_unfolded m recfuns ->
753        let fixed_args = get_fixed_args m recfuns in
754        list_iter_default2 (fun x b -> if not b then aux k x) tl false fixed_args
755   | C.Rel m ->
756      (match List.nth context (m-1) with 
757      | _,C.Decl _ -> ()
758      | _,C.Def (bo,_) -> aux k (S.lift m bo))
759   | C.Meta _ -> ()
760   | C.Appl (C.Const ((Ref.Ref (_,uri,Ref.Fix (i,recno))) as r)::args) ->
761       if List.exists (fun t -> try aux k t;false with NotGuarded _ -> true) args
762       then
763       let fl,_,_ = E.get_checked_fixes_or_cofixes r in
764       let ctx_tys, bos = 
765         List.split (List.map (fun (_,name,_,ty,bo) -> (name, C.Decl ty), bo) fl)
766       in
767       let fl_len = List.length fl in
768       let bos = List.map (debruijn uri fl_len context) bos in
769       let j = List.fold_left min max_int (List.map (fun (_,_,i,_,_)->i) fl) in
770       let ctx_len = List.length context in
771         (* we may look for fixed params not only up to j ... *)
772       let fa = fixed_args bos j ctx_len (ctx_len + fl_len) in
773       list_iter_default2 (fun x b -> if not b then aux k x) args false fa; 
774       let context = context@ctx_tys in
775       let ctx_len = List.length context in
776       let extra_recfuns = 
777         HExtlib.list_mapi (fun _ i -> ctx_len - i, UnfFix fa) ctx_tys
778       in
779       let new_k = context, extra_recfuns@recfuns, x in
780       let bos_and_ks = 
781         HExtlib.list_mapi
782          (fun bo fno ->
783           let bo_and_k =
784             eat_or_subst_lambdas ~subst ~metasenv j bo fa args new_k
785           in
786            if
787             fno = i &&
788             List.length args > recno &&
789             (*case where the recursive argument is already really_smaller *)
790             is_really_smaller r_uri r_len ~subst ~metasenv k
791              (List.nth args recno)
792            then
793             let bo,(context, _, _ as new_k) = bo_and_k in
794             let bo, context' =
795              eat_lambdas ~subst ~metasenv context (recno + 1 - j) bo in
796             let new_context_part,_ =
797              HExtlib.split_nth (List.length context' - List.length context)
798               context' in
799             let k = List.fold_right shift_k new_context_part new_k in
800             let context, recfuns, x = k in
801             let k = context, (1,Safe)::recfuns, x in
802               bo,k
803            else
804             bo_and_k
805          ) bos
806       in
807        List.iter (fun (bo,k) -> aux k bo) bos_and_ks
808   | C.Match (Ref.Ref (_,uri,_) as ref,outtype,term,pl) as t ->
809      (match R.whd ~subst context term with
810      | C.Rel m | C.Appl (C.Rel m :: _ ) as t when is_safe m recfuns || m = x ->
811         (* TODO: add CoInd to references so that this call is useless *)
812         let isinductive, _, _, _, _ = E.get_checked_indtys ref in
813         if not isinductive then recursor aux k t
814         else
815          let ty = typeof ~subst ~metasenv context term in
816          let dc_ctx, dcl, start, stop = 
817            specialize_and_abstract_constrs ~subst r_uri r_len context ty in
818          let args = match t with C.Appl (_::tl) -> tl | _ -> [] in
819          aux k outtype; 
820          List.iter (aux k) args; 
821          List.iter2
822            (fun p (_,dc) ->
823              let rl = recursive_args ~subst ~metasenv dc_ctx start stop dc in
824              let p, k = get_new_safes ~subst k p rl in
825              aux k p) 
826            pl dcl
827      | _ -> recursor aux k t)
828   | t -> recursor aux k t
829   with
830    NotGuarded _ as exc ->
831     let t' = R.whd ~delta:0 ~subst context t in
832     if t = t' then raise exc
833     else aux k t'
834  in
835   try aux (context, recfuns, 1) t
836   with NotGuarded s -> raise (TypeCheckerFailure s)
837
838 and guarded_by_constructors ~subst ~metasenv context t indURI indlen nn =
839  let rec aux context n nn h te =
840   match R.whd ~subst context te with
841    | C.Rel m when m > n && m <= nn -> h
842    | C.Rel _ | C.Meta _ -> true
843    | C.Sort _
844    | C.Implicit _
845    | C.Prod _
846    | C.Const (Ref.Ref (_,_,Ref.Ind _))
847    | C.LetIn _ -> raise (AssertFailure (lazy "17"))
848    | C.Lambda (name,so,de) ->
849       does_not_occur ~subst context n nn so &&
850       aux ((name,C.Decl so)::context) (n + 1) (nn + 1) h de
851    | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
852       h && List.for_all (does_not_occur ~subst context n nn) tl
853    | C.Const (Ref.Ref (_,_,Ref.Con _)) -> true
854    | C.Appl (C.Const (Ref.Ref (_,uri, Ref.Con (_,j)) as ref) :: tl) as t ->
855       let _, paramsno, _, _, _ = E.get_checked_indtys ref in
856       let ty_t = typeof ~subst ~metasenv context t in
857       let dc_ctx, dcl, start, stop = 
858         specialize_and_abstract_constrs ~subst indURI indlen context ty_t in
859       let _, dc = List.nth dcl (j-1) in
860 (*
861         prerr_endline (PP.ppterm ~subst ~metasenv ~context:dc_ctx dc);
862         prerr_endline (PP.ppcontext ~subst ~metasenv dc_ctx);
863  *)
864       let rec_params = recursive_args ~subst ~metasenv dc_ctx start stop dc in
865       let rec analyse_instantiated_type rec_spec args =
866        match rec_spec, args with
867        | h::rec_spec, he::args -> 
868            aux context n nn h he && analyse_instantiated_type rec_spec args 
869        | _,[] -> true
870        | _ -> raise (AssertFailure (lazy 
871          ("Too many args for constructor: " ^ String.concat " "
872          (List.map (fun x-> PP.ppterm ~subst ~metasenv ~context x) args))))
873       in
874       let left, args = HExtlib.split_nth paramsno tl in
875       List.for_all (does_not_occur ~subst context n nn) left &&
876       analyse_instantiated_type rec_params args
877    | C.Appl ((C.Match (_,out,te,pl))::_) 
878    | C.Match (_,out,te,pl) as t ->
879        let tl = match t with C.Appl (_::tl) -> tl | _ -> [] in
880        List.for_all (does_not_occur ~subst context n nn) tl &&
881        does_not_occur ~subst context n nn out &&
882        does_not_occur ~subst context n nn te &&
883        List.for_all (aux context n nn h) pl
884    | C.Const (Ref.Ref (_,u,(Ref.Fix _| Ref.CoFix _)) as ref)
885    | C.Appl(C.Const (Ref.Ref(_,u,(Ref.Fix _| Ref.CoFix _)) as ref) :: _) as t ->
886       let tl = match t with C.Appl (_::tl) -> tl | _ -> [] in
887       let fl,_,_ = E.get_checked_fixes_or_cofixes ref in 
888       let len = List.length fl in
889       let tys = List.map (fun (_,n,_,ty,_) -> n, C.Decl ty) fl in
890       List.for_all (does_not_occur ~subst context n nn) tl &&
891       List.for_all
892        (fun (_,_,_,_,bo) ->
893           aux (context@tys) n nn h (debruijn u len context bo))
894        fl
895    | C.Const _
896    | C.Appl _ as t -> does_not_occur ~subst context n nn t
897  in
898    aux context 0 nn false t
899                                                                       
900 and recursive_args ~subst ~metasenv context n nn te =
901   match R.whd context te with
902   | C.Rel _ | C.Appl _ | C.Const _ -> []
903   | C.Prod (name,so,de) ->
904      (not (does_not_occur ~subst context n nn so)) ::
905       (recursive_args ~subst ~metasenv 
906         ((name,(C.Decl so))::context) (n+1) (nn + 1) de)
907   | t -> 
908      raise (AssertFailure (lazy ("recursive_args:" ^ PP.ppterm ~subst
909      ~metasenv ~context:[] t)))
910
911 and get_new_safes ~subst (context, recfuns, x as k) p rl =
912   match R.whd ~subst context p, rl with
913   | C.Lambda (name,so,ta), b::tl ->
914       let recfuns = (if b then [0,Safe] else []) @ recfuns in
915       get_new_safes ~subst 
916         (shift_k (name,(C.Decl so)) (context, recfuns, x)) ta tl
917   | C.Meta _ as e, _ | e, [] -> e, k
918   | _ -> raise (AssertFailure (lazy "Ill formed pattern"))
919
920 and is_really_smaller 
921   r_uri r_len ~subst ~metasenv (context, recfuns, x as k) te 
922 =
923  match R.whd ~subst context te with
924  | C.Rel m when is_safe m recfuns -> true
925  | C.Lambda (name, s, t) ->
926     is_really_smaller r_uri r_len ~subst ~metasenv (shift_k (name,C.Decl s) k) t
927  | C.Appl (he::_) ->
928     is_really_smaller r_uri r_len ~subst ~metasenv k he
929  | C.Rel _ 
930  | C.Const (Ref.Ref (_,_,Ref.Con _)) -> false
931  | C.Appl [] 
932  | C.Const (Ref.Ref (_,_,Ref.Fix _)) -> assert false
933  | C.Meta _ -> true 
934  | C.Match (Ref.Ref (_,uri,_) as ref,outtype,term,pl) ->
935     (match term with
936     | C.Rel m | C.Appl (C.Rel m :: _ ) when is_safe m recfuns || m = x ->
937         (* TODO: add CoInd to references so that this call is useless *)
938         let isinductive, _, _, _, _ = E.get_checked_indtys ref in
939         if not isinductive then
940           List.for_all (is_really_smaller r_uri r_len ~subst ~metasenv k) pl
941         else
942           let ty = typeof ~subst ~metasenv context term in
943           let dc_ctx, dcl, start, stop = 
944             specialize_and_abstract_constrs ~subst r_uri r_len context ty in
945           List.for_all2
946            (fun p (_,dc) -> 
947              let rl = recursive_args ~subst ~metasenv dc_ctx start stop dc in
948              let e, k = get_new_safes ~subst k p rl in
949              is_really_smaller r_uri r_len ~subst ~metasenv k e)
950            pl dcl
951     | _ -> List.for_all (is_really_smaller r_uri r_len ~subst ~metasenv k) pl)
952  | _ -> assert false
953
954 and returns_a_coinductive ~subst context ty =
955   match R.whd ~subst context ty with
956   | C.Const (Ref.Ref (_,uri,Ref.Ind _) as ref) 
957   | C.Appl (C.Const (Ref.Ref (_,uri,Ref.Ind _) as ref)::_) ->
958      let isinductive, _, itl, _, _ = E.get_checked_indtys ref in
959      if isinductive then None else (Some (uri,List.length itl))
960   | C.Prod (n,so,de) ->
961      returns_a_coinductive ~subst ((n,C.Decl so)::context) de
962   | _ -> None
963
964 and type_of_constant ((Ref.Ref (_,uri,_)) as ref) = 
965   match E.get_checked_obj uri, ref with
966   | (_,_,_,_,C.Inductive (_,_,tl,_)), Ref.Ref (_,_,Ref.Ind i)  ->
967       let _,_,arity,_ = List.nth tl i in arity
968   | (_,_,_,_,C.Inductive (_,_,tl,_)), Ref.Ref (_,_,Ref.Con (i,j))  ->
969       let _,_,_,cl = List.nth tl i in 
970       let _,_,arity = List.nth cl (j-1) in 
971       arity
972   | (_,_,_,_,C.Fixpoint (_,fl,_)), Ref.Ref (_,_,(Ref.Fix (i,_)|Ref.CoFix i)) ->
973       let _,_,_,arity,_ = List.nth fl i in
974       arity
975   | (_,_,_,_,C.Constant (_,_,_,ty,_)), Ref.Ref (_,_,(Ref.Def |Ref.Decl)) -> ty
976   | _ -> raise (AssertFailure (lazy "type_of_constant: environment/reference"))
977 ;;
978
979 let typecheck_obj (uri,height,metasenv,subst,kind) =
980  (* CSC: here we should typecheck the metasenv and the subst *)
981  assert (metasenv = [] && subst = []);
982  match kind with
983    | C.Constant (_,_,Some te,ty,_) ->
984       let _ = typeof ~subst ~metasenv [] ty in
985       let ty_te = typeof ~subst ~metasenv [] te in
986       if not (R.are_convertible ~subst ~metasenv [] ty_te ty) then
987        raise (TypeCheckerFailure (lazy (Printf.sprintf (
988         "the type of the body is not convertible with the declared one.\n"^^
989         "inferred type:\n%s\nexpected type:\n%s")
990         (PP.ppterm ~subst ~metasenv ~context:[] ty_te) 
991         (PP.ppterm ~subst ~metasenv ~context:[] ty))))
992    | C.Constant (_,_,None,ty,_) -> ignore (typeof ~subst ~metasenv [] ty)
993    | C.Inductive (is_ind, leftno, tyl, _) -> 
994        check_mutual_inductive_defs uri ~metasenv ~subst is_ind leftno tyl
995    | C.Fixpoint (inductive,fl,_) ->
996       let types, kl =
997         List.fold_left
998          (fun (types,kl) (_,name,k,ty,_) ->
999            let _ = typeof ~subst ~metasenv [] ty in
1000             ((name,C.Decl ty)::types, k::kl)
1001          ) ([],[]) fl
1002       in
1003       let len = List.length types in
1004       let dfl, kl =   
1005         List.split (List.map2 
1006           (fun (_,_,_,_,bo) rno -> 
1007              let dbo = debruijn uri len [] bo in
1008              dbo, Evil rno)
1009           fl kl)
1010       in
1011       List.iter2 (fun (_,name,x,ty,_) bo ->
1012        let ty_bo = typeof ~subst ~metasenv types bo in
1013        if not (R.are_convertible ~subst ~metasenv types ty_bo ty)
1014        then raise (TypeCheckerFailure (lazy ("(Co)Fix: ill-typed bodies")))
1015        else
1016         if inductive then begin
1017           let m, context = eat_lambdas ~subst ~metasenv types (x + 1) bo in
1018           let r_uri, r_len =
1019             let he =
1020              match List.hd context with _,C.Decl t -> t | _ -> assert false
1021             in
1022             match R.whd ~subst (List.tl context) he with
1023             | C.Const (Ref.Ref (_,uri,Ref.Ind _) as ref)
1024             | C.Appl (C.Const (Ref.Ref (_,uri,Ref.Ind _) as ref) :: _) ->
1025                 let _,_,itl,_,_ = E.get_checked_indtys ref in
1026                   uri, List.length itl
1027             | _ -> assert false
1028           in
1029           (* guarded by destructors conditions D{f,k,x,M} *)
1030           let rec enum_from k = 
1031             function [] -> [] | v::tl -> (k,v)::enum_from (k+1) tl 
1032           in
1033           guarded_by_destructors r_uri r_len 
1034            ~subst ~metasenv context (enum_from (x+2) kl) m
1035         end else
1036          match returns_a_coinductive ~subst [] ty with
1037           | None ->
1038              raise (TypeCheckerFailure
1039                (lazy "CoFix: does not return a coinductive type"))
1040           | Some (r_uri, r_len) ->
1041              (* guarded by constructors conditions C{f,M} *)
1042              if not 
1043              (guarded_by_constructors ~subst ~metasenv types bo r_uri r_len len)
1044              then
1045                raise (TypeCheckerFailure
1046                 (lazy "CoFix: not guarded by constructors"))
1047         ) fl dfl
1048 ;;
1049
1050 (* trust *)
1051
1052 let trust = ref  (fun _ -> true);;
1053 let set_trust f = trust := f
1054 let trust_obj obj = !trust obj
1055
1056
1057 (* web interface stuff *)
1058
1059 let logger = 
1060  ref (function (`Start_type_checking _|`Type_checking_completed _|`Type_checking_interrupted _|`Type_checking_failed _|`Trust_obj _) -> ())
1061 ;;
1062
1063 let set_logger f = logger := f;;
1064
1065 let typecheck_obj obj =
1066  let u,_,_,_,_ = obj in
1067  try
1068   !logger (`Start_type_checking u);
1069   typecheck_obj obj;
1070   !logger (`Type_checking_completed u)
1071  with
1072     Sys.Break as e ->
1073      !logger (`Type_checking_interrupted u);
1074      raise e
1075   | e ->
1076      !logger (`Type_checking_failed u);
1077      raise e
1078 ;;
1079
1080 E.set_typecheck_obj
1081  (fun obj ->
1082    if trust_obj obj then
1083     let u,_,_,_,_ = obj in
1084      !logger (`Trust_obj u)
1085    else
1086     typecheck_obj obj)
1087 ;;
1088
1089 (* EOF *)