]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_kernel/nCicTypeChecker.ml
4679de20a047f9f7685a8059cf57e05727f69c62
[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 exception TypeCheckerFailure of string Lazy.t
15 exception AssertFailure of string Lazy.t
16
17 let shift_k e (c,rf,x,safes) =
18   e::c,List.map (fun (k,v) -> k+1,v) rf,x+1,List.map ((+)1) safes
19 ;;
20
21 (* $Id: cicTypeChecker.ml 8213 2008-03-13 18:48:26Z sacerdot $ *)
22
23 (*
24 exception CicEnvironmentError;;
25
26 (*CSC l'indice x dei tipi induttivi e' t.c. n < x <= nn *)
27 (*CSC questa funzione e' simile alla are_all_occurrences_positive, ma fa *)
28 (*CSC dei controlli leggermente diversi. Viene invocata solamente dalla  *)
29 (*CSC strictly_positive                                                  *)
30 (*CSC definizione (giusta???) tratta dalla mail di Hugo ;-)              *)
31 and weakly_positive context n nn uri te =
32  let module C = Cic in
33 (*CSC: Che schifo! Bisogna capire meglio e trovare una soluzione ragionevole!*)
34   let dummy_mutind =
35    C.MutInd (HelmLibraryObjects.Datatypes.nat_URI,0,[])
36   in
37   (*CSC: mettere in cicSubstitution *)
38   let rec subst_inductive_type_with_dummy_mutind =
39    function
40       C.MutInd (uri',0,_) when UriManager.eq uri' uri ->
41        dummy_mutind
42     | C.Appl ((C.MutInd (uri',0,_))::tl) when UriManager.eq uri' uri ->
43        dummy_mutind
44     | C.Cast (te,ty) -> subst_inductive_type_with_dummy_mutind te
45     | C.Prod (name,so,ta) ->
46        C.Prod (name, subst_inductive_type_with_dummy_mutind so,
47         subst_inductive_type_with_dummy_mutind ta)
48     | C.Lambda (name,so,ta) ->
49        C.Lambda (name, subst_inductive_type_with_dummy_mutind so,
50         subst_inductive_type_with_dummy_mutind ta)
51     | C.Appl tl ->
52        C.Appl (List.map subst_inductive_type_with_dummy_mutind tl)
53     | C.MutCase (uri,i,outtype,term,pl) ->
54        C.MutCase (uri,i,
55         subst_inductive_type_with_dummy_mutind outtype,
56         subst_inductive_type_with_dummy_mutind term,
57         List.map subst_inductive_type_with_dummy_mutind pl)
58     | C.Fix (i,fl) ->
59        C.Fix (i,List.map (fun (name,i,ty,bo) -> (name,i,
60         subst_inductive_type_with_dummy_mutind ty,
61         subst_inductive_type_with_dummy_mutind bo)) fl)
62     | C.CoFix (i,fl) ->
63        C.CoFix (i,List.map (fun (name,ty,bo) -> (name,
64         subst_inductive_type_with_dummy_mutind ty,
65         subst_inductive_type_with_dummy_mutind bo)) fl)
66     | C.Const (uri,exp_named_subst) ->
67        let exp_named_subst' =
68         List.map
69          (function (uri,t) -> (uri,subst_inductive_type_with_dummy_mutind t))
70          exp_named_subst
71        in
72         C.Const (uri,exp_named_subst')
73     | C.MutInd (uri,typeno,exp_named_subst) ->
74        let exp_named_subst' =
75         List.map
76          (function (uri,t) -> (uri,subst_inductive_type_with_dummy_mutind t))
77          exp_named_subst
78        in
79         C.MutInd (uri,typeno,exp_named_subst')
80     | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
81        let exp_named_subst' =
82         List.map
83          (function (uri,t) -> (uri,subst_inductive_type_with_dummy_mutind t))
84          exp_named_subst
85        in
86         C.MutConstruct (uri,typeno,consno,exp_named_subst')
87     | t -> t
88   in
89   match CicReduction.whd context te with
90 (*
91      C.Appl ((C.MutInd (uri',0,_))::tl) when UriManager.eq uri' uri -> true
92 *)
93      C.Appl ((C.MutInd (uri',_,_))::tl) when UriManager.eq uri' uri -> true
94    | C.MutInd (uri',0,_) when UriManager.eq uri' uri -> true
95    | C.Prod (C.Anonymous,source,dest) ->
96       strictly_positive context n nn
97        (subst_inductive_type_with_dummy_mutind source) &&
98        weakly_positive ((Some (C.Anonymous,(C.Decl source)))::context)
99         (n + 1) (nn + 1) uri dest
100    | C.Prod (name,source,dest) when
101       does_not_occur ((Some (name,(C.Decl source)))::context) 0 n dest ->
102        (* dummy abstraction, so we behave as in the anonimous case *)
103        strictly_positive context n nn
104         (subst_inductive_type_with_dummy_mutind source) &&
105          weakly_positive ((Some (name,(C.Decl source)))::context)
106          (n + 1) (nn + 1) uri dest
107    | C.Prod (name,source,dest) ->
108        does_not_occur context n nn
109          (subst_inductive_type_with_dummy_mutind source)&&
110          weakly_positive ((Some (name,(C.Decl source)))::context)
111          (n + 1) (nn + 1) uri dest
112    | _ ->
113      raise (TypeCheckerFailure (lazy "Malformed inductive constructor type"))
114
115 (* instantiate_parameters ps (x1:T1)...(xn:Tn)C                             *)
116 (* returns ((x_|ps|:T_|ps|)...(xn:Tn)C){ps_1 / x1 ; ... ; ps_|ps| / x_|ps|} *)
117 and instantiate_parameters params c =
118  let module C = Cic in
119   match (c,params) with
120      (c,[]) -> c
121    | (C.Prod (_,_,ta), he::tl) ->
122        instantiate_parameters tl
123         (CicSubstitution.subst he ta)
124    | (C.Cast (te,_), _) -> instantiate_parameters params te
125    | (t,l) -> raise (AssertFailure (lazy "1"))
126
127 and strictly_positive context n nn te =
128  let module C = Cic in
129  let module U = UriManager in
130   match CicReduction.whd context te with
131    | t when does_not_occur context n nn t -> true
132    | C.Rel _ -> true
133    | C.Cast (te,ty) ->
134       (*CSC: bisogna controllare ty????*)
135       strictly_positive context n nn te
136    | C.Prod (name,so,ta) ->
137       does_not_occur context n nn so &&
138        strictly_positive ((Some (name,(C.Decl so)))::context) (n+1) (nn+1) ta
139    | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
140       List.fold_right (fun x i -> i && does_not_occur context n nn x) tl true
141    | C.Appl ((C.MutInd (uri,i,exp_named_subst))::tl) -> 
142       let (ok,paramsno,ity,cl,name) =
143         let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
144           match o with
145               C.InductiveDefinition (tl,_,paramsno,_) ->
146                 let (name,_,ity,cl) = List.nth tl i in
147                 (List.length tl = 1, paramsno, ity, cl, name) 
148                 (* (true, paramsno, ity, cl, name) *)
149             | _ ->
150                 raise 
151                   (TypeCheckerFailure
152                      (lazy ("Unknown inductive type:" ^ U.string_of_uri uri)))
153       in 
154       let (params,arguments) = split tl paramsno in
155       let lifted_params = List.map (CicSubstitution.lift 1) params in
156       let cl' =
157         List.map
158           (fun (_,te) ->
159              instantiate_parameters lifted_params
160                (CicSubstitution.subst_vars exp_named_subst te)
161           ) cl
162       in
163         ok &&
164           List.fold_right
165           (fun x i -> i && does_not_occur context n nn x)
166           arguments true &&
167          (*CSC: MEGAPATCH3 (sara' quella giusta?)*)
168           List.fold_right
169           (fun x i ->
170              i &&
171                weakly_positive
172                ((Some (C.Name name,(Cic.Decl ity)))::context) (n+1) (nn+1) uri
173                x
174           ) cl' true
175    | t -> false
176        
177 (* the inductive type indexes are s.t. n < x <= nn *)
178 and are_all_occurrences_positive context uri indparamsno i n nn te =
179  let module C = Cic in
180   match CicReduction.whd context te with
181      C.Appl ((C.Rel m)::tl) when m = i ->
182       (*CSC: riscrivere fermandosi a 0 *)
183       (* let's check if the inductive type is applied at least to *)
184       (* indparamsno parameters                                   *)
185       let last =
186        List.fold_left
187         (fun k x ->
188           if k = 0 then 0
189           else
190            match CicReduction.whd context x with
191               C.Rel m when m = n - (indparamsno - k) -> k - 1
192             | _ ->
193               raise (TypeCheckerFailure
194                (lazy 
195                ("Non-positive occurence in mutual inductive definition(s) [1]" ^
196                 UriManager.string_of_uri uri)))
197         ) indparamsno tl
198       in
199        if last = 0 then
200         List.fold_right (fun x i -> i && does_not_occur context n nn x) tl true
201        else
202         raise (TypeCheckerFailure
203          (lazy ("Non-positive occurence in mutual inductive definition(s) [2]"^
204           UriManager.string_of_uri uri)))
205    | C.Rel m when m = i ->
206       if indparamsno = 0 then
207        true
208       else
209         raise (TypeCheckerFailure
210          (lazy ("Non-positive occurence in mutual inductive definition(s) [3]"^
211           UriManager.string_of_uri uri)))
212    | C.Prod (C.Anonymous,source,dest) ->
213        let b = strictly_positive context n nn source in
214        b &&
215        are_all_occurrences_positive
216         ((Some (C.Anonymous,(C.Decl source)))::context) uri indparamsno
217         (i+1) (n + 1) (nn + 1) dest
218    | C.Prod (name,source,dest) when
219       does_not_occur ((Some (name,(C.Decl source)))::context) 0 n dest ->
220       (* dummy abstraction, so we behave as in the anonimous case *)
221       strictly_positive context n nn source &&
222        are_all_occurrences_positive
223         ((Some (name,(C.Decl source)))::context) uri indparamsno
224         (i+1) (n + 1) (nn + 1) dest
225    | C.Prod (name,source,dest) ->
226       does_not_occur context n nn source &&
227        are_all_occurrences_positive ((Some (name,(C.Decl source)))::context)
228         uri indparamsno (i+1) (n + 1) (nn + 1) dest
229    | _ ->
230      raise
231       (TypeCheckerFailure (lazy ("Malformed inductive constructor type " ^
232         (UriManager.string_of_uri uri))))
233
234 (* Main function to checks the correctness of a mutual *)
235 (* inductive block definition. This is the function    *)
236 (* exported to the proof-engine.                       *)
237 and typecheck_mutual_inductive_defs ~logger uri (itl,_,indparamsno) ugraph =
238  let module U = UriManager in
239   (* let's check if the arity of the inductive types are well *)
240   (* formed                                                   *)
241   let ugrap1 = List.fold_left 
242    (fun ugraph (_,_,x,_) -> let _,ugraph' = 
243       type_of ~logger x ugraph in ugraph') 
244    ugraph itl in
245
246   (* let's check if the types of the inductive constructors  *)
247   (* are well formed.                                        *)
248   (* In order not to use type_of_aux we put the types of the *)
249   (* mutual inductive types at the head of the types of the  *)
250   (* constructors using Prods                                *)
251   let len = List.length itl in
252   let tys =
253     List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) itl in
254   let _,ugraph2 =
255     List.fold_right
256       (fun (_,_,_,cl) (i,ugraph) ->
257         let ugraph'' = 
258           List.fold_left
259             (fun ugraph (name,te) -> 
260               let debruijnedte = debruijn_constructor uri len te in
261               let augmented_term =
262                 List.fold_right
263                   (fun (name,_,ty,_) i -> Cic.Prod (Cic.Name name, ty, i))
264                   itl debruijnedte
265               in
266               let _,ugraph' = type_of ~logger augmented_term ugraph in
267               (* let's check also the positivity conditions *)
268               if
269                 not
270                   (are_all_occurrences_positive tys uri indparamsno i 0 len
271                      debruijnedte)
272               then
273                 begin
274                 prerr_endline (UriManager.string_of_uri uri);
275                 prerr_endline (string_of_int (List.length tys));
276                 raise
277                   (TypeCheckerFailure
278                     (lazy ("Non positive occurence in " ^ U.string_of_uri uri)))                end 
279               else
280                 ugraph'
281             ) ugraph cl in
282         (i + 1),ugraph''
283       ) itl (1,ugrap1)
284   in
285   ugraph2
286
287 (* Main function to checks the correctness of a mutual *)
288 (* inductive block definition.                         *)
289 and check_mutual_inductive_defs uri obj ugraph =
290   match obj with
291       Cic.InductiveDefinition (itl, params, indparamsno, _) ->
292         typecheck_mutual_inductive_defs uri (itl,params,indparamsno) ugraph 
293     | _ ->
294         raise (TypeCheckerFailure (
295                 lazy ("Unknown mutual inductive definition:" ^
296                  UriManager.string_of_uri uri)))
297
298 (* the boolean h means already protected *)
299 (* args is the list of arguments the type of the constructor that may be *)
300 (* found in head position must be applied to.                            *)
301 and guarded_by_constructors ~subst context n nn h te args coInductiveTypeURI =
302  let module C = Cic in
303   (*CSC: There is a lot of code replication between the cases X and    *)
304   (*CSC: (C.Appl X tl). Maybe it will be better to define a function   *)
305   (*CSC: that maps X into (C.Appl X []) when X is not already a C.Appl *)
306   match CicReduction.whd ~subst context te with
307      C.Rel m when m > n && m <= nn -> h
308    | C.Rel _ -> true
309    | C.Meta _
310    | C.Sort _
311    | C.Implicit _
312    | C.Cast _
313    | C.Prod _
314    | C.LetIn _ ->
315       (* the term has just been type-checked *)
316       raise (AssertFailure (lazy "17"))
317    | C.Lambda (name,so,de) ->
318       does_not_occur ~subst context n nn so &&
319        guarded_by_constructors ~subst ((Some (name,(C.Decl so)))::context)
320         (n + 1) (nn + 1) h de args coInductiveTypeURI
321    | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
322       h &&
323        List.fold_right (fun x i -> i && does_not_occur ~subst context n nn x) tl true
324    | C.Appl ((C.MutConstruct (uri,i,j,exp_named_subst))::tl) ->
325       let consty =
326         let obj,_ = 
327           try 
328             CicEnvironment.get_cooked_obj ~trust:false CicUniv.empty_ugraph uri
329           with Not_found -> assert false
330         in
331        match obj with
332           C.InductiveDefinition (itl,_,_,_) ->
333            let (_,_,_,cl) = List.nth itl i in
334             let (_,cons) = List.nth cl (j - 1) in
335              CicSubstitution.subst_vars exp_named_subst cons
336         | _ ->
337             raise (TypeCheckerFailure
338              (lazy ("Unknown mutual inductive definition:" ^ UriManager.string_of_uri uri)))
339       in
340        let rec analyse_branch context ty te =
341         match CicReduction.whd ~subst context ty with
342            C.Meta _ -> raise (AssertFailure (lazy "34"))
343          | C.Rel _
344          | C.Var _
345          | C.Sort _ ->
346             does_not_occur ~subst context n nn te
347          | C.Implicit _
348          | C.Cast _ ->
349             raise (AssertFailure (lazy "24"))(* due to type-checking *)
350          | C.Prod (name,so,de) ->
351             analyse_branch ((Some (name,(C.Decl so)))::context) de te
352          | C.Lambda _
353          | C.LetIn _ ->
354             raise (AssertFailure (lazy "25"))(* due to type-checking *)
355          | C.Appl ((C.MutInd (uri,_,_))::_) when uri == coInductiveTypeURI -> 
356              guarded_by_constructors ~subst context n nn true te []
357               coInductiveTypeURI
358          | C.Appl ((C.MutInd (uri,_,_))::_) -> 
359             guarded_by_constructors ~subst context n nn true te tl
360              coInductiveTypeURI
361          | C.Appl _ ->
362             does_not_occur ~subst context n nn te
363          | C.Const _ -> raise (AssertFailure (lazy "26"))
364          | C.MutInd (uri,_,_) when uri == coInductiveTypeURI ->
365             guarded_by_constructors ~subst context n nn true te []
366              coInductiveTypeURI
367          | C.MutInd _ ->
368             does_not_occur ~subst context n nn te
369          | C.MutConstruct _ -> raise (AssertFailure (lazy "27"))
370          (*CSC: we do not consider backbones with a MutCase, Fix, Cofix *)
371          (*CSC: in head position.                                       *)
372          | C.MutCase _
373          | C.Fix _
374          | C.CoFix _ ->
375             raise (AssertFailure (lazy "28"))(* due to type-checking *)
376        in
377        let rec analyse_instantiated_type context ty l =
378         match CicReduction.whd ~subst context ty with
379            C.Rel _
380          | C.Var _
381          | C.Meta _
382          | C.Sort _
383          | C.Implicit _
384          | C.Cast _ -> raise (AssertFailure (lazy "29"))(* due to type-checking *)
385          | C.Prod (name,so,de) ->
386             begin
387              match l with
388                 [] -> true
389               | he::tl ->
390                  analyse_branch context so he &&
391                   analyse_instantiated_type
392                    ((Some (name,(C.Decl so)))::context) de tl
393             end
394          | C.Lambda _
395          | C.LetIn _ ->
396             raise (AssertFailure (lazy "30"))(* due to type-checking *)
397          | C.Appl _ -> 
398             List.fold_left
399              (fun i x -> i && does_not_occur ~subst context n nn x) true l
400          | C.Const _ -> raise (AssertFailure (lazy "31"))
401          | C.MutInd _ ->
402             List.fold_left
403              (fun i x -> i && does_not_occur ~subst context n nn x) true l
404          | C.MutConstruct _ -> raise (AssertFailure (lazy "32"))
405          (*CSC: we do not consider backbones with a MutCase, Fix, Cofix *)
406          (*CSC: in head position.                                       *)
407          | C.MutCase _
408          | C.Fix _
409          | C.CoFix _ ->
410             raise (AssertFailure (lazy "33"))(* due to type-checking *)
411        in
412         let rec instantiate_type args consty =
413          function
414             [] -> true
415           | tlhe::tltl as l ->
416              let consty' = CicReduction.whd ~subst context consty in
417               match args with 
418                  he::tl ->
419                   begin
420                    match consty' with
421                       C.Prod (_,_,de) ->
422                        let instantiated_de = CicSubstitution.subst he de in
423                         (*CSC: siamo sicuri che non sia troppo forte? *)
424                         does_not_occur ~subst context n nn tlhe &
425                          instantiate_type tl instantiated_de tltl
426                     | _ ->
427                       (*CSC:We do not consider backbones with a MutCase, a    *)
428                       (*CSC:FixPoint, a CoFixPoint and so on in head position.*)
429                       raise (AssertFailure (lazy "23"))
430                   end
431                | [] -> analyse_instantiated_type context consty' l
432                   (* These are all the other cases *)
433        in
434         instantiate_type args consty tl
435    | C.Appl ((C.CoFix (_,fl))::tl) ->
436       List.fold_left (fun i x -> i && does_not_occur ~subst context n nn x) true tl &&
437        let len = List.length fl in
438         let n_plus_len = n + len
439         and nn_plus_len = nn + len
440         (*CSC: Is a Decl of the ty ok or should I use Def of a Fix? *)
441         and tys,_ =
442           List.fold_left
443             (fun (types,len) (n,ty,_) ->
444                (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
445                 len+1)
446             ) ([],0) fl
447         in
448          List.fold_right
449           (fun (_,ty,bo) i ->
450             i && does_not_occur ~subst context n nn ty &&
451              guarded_by_constructors ~subst (tys@context) n_plus_len nn_plus_len
452               h bo args coInductiveTypeURI
453           ) fl true
454    | C.Appl ((C.MutCase (_,_,out,te,pl))::tl) ->
455        List.fold_left (fun i x -> i && does_not_occur ~subst context n nn x) true tl &&
456         does_not_occur ~subst context n nn out &&
457          does_not_occur ~subst context n nn te &&
458           List.fold_right
459            (fun x i ->
460              i &&
461              guarded_by_constructors ~subst context n nn h x args
462               coInductiveTypeURI
463            ) pl true
464    | C.Appl l ->
465       List.fold_right (fun x i -> i && does_not_occur ~subst context n nn x) l true
466    | C.Var (_,exp_named_subst)
467    | C.Const (_,exp_named_subst) ->
468       List.fold_right
469        (fun (_,x) i -> i && does_not_occur ~subst context n nn x) exp_named_subst true
470    | C.MutInd _ -> assert false
471    | C.MutConstruct (_,_,_,exp_named_subst) ->
472       List.fold_right
473        (fun (_,x) i -> i && does_not_occur ~subst context n nn x) exp_named_subst true
474    | C.MutCase (_,_,out,te,pl) ->
475        does_not_occur ~subst context n nn out &&
476         does_not_occur ~subst context n nn te &&
477          List.fold_right
478           (fun x i ->
479             i &&
480              guarded_by_constructors ~subst context n nn h x args
481               coInductiveTypeURI
482           ) pl true
483    | C.Fix (_,fl) ->
484       let len = List.length fl in
485        let n_plus_len = n + len
486        and nn_plus_len = nn + len
487        (*CSC: Is a Decl of the ty ok or should I use Def of a Fix? *)
488        and tys,_ =
489         List.fold_left
490           (fun (types,len) (n,_,ty,_) ->
491              (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
492               len+1)
493           ) ([],0) fl
494        in
495         List.fold_right
496          (fun (_,_,ty,bo) i ->
497            i && does_not_occur ~subst context n nn ty &&
498             does_not_occur ~subst (tys@context) n_plus_len nn_plus_len bo
499          ) fl true
500    | C.CoFix (_,fl) ->
501       let len = List.length fl in
502        let n_plus_len = n + len
503        and nn_plus_len = nn + len
504        (*CSC: Is a Decl of the ty ok or should I use Def of a Fix? *)
505        and tys,_ =
506         List.fold_left
507           (fun (types,len) (n,ty,_) ->
508              (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
509               len+1)
510           ) ([],0) fl
511        in
512         List.fold_right
513          (fun (_,ty,bo) i ->
514            i && does_not_occur ~subst context n nn ty &&
515             guarded_by_constructors ~subst (tys@context) n_plus_len nn_plus_len
516              h bo
517              args coInductiveTypeURI
518          ) fl true
519
520 and type_of_branch ~subst context argsno need_dummy outtype term constype =
521  let module C = Cic in
522  let module R = CicReduction in
523   match R.whd ~subst context constype with
524      C.MutInd (_,_,_) ->
525       if need_dummy then
526        outtype
527       else
528        C.Appl [outtype ; term]
529    | C.Appl (C.MutInd (_,_,_)::tl) ->
530       let (_,arguments) = split tl argsno
531       in
532        if need_dummy && arguments = [] then
533         outtype
534        else
535         C.Appl (outtype::arguments@(if need_dummy then [] else [term]))
536    | C.Prod (name,so,de) ->
537       let term' =
538        match CicSubstitution.lift 1 term with
539           C.Appl l -> C.Appl (l@[C.Rel 1])
540         | t -> C.Appl [t ; C.Rel 1]
541       in
542        C.Prod (name,so,type_of_branch ~subst
543         ((Some (name,(C.Decl so)))::context) argsno need_dummy
544         (CicSubstitution.lift 1 outtype) term' de)
545    | _ -> raise (AssertFailure (lazy "20"))
546
547  and returns_a_coinductive ~subst context ty =
548   let module C = Cic in
549    match CicReduction.whd ~subst context ty with
550       C.MutInd (uri,i,_) ->
551        (*CSC: definire una funzioncina per questo codice sempre replicato *)
552         let obj,_ =
553           try
554             CicEnvironment.get_cooked_obj ~trust:false CicUniv.empty_ugraph uri
555           with Not_found -> assert false
556         in
557         (match obj with
558            C.InductiveDefinition (itl,_,_,_) ->
559             let (_,is_inductive,_,_) = List.nth itl i in
560              if is_inductive then None else (Some uri)
561          | _ ->
562             raise (TypeCheckerFailure
563               (lazy ("Unknown mutual inductive definition:" ^
564               UriManager.string_of_uri uri)))
565         )
566     | C.Appl ((C.MutInd (uri,i,_))::_) ->
567        (let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
568          match o with
569            C.InductiveDefinition (itl,_,_,_) ->
570             let (_,is_inductive,_,_) = List.nth itl i in
571              if is_inductive then None else (Some uri)
572          | _ ->
573             raise (TypeCheckerFailure
574               (lazy ("Unknown mutual inductive definition:" ^
575               UriManager.string_of_uri uri)))
576         )
577     | C.Prod (n,so,de) ->
578        returns_a_coinductive ~subst ((Some (n,C.Decl so))::context) de
579     | _ -> None
580
581  in
582   type_of_aux ~logger context t ugraph
583
584 ;;
585
586 (** wrappers which instantiate fresh loggers *)
587
588 (* check_allowed_sort_elimination uri i s1 s2
589    This function is used outside the kernel to determine in advance whether
590    a MutCase will be allowed or not.
591    [uri,i] is the type of the term to match
592    [s1] is the sort of the term to eliminate (i.e. the head of the arity
593         of the inductive type [uri,i])
594    [s2] is the sort of the goal (i.e. the head of the type of the outtype
595         of the MutCase) *)
596 let check_allowed_sort_elimination uri i s1 s2 =
597  fst (check_allowed_sort_elimination ~subst:[] ~metasenv:[]
598   ~logger:(new CicLogger.logger) [] uri i true
599   (Cic.Implicit None) (* never used *) (Cic.Sort s1) (Cic.Sort s2)
600   CicUniv.empty_ugraph)
601 ;;
602
603 Deannotate.type_of_aux' := fun context t -> fst (type_of_aux' [] context t CicUniv.oblivion_ugraph);;
604
605 *)
606
607 module C = NCic 
608 module R = NCicReduction
609 module Ref = NReference
610 module S = NCicSubstitution 
611 module U = NCicUtils
612 module E = NCicEnvironment
613
614 let rec split_prods ~subst context n te =
615   match (n, R.whd ~subst context te) with
616    | (0, _) -> context,te
617    | (n, C.Prod (name,so,ta)) when n > 0 ->
618        split_prods ~subst ((name,(C.Decl so))::context) (n - 1) ta
619    | (_, _) -> raise (AssertFailure (lazy "split_prods"))
620 ;;
621
622 let debruijn_constructor ?(cb=fun _ _ -> ()) uri number_of_types t = assert false
623 (*
624  let rec aux k t =
625   let module C = Cic in
626   let res =
627    match t with
628       C.Rel n as t when n <= k -> t
629     | C.Rel _ ->
630         raise (TypeCheckerFailure (lazy "unbound variable found in constructor type"))
631     | C.Var (uri,exp_named_subst) ->
632        let exp_named_subst' = 
633         List.map (function (uri,t) -> (uri,aux k t)) exp_named_subst
634        in
635         C.Var (uri,exp_named_subst')
636     | C.Meta (i,l) ->
637        let l' = List.map (function None -> None | Some t -> Some (aux k t)) l in
638         C.Meta (i,l')
639     | C.Sort _
640     | C.Implicit _ as t -> t
641     | C.Cast (te,ty) -> C.Cast (aux k te, aux k ty)
642     | C.Prod (n,s,t) -> C.Prod (n, aux k s, aux (k+1) t)
643     | C.Lambda (n,s,t) -> C.Lambda (n, aux k s, aux (k+1) t)
644     | C.LetIn (n,s,ty,t) -> C.LetIn (n, aux k s, aux k ty, aux (k+1) t)
645     | C.Appl l -> C.Appl (List.map (aux k) l)
646     | C.Const (uri,exp_named_subst) ->
647        let exp_named_subst' = 
648         List.map (function (uri,t) -> (uri,aux k t)) exp_named_subst
649        in
650         C.Const (uri,exp_named_subst')
651     | C.MutInd (uri',tyno,exp_named_subst) when UriManager.eq uri uri' ->
652        if exp_named_subst != [] then
653         raise (TypeCheckerFailure
654           (lazy ("non-empty explicit named substitution is applied to "^
655            "a mutual inductive type which is being defined"))) ;
656        C.Rel (k + number_of_types - tyno) ;
657     | C.MutInd (uri',tyno,exp_named_subst) ->
658        let exp_named_subst' = 
659         List.map (function (uri,t) -> (uri,aux k t)) exp_named_subst
660        in
661         C.MutInd (uri',tyno,exp_named_subst')
662     | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
663        let exp_named_subst' = 
664         List.map (function (uri,t) -> (uri,aux k t)) exp_named_subst
665        in
666         C.MutConstruct (uri,tyno,consno,exp_named_subst')
667     | C.MutCase (sp,i,outty,t,pl) ->
668        C.MutCase (sp, i, aux k outty, aux k t,
669         List.map (aux k) pl)
670     | C.Fix (i, fl) ->
671        let len = List.length fl in
672        let liftedfl =
673         List.map
674          (fun (name, i, ty, bo) -> (name, i, aux k ty, aux (k+len) bo))
675           fl
676        in
677         C.Fix (i, liftedfl)
678     | C.CoFix (i, fl) ->
679        let len = List.length fl in
680        let liftedfl =
681         List.map
682          (fun (name, ty, bo) -> (name, aux k ty, aux (k+len) bo))
683           fl
684        in
685         C.CoFix (i, liftedfl)
686   in
687    cb t res;
688    res
689  in
690   aux 0*)
691 ;;
692
693
694 let sort_of_prod ~subst context (name,s) (t1, t2) =
695    let t1 = R.whd ~subst context t1 in
696    let t2 = R.whd ~subst ((name,C.Decl s)::context) t2 in
697    match t1, t2 with
698    | C.Sort s1, C.Sort C.Prop -> t2
699    | C.Sort (C.Type u1), C.Sort (C.Type u2) -> C.Sort (C.Type (max u1 u2)) 
700    | C.Sort _,C.Sort (C.Type _) -> t2
701    | C.Sort (C.Type _) , C.Sort C.CProp -> t1
702    | C.Sort _, C.Sort C.CProp -> t2
703    | C.Meta _, C.Sort _
704    | C.Meta _, C.Meta _
705    | C.Sort _, C.Meta _ when U.is_closed t2 -> t2
706    | _ -> 
707       raise (TypeCheckerFailure (lazy (Printf.sprintf
708         "Prod: expected two sorts, found = %s, %s" 
709          (NCicPp.ppterm t1) (NCicPp.ppterm t2))))
710 ;;
711
712 let eat_prods ~subst ~metasenv context ty_he args_with_ty = 
713   let rec aux ty_he = function 
714   | [] -> ty_he
715   | (arg, ty_arg)::tl ->
716       (match R.whd ~subst context ty_he with 
717       | C.Prod (n,s,t) ->
718           if R.are_convertible ~subst ~metasenv context ty_arg s then
719             aux (S.subst ~avoid_beta_redexes:true arg t) tl
720           else
721             raise 
722               (TypeCheckerFailure 
723                 (lazy (Printf.sprintf
724                   ("Appl: wrong parameter-type, expected %s, found %s")
725                   (NCicPp.ppterm ty_arg) (NCicPp.ppterm s))))
726        | _ ->
727           raise 
728             (TypeCheckerFailure
729               (lazy "Appl: this is not a function, it cannot be applied")))
730   in
731     aux ty_he args_with_ty
732 ;;
733
734 let fix_lefts_in_constrs ~subst paramsno tyl i =
735   let len = List.length tyl in
736   let _,_,arity,cl = List.nth tyl i in
737   let tys = List.map (fun (_,n,ty,_) -> n,C.Decl ty) tyl in
738   let cl' =
739    List.map
740     (fun (_,id,ty) ->
741       let debruijnedty = debruijn_constructor ref len ty in
742       id, snd (split_prods ~subst tys paramsno ty),
743        snd (split_prods ~subst tys paramsno debruijnedty))
744     cl 
745   in
746   let lefts = fst (split_prods ~subst [] paramsno arity) in
747   tys@lefts, len, cl'
748 ;;
749
750 exception DoesOccur;;
751
752 let does_not_occur ~subst context n nn t = 
753   let rec aux (context,n,nn as k) _ = function
754     | C.Rel m when m > n && m <= nn -> raise DoesOccur
755     | C.Rel m ->
756         (try (match List.nth context (m-1) with
757           | _,C.Def (bo,_) -> aux k () (S.lift m bo)
758           | _ -> ())
759          with Failure _ -> assert false)
760     | C.Meta (_,(_,(C.Irl 0 | C.Ctx []))) -> (* closed meta *) ()
761     | C.Meta (mno,(s,l)) ->
762          (try
763            let _,_,term,_ = U.lookup_subst mno subst in
764            aux (context,n+s,nn+s) () (S.subst_meta (0,l) term)
765           with CicUtil.Subst_not_found _ -> match l with
766           | C.Irl len -> if not (n >= s+len || s > nn) then raise DoesOccur
767           | C.Ctx lc -> List.iter (aux (context,n+s,nn+s) ()) lc)
768     | t -> U.fold (fun e (ctx,n,nn) -> (e::ctx,n+1,nn+1)) k aux () t
769   in
770    try aux (context,n,nn) () t; true
771    with DoesOccur -> false
772 ;;
773
774 exception NotGuarded;;
775
776 let rec typeof ~subst ~metasenv context term =
777   let rec typeof_aux context = function
778     | C.Rel n ->
779        (try
780          match List.nth context (n - 1) with
781          | (_,C.Decl ty) -> S.lift n ty
782          | (_,C.Def (_,ty)) -> S.lift n ty
783         with Failure _ -> raise (TypeCheckerFailure (lazy "unbound variable")))
784     | C.Sort (C.Type i) -> C.Sort (C.Type (i+1))
785     | C.Sort s -> C.Sort (C.Type 0)
786     | C.Implicit _ -> raise (AssertFailure (lazy "Implicit found"))
787     | C.Meta (n,l) as t -> 
788        let canonical_context,ty =
789         try
790          let _,c,_,ty = U.lookup_subst n subst in c,ty
791         with U.Subst_not_found _ -> try
792          let _,_,c,ty = U.lookup_meta n metasenv in c,ty
793         with U.Meta_not_found _ ->
794          raise (AssertFailure (lazy (Printf.sprintf
795           "%s not found" (NCicPp.ppterm t))))
796        in
797         check_metasenv_consistency t context canonical_context l;
798         S.subst_meta l ty
799     | C.Const ref -> type_of_constant ref
800     | C.Prod (name,s,t) ->
801        let sort1 = typeof_aux context s in
802        let sort2 = typeof_aux ((name,(C.Decl s))::context) t in
803        sort_of_prod ~subst context (name,s) (sort1,sort2)
804     | C.Lambda (n,s,t) ->
805        let sort = typeof_aux context s in
806        (match R.whd ~subst context sort with
807        | C.Meta _ | C.Sort _ -> ()
808        | _ ->
809          raise
810            (TypeCheckerFailure (lazy (Printf.sprintf
811              ("Not well-typed lambda-abstraction: " ^^
812              "the source %s should be a type; instead it is a term " ^^ 
813              "of type %s") (NCicPp.ppterm s) (NCicPp.ppterm sort)))));
814        let ty = typeof_aux ((n,(C.Decl s))::context) t in
815          C.Prod (n,s,ty)
816     | C.LetIn (n,ty,t,bo) ->
817        let ty_t = typeof_aux context t in
818        if not (R.are_convertible ~subst ~metasenv context ty ty_t) then
819          raise 
820           (TypeCheckerFailure 
821             (lazy (Printf.sprintf
822               "The type of %s is %s but it is expected to be %s" 
823                 (NCicPp.ppterm t) (NCicPp.ppterm ty_t) (NCicPp.ppterm ty))))
824        else
825          let ty_bo = typeof_aux  ((n,C.Def (t,ty))::context) bo in
826          S.subst ~avoid_beta_redexes:true t ty_bo
827     | C.Appl (he::(_::_ as args)) ->
828        let ty_he = typeof_aux context he in
829        let args_with_ty = List.map (fun t -> t, typeof_aux context t) args in
830        eat_prods ~subst ~metasenv context ty_he args_with_ty
831    | C.Appl _ -> raise (AssertFailure (lazy "Appl of length < 2"))
832    | C.Match (Ref.Ref (dummy_depth,uri,Ref.Ind tyno) as r,outtype,term,pl) ->
833       let outsort = typeof_aux context outtype in
834       let leftno = E.get_indty_leftno r in
835       let parameters, arguments =
836         let ty = R.whd ~subst context (typeof_aux context term) in
837         let r',tl =
838          match ty with
839             C.Const (Ref.Ref (_,_,Ref.Ind _) as r') -> r',[]
840           | C.Appl (C.Const (Ref.Ref (_,_,Ref.Ind _) as r') :: tl) -> r',tl
841           | _ ->
842              raise 
843                (TypeCheckerFailure (lazy (Printf.sprintf
844                  "Case analysis: analysed term %s is not an inductive one"
845                  (NCicPp.ppterm term)))) in
846         if not (Ref.eq r r') then
847          raise
848           (TypeCheckerFailure (lazy (Printf.sprintf
849             ("Case analysys: analysed term type is %s, but is expected " ^^
850              "to be (an application of) %s")
851             (NCicPp.ppterm ty) (NCicPp.ppterm (C.Const r')))))
852         else
853          try HExtlib.split_nth leftno tl
854          with
855           Failure _ ->
856            raise (TypeCheckerFailure (lazy (Printf.sprintf
857             "%s is partially applied" (NCicPp.ppterm ty)))) in
858       (* let's control if the sort elimination is allowed: [(I q1 ... qr)|B] *)
859       let sort_of_ind_type =
860         if parameters = [] then C.Const r
861         else C.Appl ((C.Const r)::parameters) in
862       let type_of_sort_of_ind_ty = typeof_aux context sort_of_ind_type in
863       if not (check_allowed_sort_elimination ~subst ~metasenv r context
864           sort_of_ind_type type_of_sort_of_ind_ty outsort)
865       then raise (TypeCheckerFailure (lazy ("Sort elimination not allowed")));
866       (* let's check if the type of branches are right *)
867       let leftno,constructorsno =
868         let inductive,leftno,itl,_,i = E.get_checked_indtys r in
869         let _,name,ty,cl = List.nth itl i in
870         let cl_len = List.length cl in
871         leftno, cl_len
872       in
873       if List.length pl <> constructorsno then
874        raise (TypeCheckerFailure (lazy ("Wrong number of cases in a match")));
875       let j,branches_ok =
876         List.fold_left
877           (fun (j,b) p ->
878             if b then
879               let cons = 
880                 let cons = Ref.Ref (dummy_depth, uri, Ref.Con (tyno, j)) in
881                 if parameters = [] then C.Const cons
882                 else C.Appl (C.Const cons::parameters)
883               in
884               let ty_p = typeof_aux context p in
885               let ty_cons = typeof_aux context cons in
886               let ty_branch = 
887                 type_of_branch ~subst context leftno outtype cons ty_cons in
888               j+1, R.are_convertible ~subst ~metasenv context ty_p ty_branch 
889             else
890               j,false
891           ) (1,true) pl
892          in
893           if not branches_ok then
894            raise
895             (TypeCheckerFailure 
896               (lazy (Printf.sprintf "Branch for constructor %s has wrong type"
897               (NCicPp.ppterm (C.Const 
898                 (Ref.Ref (dummy_depth, uri, Ref.Con (tyno, j)))))))); 
899           let res = outtype::arguments@[term] in
900           R.head_beta_reduce (C.Appl res)
901     | C.Match _ -> assert false
902
903   and type_of_branch ~subst context leftno outty cons tycons = assert false
904
905   (* check_metasenv_consistency checks that the "canonical" context of a
906      metavariable is consitent - up to relocation via the relocation list l -
907      with the actual context *)
908   and check_metasenv_consistency term context canonical_context l =
909    match l with
910     | shift, NCic.Irl n ->
911        let context = snd (HExtlib.split_nth shift context) in
912         let rec compare = function
913          | 0,_,[] -> ()
914          | 0,_,_::_
915          | _,_,[] ->
916             raise (AssertFailure (lazy (Printf.sprintf
917              "Local and canonical context %s have different lengths"
918              (NCicPp.ppterm term))))
919          | m,[],_::_ ->
920             raise (TypeCheckerFailure (lazy (Printf.sprintf
921              "Unbound variable -%d in %s" m (NCicPp.ppterm term))))
922          | m,t::tl,ct::ctl ->
923             (match t,ct with
924                 (_,C.Decl t1), (_,C.Decl t2)
925               | (_,C.Def (t1,_)), (_,C.Def (t2,_))
926               | (_,C.Def (_,t1)), (_,C.Decl t2) ->
927                  if not (R.are_convertible ~subst ~metasenv tl t1 t2) then
928                   raise 
929                       (TypeCheckerFailure 
930                         (lazy (Printf.sprintf 
931                       ("Not well typed metavariable local context for %s: " ^^ 
932                        "%s expected, which is not convertible with %s")
933                       (NCicPp.ppterm term) (NCicPp.ppterm t2) (NCicPp.ppterm t1)
934                       )))
935               | _,_ ->
936                raise 
937                    (TypeCheckerFailure 
938                      (lazy (Printf.sprintf 
939                     ("Not well typed metavariable local context for %s: " ^^ 
940                      "a definition expected, but a declaration found")
941                     (NCicPp.ppterm term)))));
942             compare (m - 1,tl,ctl)
943         in
944          compare (n,context,canonical_context)
945     | shift, lc_kind ->
946        (* we avoid useless lifting by shortening the context*)
947        let l,context = (0,lc_kind), snd (HExtlib.split_nth shift context) in
948        let lifted_canonical_context = 
949          let rec lift_metas i = function
950            | [] -> []
951            | (n,C.Decl t)::tl ->
952                (n,C.Decl (S.subst_meta l (S.lift i t)))::(lift_metas (i+1) tl)
953            | (n,C.Def (t,ty))::tl ->
954                (n,C.Def ((S.subst_meta l (S.lift i t)),
955                           S.subst_meta l (S.lift i ty)))::(lift_metas (i+1) tl)
956          in
957           lift_metas 1 canonical_context in
958        let l = U.expand_local_context lc_kind in
959        try
960         List.iter2 
961         (fun t ct -> 
962           match (t,ct) with
963           | t, (_,C.Def (ct,_)) ->
964              (*CSC: the following optimization is to avoid a possibly expensive
965                     reduction that can be easily avoided and that is quite
966                     frequent. However, this is better handled using levels to
967                     control reduction *)
968              let optimized_t =
969               match t with
970               | C.Rel n ->
971                   (try
972                     match List.nth context (n - 1) with
973                     | (_,C.Def (te,_)) -> S.lift n te
974                     | _ -> t
975                     with Failure _ -> t)
976               | _ -> t
977              in
978              if not (R.are_convertible ~subst ~metasenv context optimized_t ct)
979              then
980                raise 
981                  (TypeCheckerFailure 
982                    (lazy (Printf.sprintf 
983                      ("Not well typed metavariable local context: " ^^ 
984                       "expected a term convertible with %s, found %s")
985                      (NCicPp.ppterm ct) (NCicPp.ppterm t))))
986           | t, (_,C.Decl ct) ->
987               let type_t = typeof_aux context t in
988               if not (R.are_convertible ~subst ~metasenv context type_t ct) then
989                 raise (TypeCheckerFailure 
990                   (lazy (Printf.sprintf 
991                    ("Not well typed metavariable local context: "^^
992                     "expected a term of type %s, found %s of type %s") 
993                     (NCicPp.ppterm ct) (NCicPp.ppterm t) (NCicPp.ppterm type_t))))
994         ) l lifted_canonical_context 
995        with
996         Invalid_argument _ ->
997           raise (AssertFailure (lazy (Printf.sprintf
998            "Local and canonical context %s have different lengths"
999            (NCicPp.ppterm term))))
1000
1001   and is_non_informative context paramsno c =
1002    let rec aux context c =
1003      match R.whd context c with
1004       | C.Prod (n,so,de) ->
1005          let s = typeof_aux context so in
1006          s = C.Sort C.Prop && aux ((n,(C.Decl so))::context) de
1007       | _ -> true in
1008    let context',dx = split_prods ~subst:[] context paramsno c in
1009     aux context' dx
1010
1011   and check_allowed_sort_elimination ~subst ~metasenv r =
1012    let mkapp he arg =
1013      match he with
1014      | C.Appl l -> C.Appl (l @ [arg])
1015      | t -> C.Appl [t;arg] in
1016    let rec aux context ind arity1 arity2 =
1017     let arity1 = R.whd ~subst context arity1 in
1018     let arity2 = R.whd ~subst context arity2 in
1019       match arity1,arity2 with
1020        | C.Prod (name,so1,de1), C.Prod (_,so2,de2) ->
1021           R.are_convertible ~subst ~metasenv context so1 so2 &&
1022            aux ((name, C.Decl so1)::context)
1023             (mkapp (S.lift 1 ind) (C.Rel 1)) de1 de2
1024        | C.Sort _, C.Prod (name,so,ta) ->
1025         (R.are_convertible ~subst ~metasenv context so ind &&
1026           match arity1,ta with
1027           | (C.Sort (C.CProp | C.Type _), C.Sort _)
1028           | (C.Sort C.Prop, C.Sort C.Prop) -> true
1029           | (C.Sort C.Prop, C.Sort (C.CProp | C.Type _)) ->
1030               let inductive,leftno,itl,_,i = E.get_checked_indtys r in
1031               let itl_len = List.length itl in
1032               let _,name,ty,cl = List.nth itl i in
1033               let cl_len = List.length cl in
1034                (* is it a singleton or empty non recursive and non informative
1035                   definition? *)
1036                cl_len = 0 ||
1037                 (itl_len = 1 && cl_len = 1 &&
1038                  is_non_informative [name,C.Decl ty] leftno
1039                   (let _,_,x = List.nth cl 0 in x))
1040           | _,_ -> false)
1041        | _,_ -> false
1042    in
1043     aux 
1044
1045  in 
1046    typeof_aux context term
1047
1048 and check_mutual_inductive_defs _ = assert false
1049
1050 and eat_lambdas ~subst context n te =
1051   match (n, R.whd ~subst context te) with
1052   | (0, _) -> (te, context)
1053   | (n, C.Lambda (name,so,ta)) when n > 0 ->
1054       eat_lambdas ~subst ((name,(C.Decl so))::context) (n - 1) ta
1055    | (n, te) ->
1056       raise (AssertFailure 
1057         (lazy (Printf.sprintf "9 (%d, %s)" n (NCicPp.ppterm te))))
1058
1059 and guarded_by_destructors ~subst context recfuns t = 
1060  let recursor f k t = NCicUtils.fold shift_k k (fun k () -> f k) () t in
1061  let rec aux (context, recfuns, x, safes as k) = function
1062   | C.Rel m when List.mem_assoc m recfuns -> raise NotGuarded 
1063   | C.Rel m ->
1064      (match List.nth context (m-1) with 
1065      | _,C.Decl _ -> ()
1066      | _,C.Def (bo,_) -> aux (context, recfuns, x, safes) (S.lift m bo))
1067   | C.Meta _ -> ()
1068   | C.Appl ((C.Rel m)::tl) when List.mem_assoc m recfuns ->
1069      let rec_no = List.assoc m recfuns in
1070      if not (List.length tl > rec_no) then raise NotGuarded
1071      else
1072        let rec_arg = List.nth tl rec_no in
1073        aux k rec_arg;
1074        List.iter (aux k) tl
1075   | C.Match (ref,outtype,term,pl) as t ->
1076      (match R.whd ~subst context term with
1077      | C.Rel m | C.Appl (C.Rel m :: _ ) as t when List.mem m safes || m = x ->
1078         let isinductive, paramsno, tl, _, i = E.get_checked_indtys ref in
1079         if not isinductive then recursor aux k t
1080         else
1081          let lefts_and_tys,len,cl = fix_lefts_in_constrs ~subst paramsno tl i in
1082          let args = match t with C.Appl (_::tl) -> tl | _ -> [] in
1083          aux k outtype; 
1084          List.iter (aux k) args; 
1085          List.iter2
1086            (fun p (_,c,bruijnedc) ->
1087              let rl = recursive_args ~subst lefts_and_tys 0 len bruijnedc in
1088              let p, k = get_new_safes ~subst k p rl in
1089              aux k p) 
1090            pl cl
1091      | _ -> recursor aux k t)
1092   | t -> recursor aux k t
1093  in
1094   try aux (context, recfuns, 1, []) t;true
1095   with NotGuarded -> false
1096
1097 (*
1098  | C.Fix (_, fl) ->
1099     let len = List.length fl in
1100      let n_plus_len = n + len
1101      and nn_plus_len = nn + len
1102      and x_plus_len = x + len
1103      and tys,_ =
1104       List.fold_left
1105         (fun (types,len) (n,_,ty,_) ->
1106            (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1107             len+1)
1108         ) ([],0) fl
1109      and safes' = List.map (fun x -> x + len) safes in
1110       List.fold_right
1111        (fun (_,_,ty,bo) i ->
1112          i && guarded_by_destructors ~subst context n nn kl x_plus_len safes' ty &&
1113           guarded_by_destructors ~subst (tys@context) n_plus_len nn_plus_len kl
1114            x_plus_len safes' bo
1115        ) fl true
1116  | C.CoFix (_, fl) ->
1117     let len = List.length fl in
1118      let n_plus_len = n + len
1119      and nn_plus_len = nn + len
1120      and x_plus_len = x + len
1121      and tys,_ =
1122       List.fold_left
1123         (fun (types,len) (n,ty,_) ->
1124            (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1125             len+1)
1126         ) ([],0) fl
1127      and safes' = List.map (fun x -> x + len) safes in
1128       List.fold_right
1129        (fun (_,ty,bo) i ->
1130          i &&
1131           guarded_by_destructors ~subst context n nn kl x_plus_len safes' ty &&
1132           guarded_by_destructors ~subst (tys@context) n_plus_len nn_plus_len kl
1133            x_plus_len safes' bo
1134        ) fl true
1135 *)
1136
1137 and guarded_by_constructors ~subst _ _ _ _ _ _ _ = assert false
1138
1139 and recursive_args ~subst context n nn te =
1140   match R.whd context te with
1141   | C.Rel _ -> []
1142   | C.Prod (name,so,de) ->
1143      (not (does_not_occur ~subst context n nn so)) ::
1144       (recursive_args ~subst ((name,(C.Decl so))::context) (n+1) (nn + 1) de)
1145   | _ -> raise (AssertFailure (lazy ("recursive_args")))
1146
1147 and get_new_safes ~subst (context, recfuns, x, safes as k) p rl =
1148   match R.whd ~subst context p, rl with
1149   | C.Lambda (name,so,ta), b::tl ->
1150       let safes = (if b then [0] else []) @ safes in
1151       get_new_safes ~subst 
1152         (shift_k (name,(C.Decl so)) (context, recfuns, x, safes)) ta tl
1153   | C.Meta _ as e, _ | e, [] -> e, k
1154   | _ -> raise (AssertFailure (lazy "Ill formed pattern"))
1155
1156 and split_prods ~subst context n te =
1157   match n, R.whd ~subst context te with
1158   | 0, _ -> context,te
1159   | n, C.Prod (name,so,ta) when n > 0 ->
1160        split_prods ~subst ((name,(C.Decl so))::context) (n - 1) ta
1161   | _ -> raise (AssertFailure (lazy "split_prods"))
1162
1163 (*CSC: Tutto quello che segue e' l'intuzione di luca ;-) *) 
1164 and check_is_really_smaller_arg ~subst context n nn kl x safes te =
1165 assert false        (*
1166  (*CSC: forse la whd si puo' fare solo quando serve veramente. *)
1167  (*CSC: cfr guarded_by_destructors                             *)
1168  let module C = Cic in
1169  let module U = UriManager in
1170  match CicReduction.whd ~subst context te with
1171      C.Rel m when List.mem m safes -> true
1172    | C.Rel _ -> false
1173    | C.Var _
1174    | C.Meta _
1175    | C.Sort _
1176    | C.Implicit _
1177    | C.Cast _
1178 (*   | C.Cast (te,ty) ->
1179       check_is_really_smaller_arg ~subst n nn kl x safes te &&
1180        check_is_really_smaller_arg ~subst n nn kl x safes ty*)
1181 (*   | C.Prod (_,so,ta) ->
1182       check_is_really_smaller_arg ~subst n nn kl x safes so &&
1183        check_is_really_smaller_arg ~subst (n+1) (nn+1) kl (x+1)
1184         (List.map (fun x -> x + 1) safes) ta*)
1185    | C.Prod _ -> raise (AssertFailure (lazy "10"))
1186    | C.Lambda (name,so,ta) ->
1187       check_is_really_smaller_arg ~subst context n nn kl x safes so &&
1188        check_is_really_smaller_arg ~subst ((Some (name,(C.Decl so)))::context)
1189         (n+1) (nn+1) kl (x+1) (List.map (fun x -> x + 1) safes) ta
1190    | C.LetIn (name,so,ty,ta) ->
1191       check_is_really_smaller_arg ~subst context n nn kl x safes so &&
1192        check_is_really_smaller_arg ~subst context n nn kl x safes ty &&
1193         check_is_really_smaller_arg ~subst ((Some (name,(C.Def (so,ty))))::context)
1194         (n+1) (nn+1) kl (x+1) (List.map (fun x -> x + 1) safes) ta
1195    | C.Appl (he::_) ->
1196       (*CSC: sulla coda ci vogliono dei controlli? secondo noi no, ma *)
1197       (*CSC: solo perche' non abbiamo trovato controesempi            *)
1198       check_is_really_smaller_arg ~subst context n nn kl x safes he
1199    | C.Appl [] -> raise (AssertFailure (lazy "11"))
1200    | C.Const _
1201    | C.MutInd _ -> raise (AssertFailure (lazy "12"))
1202    | C.MutConstruct _ -> false
1203    | C.MutCase (uri,i,outtype,term,pl) ->
1204       (match term with
1205           C.Rel m when List.mem m safes || m = x ->
1206            let (lefts_and_tys,len,isinductive,paramsno,cl) =
1207             let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
1208             match o with
1209                C.InductiveDefinition (tl,_,paramsno,_) ->
1210                 let tys =
1211                  List.map
1212                   (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) tl
1213                 in
1214                  let (_,isinductive,_,cl) = List.nth tl i in
1215                   let cl' =
1216                    List.map
1217                     (fun (id,ty) ->
1218                       (id, snd (split_prods ~subst tys paramsno ty))) cl in
1219                   let lefts =
1220                    match tl with
1221                       [] -> assert false
1222                     | (_,_,ty,_)::_ ->
1223                        fst (split_prods ~subst [] paramsno ty)
1224                   in
1225                    (tys@lefts,List.length tl,isinductive,paramsno,cl')
1226              | _ ->
1227                 raise (TypeCheckerFailure
1228                   (lazy ("Unknown mutual inductive definition:" ^
1229                   UriManager.string_of_uri uri)))
1230            in
1231             if not isinductive then
1232               List.fold_right
1233                (fun p i ->
1234                  i && check_is_really_smaller_arg ~subst context n nn kl x safes p)
1235                pl true
1236             else
1237              let pl_and_cl =
1238               try
1239                List.combine pl cl
1240               with
1241                Invalid_argument _ ->
1242                 raise (TypeCheckerFailure (lazy "not enough patterns"))
1243              in
1244               (*CSC: supponiamo come prima che nessun controllo sia necessario*)
1245               (*CSC: sugli argomenti di una applicazione                      *)
1246               List.fold_right
1247                (fun (p,(_,c)) i ->
1248                  let rl' =
1249                   let debruijnedte = debruijn_constructor uri len c in
1250                    recursive_args lefts_and_tys 0 len debruijnedte
1251                  in
1252                   let (e,safes',n',nn',x',context') =
1253                    get_new_safes ~subst context p c rl' safes n nn x
1254                   in
1255                    i &&
1256                    check_is_really_smaller_arg ~subst context' n' nn' kl x' safes' e
1257                ) pl_and_cl true
1258         | C.Appl ((C.Rel m)::tl) when List.mem m safes || m = x ->
1259            let (lefts_and_tys,len,isinductive,paramsno,cl) =
1260             let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
1261             match o with
1262                C.InductiveDefinition (tl,_,paramsno,_) ->
1263                 let (_,isinductive,_,cl) = List.nth tl i in
1264                  let tys =
1265                   List.map (fun (n,_,ty,_) ->
1266                    Some(Cic.Name n,(Cic.Decl ty))) tl
1267                  in
1268                   let cl' =
1269                    List.map
1270                     (fun (id,ty) ->
1271                       (id, snd (split_prods ~subst tys paramsno ty))) cl in
1272                   let lefts =
1273                    match tl with
1274                       [] -> assert false
1275                     | (_,_,ty,_)::_ ->
1276                        fst (split_prods ~subst [] paramsno ty)
1277                   in
1278                    (tys@lefts,List.length tl,isinductive,paramsno,cl')
1279              | _ ->
1280                 raise (TypeCheckerFailure
1281                   (lazy ("Unknown mutual inductive definition:" ^
1282                   UriManager.string_of_uri uri)))
1283            in
1284             if not isinductive then
1285               List.fold_right
1286                (fun p i ->
1287                  i && check_is_really_smaller_arg ~subst context n nn kl x safes p)
1288                pl true
1289             else
1290              let pl_and_cl =
1291               try
1292                List.combine pl cl
1293               with
1294                Invalid_argument _ ->
1295                 raise (TypeCheckerFailure (lazy "not enough patterns"))
1296              in
1297               (*CSC: supponiamo come prima che nessun controllo sia necessario*)
1298               (*CSC: sugli argomenti di una applicazione                      *)
1299               List.fold_right
1300                (fun (p,(_,c)) i ->
1301                  let rl' =
1302                   let debruijnedte = debruijn_constructor uri len c in
1303                    recursive_args lefts_and_tys 0 len debruijnedte
1304                  in
1305                   let (e,safes',n',nn',x',context') =
1306                    get_new_safes ~subst context p c rl' safes n nn x
1307                   in
1308                    i &&
1309                    check_is_really_smaller_arg ~subst context' n' nn' kl x' safes' e
1310                ) pl_and_cl true
1311         | _ ->
1312           List.fold_right
1313            (fun p i ->
1314              i && check_is_really_smaller_arg ~subst context n nn kl x safes p
1315            ) pl true
1316       )
1317    | C.Fix (_, fl) ->
1318       let len = List.length fl in
1319        let n_plus_len = n + len
1320        and nn_plus_len = nn + len
1321        and x_plus_len = x + len
1322        and tys,_ =
1323         List.fold_left
1324           (fun (types,len) (n,_,ty,_) ->
1325              (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1326               len+1)
1327           ) ([],0) fl
1328        and safes' = List.map (fun x -> x + len) safes in
1329         List.fold_right
1330          (fun (_,_,ty,bo) i ->
1331            i &&
1332             check_is_really_smaller_arg ~subst (tys@context) n_plus_len nn_plus_len kl
1333              x_plus_len safes' bo
1334          ) fl true
1335    | C.CoFix (_, fl) ->
1336       let len = List.length fl in
1337        let n_plus_len = n + len
1338        and nn_plus_len = nn + len
1339        and x_plus_len = x + len
1340        and tys,_ =
1341         List.fold_left
1342           (fun (types,len) (n,ty,_) ->
1343              (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1344               len+1)
1345           ) ([],0) fl
1346        and safes' = List.map (fun x -> x + len) safes in
1347         List.fold_right
1348          (fun (_,ty,bo) i ->
1349            i &&
1350             check_is_really_smaller_arg ~subst (tys@context) n_plus_len nn_plus_len kl
1351              x_plus_len safes' bo
1352          ) fl true
1353          *)
1354
1355 and returns_a_coinductive ~subst _ _ = assert false
1356
1357 and type_of_constant ref = assert false (* USARE typecheck_obj0 *)
1358 (* ALIAS typecheck *)
1359 (*
1360   let cobj,ugraph1 =
1361    match CicEnvironment.is_type_checked ~trust:true ugraph uri with
1362        CicEnvironment.CheckedObj (cobj,ugraph') -> cobj,ugraph'
1363      | CicEnvironment.UncheckedObj uobj ->
1364          logger#log (`Start_type_checking uri) ;
1365          let ugraph1_dust =
1366           typecheck_obj0 ~logger uri CicUniv.empty_ugraph uobj in
1367            try 
1368              CicEnvironment.set_type_checking_info uri ;
1369              logger#log (`Type_checking_completed uri) ;
1370              (match CicEnvironment.is_type_checked ~trust:false ugraph uri with
1371                   CicEnvironment.CheckedObj (cobj,ugraph') -> (cobj,ugraph')
1372                 | CicEnvironment.UncheckedObj _ -> raise CicEnvironmentError
1373              )
1374            with
1375             (*
1376               this is raised if set_type_checking_info is called on an object
1377               that has no associated universe file. If we are in univ_maker 
1378               phase this is OK since univ_maker will properly commit the 
1379               object.
1380             *)
1381                Invalid_argument s ->
1382                  (*debug_print (lazy s);*)
1383                  uobj,ugraph1_dust
1384   in
1385 CASO COSTRUTTORE
1386     match cobj with
1387         C.InductiveDefinition (dl,_,_,_) ->
1388           let (_,_,arity,_) = List.nth dl i in
1389             arity,ugraph1
1390       | _ ->
1391           raise (TypeCheckerFailure
1392            (lazy ("Unknown mutual inductive definition:" ^ U.string_of_uri uri)))
1393 CASO TIPO INDUTTIVO
1394     match cobj with
1395         C.InductiveDefinition (dl,_,_,_) ->
1396           let (_,_,_,cl) = List.nth dl i in
1397           let (_,ty) = List.nth cl (j-1) in
1398             ty,ugraph1
1399       | _ ->
1400           raise (TypeCheckerFailure
1401            (lazy ("Unknown mutual inductive definition:" ^ UriManager.string_of_uri uri)))
1402 CASO COSTANTE
1403 CASO FIX/COFIX
1404 *)
1405
1406 and typecheck_obj0 (uri,height,metasenv,subst,kind) =
1407  (* CSC: here we should typecheck the metasenv and the subst *)
1408  assert (metasenv = [] && subst = []);
1409  match kind with
1410    | C.Constant (_,_,Some te,ty,_) ->
1411       let _ = typeof ~subst ~metasenv [] ty in
1412       let ty_te = typeof ~subst ~metasenv [] te in
1413       if not (R.are_convertible ~subst ~metasenv [] ty_te ty) then
1414        raise (TypeCheckerFailure (lazy (Printf.sprintf
1415         "the type of the body is not the one expected:\n%s\nvs\n%s"
1416         (NCicPp.ppterm ty_te) (NCicPp.ppterm ty))))
1417    | C.Constant (_,_,None,ty,_) -> ignore (typeof ~subst ~metasenv [] ty)
1418    | C.Inductive _ as obj -> check_mutual_inductive_defs uri obj
1419    | C.Fixpoint (inductive,fl,_) ->
1420       let types,kl,len =
1421         List.fold_left
1422          (fun (types,kl,len) (_,name,k,ty,_) ->
1423            let _ = typeof ~subst ~metasenv [] ty in
1424             ((name,(C.Decl (S.lift len ty)))::types, k::kl,len+1)
1425          ) ([],[],0) fl
1426       in
1427         List.iter (fun (_,name,x,ty,bo) ->
1428          let ty_bo = typeof ~subst ~metasenv types bo in
1429          if not (R.are_convertible ~subst ~metasenv types ty_bo (S.lift len ty))
1430          then raise (TypeCheckerFailure (lazy ("(Co)Fix: ill-typed bodies")))
1431          else
1432           if inductive then begin
1433             let m, context = eat_lambdas ~subst types (x + 1) bo in
1434             (* guarded by destructors conditions D{f,k,x,M} *)
1435             let rec enum_from k = 
1436               function [] -> [] | v::tl -> (k,v)::enum_from (k+1) tl 
1437             in
1438             if not (guarded_by_destructors 
1439                       ~subst context (enum_from (x+1) kl) m) then
1440               raise(TypeCheckerFailure(lazy("Fix: not guarded by destructors")))
1441           end else
1442            match returns_a_coinductive ~subst [] ty with
1443             | None ->
1444                 raise (TypeCheckerFailure
1445                   (lazy "CoFix: does not return a coinductive type"))
1446             | Some uri ->
1447                 (* guarded by constructors conditions C{f,M} *)
1448                 if not (guarded_by_constructors ~subst
1449                     types 0 len false bo [] uri)
1450                 then
1451                   raise (TypeCheckerFailure
1452                    (lazy "CoFix: not guarded by constructors"))
1453           ) fl
1454
1455 let typecheck_obj (*uri*) obj = assert false (*
1456  let ugraph = typecheck_obj0 ~logger uri CicUniv.empty_ugraph obj in
1457  let ugraph, univlist, obj = CicUnivUtils.clean_and_fill uri obj ugraph in
1458   CicEnvironment.add_type_checked_obj uri (obj,ugraph,univlist)
1459 *)
1460 ;;