]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_kernel/nCicTypeChecker.ml
1760c57e418ce3f9ecf6820021ce0a797caf520c
[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 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 ?(cb=fun _ _ -> ()) uri number_of_types = 
623  let rec aux k t =
624   let res =
625    match t with
626     | C.Meta (i,(s,C.Ctx l)) ->
627        let l1 = NCicUtils.sharing_map (aux (k-s)) l in
628        if l1 == l then t else C.Meta (i,(s,C.Ctx l1))
629     | C.Meta _ -> t
630     | C.Const (Ref.Ref (_,uri1,(Ref.Fix (no,_) | Ref.CoFix no))) 
631     | C.Const (Ref.Ref (_,uri1,Ref.Ind no)) when NUri.eq uri uri1 ->
632        C.Rel (k + number_of_types - no)
633     | t -> NCicUtils.map (fun _ k -> k+1) k aux t
634   in
635    cb t res; res
636  in
637   aux 0
638 ;;
639
640 let sort_of_prod ~subst context (name,s) (t1, t2) =
641    let t1 = R.whd ~subst context t1 in
642    let t2 = R.whd ~subst ((name,C.Decl s)::context) t2 in
643    match t1, t2 with
644    | C.Sort s1, C.Sort C.Prop -> t2
645    | C.Sort (C.Type u1), C.Sort (C.Type u2) -> C.Sort (C.Type (max u1 u2)) 
646    | C.Sort _,C.Sort (C.Type _) -> t2
647    | C.Sort (C.Type _) , C.Sort C.CProp -> t1
648    | C.Sort _, C.Sort C.CProp -> t2
649    | C.Meta _, C.Sort _
650    | C.Meta _, C.Meta _
651    | C.Sort _, C.Meta _ when U.is_closed t2 -> t2
652    | _ -> 
653       raise (TypeCheckerFailure (lazy (Printf.sprintf
654         "Prod: expected two sorts, found = %s, %s" 
655          (NCicPp.ppterm t1) (NCicPp.ppterm t2))))
656 ;;
657
658 let eat_prods ~subst ~metasenv context ty_he args_with_ty = 
659   let rec aux ty_he = function 
660   | [] -> ty_he
661   | (arg, ty_arg)::tl ->
662       (match R.whd ~subst context ty_he with 
663       | C.Prod (n,s,t) ->
664           if R.are_convertible ~subst ~metasenv context ty_arg s then
665             aux (S.subst ~avoid_beta_redexes:true arg t) tl
666           else
667             raise 
668               (TypeCheckerFailure 
669                 (lazy (Printf.sprintf
670                   ("Appl: wrong parameter-type, expected %s, found %s")
671                   (NCicPp.ppterm ty_arg) (NCicPp.ppterm s))))
672        | _ ->
673           raise 
674             (TypeCheckerFailure
675               (lazy "Appl: this is not a function, it cannot be applied")))
676   in
677     aux ty_he args_with_ty
678 ;;
679
680 let fix_lefts_in_constrs ~subst uri paramsno tyl i =
681   let len = List.length tyl in
682   let _,_,arity,cl = List.nth tyl i in
683   let tys = List.map (fun (_,n,ty,_) -> n,C.Decl ty) tyl in
684   let cl' =
685    List.map
686     (fun (_,id,ty) ->
687       let debruijnedty = debruijn uri len ty in
688       id, snd (split_prods ~subst tys paramsno ty),
689        snd (split_prods ~subst tys paramsno debruijnedty))
690     cl 
691   in
692   let lefts = fst (split_prods ~subst [] paramsno arity) in
693   tys@lefts, len, cl'
694 ;;
695
696 exception DoesOccur;;
697
698 let does_not_occur ~subst context n nn t = 
699   let rec aux (context,n,nn as k) _ = function
700     | C.Rel m when m > n && m <= nn -> raise DoesOccur
701     | C.Rel m ->
702         (try (match List.nth context (m-1) with
703           | _,C.Def (bo,_) -> aux k () (S.lift m bo)
704           | _ -> ())
705          with Failure _ -> assert false)
706     | C.Meta (_,(_,(C.Irl 0 | C.Ctx []))) -> (* closed meta *) ()
707     | C.Meta (mno,(s,l)) ->
708          (try
709            let _,_,term,_ = U.lookup_subst mno subst in
710            aux (context,n+s,nn+s) () (S.subst_meta (0,l) term)
711           with CicUtil.Subst_not_found _ -> match l with
712           | C.Irl len -> if not (n >= s+len || s > nn) then raise DoesOccur
713           | C.Ctx lc -> List.iter (aux (context,n+s,nn+s) ()) lc)
714     | t -> U.fold (fun e (ctx,n,nn) -> (e::ctx,n+1,nn+1)) k aux () t
715   in
716    try aux (context,n,nn) () t; true
717    with DoesOccur -> false
718 ;;
719
720 exception NotGuarded;;
721
722 let rec typeof ~subst ~metasenv context term =
723   let rec typeof_aux context = function
724     | C.Rel n ->
725        (try
726          match List.nth context (n - 1) with
727          | (_,C.Decl ty) -> S.lift n ty
728          | (_,C.Def (_,ty)) -> S.lift n ty
729         with Failure _ -> raise (TypeCheckerFailure (lazy "unbound variable")))
730     | C.Sort (C.Type i) -> C.Sort (C.Type (i+1))
731     | C.Sort s -> C.Sort (C.Type 0)
732     | C.Implicit _ -> raise (AssertFailure (lazy "Implicit found"))
733     | C.Meta (n,l) as t -> 
734        let canonical_context,ty =
735         try
736          let _,c,_,ty = U.lookup_subst n subst in c,ty
737         with U.Subst_not_found _ -> try
738          let _,_,c,ty = U.lookup_meta n metasenv in c,ty
739         with U.Meta_not_found _ ->
740          raise (AssertFailure (lazy (Printf.sprintf
741           "%s not found" (NCicPp.ppterm t))))
742        in
743         check_metasenv_consistency t context canonical_context l;
744         S.subst_meta l ty
745     | C.Const ref -> type_of_constant ref
746     | C.Prod (name,s,t) ->
747        let sort1 = typeof_aux context s in
748        let sort2 = typeof_aux ((name,(C.Decl s))::context) t in
749        sort_of_prod ~subst context (name,s) (sort1,sort2)
750     | C.Lambda (n,s,t) ->
751        let sort = typeof_aux context s in
752        (match R.whd ~subst context sort with
753        | C.Meta _ | C.Sort _ -> ()
754        | _ ->
755          raise
756            (TypeCheckerFailure (lazy (Printf.sprintf
757              ("Not well-typed lambda-abstraction: " ^^
758              "the source %s should be a type; instead it is a term " ^^ 
759              "of type %s") (NCicPp.ppterm s) (NCicPp.ppterm sort)))));
760        let ty = typeof_aux ((n,(C.Decl s))::context) t in
761          C.Prod (n,s,ty)
762     | C.LetIn (n,ty,t,bo) ->
763        let ty_t = typeof_aux context t in
764        if not (R.are_convertible ~subst ~metasenv context ty ty_t) then
765          raise 
766           (TypeCheckerFailure 
767             (lazy (Printf.sprintf
768               "The type of %s is %s but it is expected to be %s" 
769                 (NCicPp.ppterm t) (NCicPp.ppterm ty_t) (NCicPp.ppterm ty))))
770        else
771          let ty_bo = typeof_aux  ((n,C.Def (t,ty))::context) bo in
772          S.subst ~avoid_beta_redexes:true t ty_bo
773     | C.Appl (he::(_::_ as args)) ->
774        let ty_he = typeof_aux context he in
775        let args_with_ty = List.map (fun t -> t, typeof_aux context t) args in
776        eat_prods ~subst ~metasenv context ty_he args_with_ty
777    | C.Appl _ -> raise (AssertFailure (lazy "Appl of length < 2"))
778    | C.Match (Ref.Ref (dummy_depth,uri,Ref.Ind tyno) as r,outtype,term,pl) ->
779       let outsort = typeof_aux context outtype in
780       let leftno = E.get_indty_leftno r in
781       let parameters, arguments =
782         let ty = R.whd ~subst context (typeof_aux context term) in
783         let r',tl =
784          match ty with
785             C.Const (Ref.Ref (_,_,Ref.Ind _) as r') -> r',[]
786           | C.Appl (C.Const (Ref.Ref (_,_,Ref.Ind _) as r') :: tl) -> r',tl
787           | _ ->
788              raise 
789                (TypeCheckerFailure (lazy (Printf.sprintf
790                  "Case analysis: analysed term %s is not an inductive one"
791                  (NCicPp.ppterm term)))) in
792         if not (Ref.eq r r') then
793          raise
794           (TypeCheckerFailure (lazy (Printf.sprintf
795             ("Case analysys: analysed term type is %s, but is expected " ^^
796              "to be (an application of) %s")
797             (NCicPp.ppterm ty) (NCicPp.ppterm (C.Const r')))))
798         else
799          try HExtlib.split_nth leftno tl
800          with
801           Failure _ ->
802            raise (TypeCheckerFailure (lazy (Printf.sprintf
803             "%s is partially applied" (NCicPp.ppterm ty)))) in
804       (* let's control if the sort elimination is allowed: [(I q1 ... qr)|B] *)
805       let sort_of_ind_type =
806         if parameters = [] then C.Const r
807         else C.Appl ((C.Const r)::parameters) in
808       let type_of_sort_of_ind_ty = typeof_aux context sort_of_ind_type in
809       if not (check_allowed_sort_elimination ~subst ~metasenv r context
810           sort_of_ind_type type_of_sort_of_ind_ty outsort)
811       then raise (TypeCheckerFailure (lazy ("Sort elimination not allowed")));
812       (* let's check if the type of branches are right *)
813       let leftno,constructorsno =
814         let inductive,leftno,itl,_,i = E.get_checked_indtys r in
815         let _,name,ty,cl = List.nth itl i in
816         let cl_len = List.length cl in
817         leftno, cl_len
818       in
819       if List.length pl <> constructorsno then
820        raise (TypeCheckerFailure (lazy ("Wrong number of cases in a match")));
821       let j,branches_ok =
822         List.fold_left
823           (fun (j,b) p ->
824             if b then
825               let cons = 
826                 let cons = Ref.Ref (dummy_depth, uri, Ref.Con (tyno, j)) in
827                 if parameters = [] then C.Const cons
828                 else C.Appl (C.Const cons::parameters)
829               in
830               let ty_p = typeof_aux context p in
831               let ty_cons = typeof_aux context cons in
832               let ty_branch = 
833                 type_of_branch ~subst context leftno outtype cons ty_cons in
834               j+1, R.are_convertible ~subst ~metasenv context ty_p ty_branch 
835             else
836               j,false
837           ) (1,true) pl
838          in
839           if not branches_ok then
840            raise
841             (TypeCheckerFailure 
842               (lazy (Printf.sprintf "Branch for constructor %s has wrong type"
843               (NCicPp.ppterm (C.Const 
844                 (Ref.Ref (dummy_depth, uri, Ref.Con (tyno, j)))))))); 
845           let res = outtype::arguments@[term] in
846           R.head_beta_reduce (C.Appl res)
847     | C.Match _ -> assert false
848
849   and type_of_branch ~subst context leftno outty cons tycons = assert false
850
851   (* check_metasenv_consistency checks that the "canonical" context of a
852      metavariable is consitent - up to relocation via the relocation list l -
853      with the actual context *)
854   and check_metasenv_consistency term context canonical_context l =
855    match l with
856     | shift, NCic.Irl n ->
857        let context = snd (HExtlib.split_nth shift context) in
858         let rec compare = function
859          | 0,_,[] -> ()
860          | 0,_,_::_
861          | _,_,[] ->
862             raise (AssertFailure (lazy (Printf.sprintf
863              "Local and canonical context %s have different lengths"
864              (NCicPp.ppterm term))))
865          | m,[],_::_ ->
866             raise (TypeCheckerFailure (lazy (Printf.sprintf
867              "Unbound variable -%d in %s" m (NCicPp.ppterm term))))
868          | m,t::tl,ct::ctl ->
869             (match t,ct with
870                 (_,C.Decl t1), (_,C.Decl t2)
871               | (_,C.Def (t1,_)), (_,C.Def (t2,_))
872               | (_,C.Def (_,t1)), (_,C.Decl t2) ->
873                  if not (R.are_convertible ~subst ~metasenv tl t1 t2) then
874                   raise 
875                       (TypeCheckerFailure 
876                         (lazy (Printf.sprintf 
877                       ("Not well typed metavariable local context for %s: " ^^ 
878                        "%s expected, which is not convertible with %s")
879                       (NCicPp.ppterm term) (NCicPp.ppterm t2) (NCicPp.ppterm t1)
880                       )))
881               | _,_ ->
882                raise 
883                    (TypeCheckerFailure 
884                      (lazy (Printf.sprintf 
885                     ("Not well typed metavariable local context for %s: " ^^ 
886                      "a definition expected, but a declaration found")
887                     (NCicPp.ppterm term)))));
888             compare (m - 1,tl,ctl)
889         in
890          compare (n,context,canonical_context)
891     | shift, lc_kind ->
892        (* we avoid useless lifting by shortening the context*)
893        let l,context = (0,lc_kind), snd (HExtlib.split_nth shift context) in
894        let lifted_canonical_context = 
895          let rec lift_metas i = function
896            | [] -> []
897            | (n,C.Decl t)::tl ->
898                (n,C.Decl (S.subst_meta l (S.lift i t)))::(lift_metas (i+1) tl)
899            | (n,C.Def (t,ty))::tl ->
900                (n,C.Def ((S.subst_meta l (S.lift i t)),
901                           S.subst_meta l (S.lift i ty)))::(lift_metas (i+1) tl)
902          in
903           lift_metas 1 canonical_context in
904        let l = U.expand_local_context lc_kind in
905        try
906         List.iter2 
907         (fun t ct -> 
908           match (t,ct) with
909           | t, (_,C.Def (ct,_)) ->
910              (*CSC: the following optimization is to avoid a possibly expensive
911                     reduction that can be easily avoided and that is quite
912                     frequent. However, this is better handled using levels to
913                     control reduction *)
914              let optimized_t =
915               match t with
916               | C.Rel n ->
917                   (try
918                     match List.nth context (n - 1) with
919                     | (_,C.Def (te,_)) -> S.lift n te
920                     | _ -> t
921                     with Failure _ -> t)
922               | _ -> t
923              in
924              if not (R.are_convertible ~subst ~metasenv context optimized_t ct)
925              then
926                raise 
927                  (TypeCheckerFailure 
928                    (lazy (Printf.sprintf 
929                      ("Not well typed metavariable local context: " ^^ 
930                       "expected a term convertible with %s, found %s")
931                      (NCicPp.ppterm ct) (NCicPp.ppterm t))))
932           | t, (_,C.Decl ct) ->
933               let type_t = typeof_aux context t in
934               if not (R.are_convertible ~subst ~metasenv context type_t ct) then
935                 raise (TypeCheckerFailure 
936                   (lazy (Printf.sprintf 
937                    ("Not well typed metavariable local context: "^^
938                     "expected a term of type %s, found %s of type %s") 
939                     (NCicPp.ppterm ct) (NCicPp.ppterm t) (NCicPp.ppterm type_t))))
940         ) l lifted_canonical_context 
941        with
942         Invalid_argument _ ->
943           raise (AssertFailure (lazy (Printf.sprintf
944            "Local and canonical context %s have different lengths"
945            (NCicPp.ppterm term))))
946
947   and is_non_informative context paramsno c =
948    let rec aux context c =
949      match R.whd context c with
950       | C.Prod (n,so,de) ->
951          let s = typeof_aux context so in
952          s = C.Sort C.Prop && aux ((n,(C.Decl so))::context) de
953       | _ -> true in
954    let context',dx = split_prods ~subst:[] context paramsno c in
955     aux context' dx
956
957   and check_allowed_sort_elimination ~subst ~metasenv r =
958    let mkapp he arg =
959      match he with
960      | C.Appl l -> C.Appl (l @ [arg])
961      | t -> C.Appl [t;arg] in
962    let rec aux context ind arity1 arity2 =
963     let arity1 = R.whd ~subst context arity1 in
964     let arity2 = R.whd ~subst context arity2 in
965       match arity1,arity2 with
966        | C.Prod (name,so1,de1), C.Prod (_,so2,de2) ->
967           R.are_convertible ~subst ~metasenv context so1 so2 &&
968            aux ((name, C.Decl so1)::context)
969             (mkapp (S.lift 1 ind) (C.Rel 1)) de1 de2
970        | C.Sort _, C.Prod (name,so,ta) ->
971         (R.are_convertible ~subst ~metasenv context so ind &&
972           match arity1,ta with
973           | (C.Sort (C.CProp | C.Type _), C.Sort _)
974           | (C.Sort C.Prop, C.Sort C.Prop) -> true
975           | (C.Sort C.Prop, C.Sort (C.CProp | C.Type _)) ->
976               let inductive,leftno,itl,_,i = E.get_checked_indtys r in
977               let itl_len = List.length itl in
978               let _,name,ty,cl = List.nth itl i in
979               let cl_len = List.length cl in
980                (* is it a singleton or empty non recursive and non informative
981                   definition? *)
982                cl_len = 0 ||
983                 (itl_len = 1 && cl_len = 1 &&
984                  is_non_informative [name,C.Decl ty] leftno
985                   (let _,_,x = List.nth cl 0 in x))
986           | _,_ -> false)
987        | _,_ -> false
988    in
989     aux 
990
991  in 
992    typeof_aux context term
993
994 and check_mutual_inductive_defs _ = assert false
995
996 and eat_lambdas ~subst context n te =
997   match (n, R.whd ~subst context te) with
998   | (0, _) -> (te, context)
999   | (n, C.Lambda (name,so,ta)) when n > 0 ->
1000       eat_lambdas ~subst ((name,(C.Decl so))::context) (n - 1) ta
1001    | (n, te) ->
1002       raise (AssertFailure 
1003         (lazy (Printf.sprintf "9 (%d, %s)" n (NCicPp.ppterm te))))
1004
1005 and guarded_by_destructors ~subst context recfuns t = 
1006  let recursor f k t = NCicUtils.fold shift_k k (fun k () -> f k) () t in
1007  let rec aux (context, recfuns, x, safes as k) = function
1008   | C.Rel m when List.mem_assoc m recfuns -> raise NotGuarded 
1009   | C.Rel m ->
1010      (match List.nth context (m-1) with 
1011      | _,C.Decl _ -> ()
1012      | _,C.Def (bo,_) -> aux (context, recfuns, x, safes) (S.lift m bo))
1013   | C.Meta _ -> ()
1014   | C.Appl ((C.Rel m)::tl) when List.mem_assoc m recfuns ->
1015      let rec_no = List.assoc m recfuns in
1016      if not (List.length tl > rec_no) then raise NotGuarded
1017      else
1018        let rec_arg = List.nth tl rec_no in
1019        if not (is_really_smaller ~subst k rec_arg) then raise
1020        NotGuarded;
1021        List.iter (aux k) tl
1022   | C.Match (Ref.Ref (_,uri,_) as ref,outtype,term,pl) as t ->
1023      (match R.whd ~subst context term with
1024      | C.Rel m | C.Appl (C.Rel m :: _ ) as t when List.mem m safes || m = x ->
1025         let isinductive, paramsno, tl, _, i = E.get_checked_indtys ref in
1026         if not isinductive then recursor aux k t
1027         else
1028          let c_ctx,len,cl = fix_lefts_in_constrs ~subst uri paramsno tl i in
1029          let args = match t with C.Appl (_::tl) -> tl | _ -> [] in
1030          aux k outtype; 
1031          List.iter (aux k) args; 
1032          List.iter2
1033            (fun p (_,_,bruijnedc) ->
1034              let rl = recursive_args ~subst c_ctx 0 len bruijnedc in
1035              let p, k = get_new_safes ~subst k p rl in
1036              aux k p) 
1037            pl cl
1038      | _ -> recursor aux k t)
1039   | t -> recursor aux k t
1040  in
1041   try aux (context, recfuns, 1, []) t;true
1042   with NotGuarded -> false
1043
1044 (*
1045  | C.Fix (_, fl) ->
1046     let len = List.length fl in
1047      let n_plus_len = n + len
1048      and nn_plus_len = nn + len
1049      and x_plus_len = x + len
1050      and tys,_ =
1051       List.fold_left
1052         (fun (types,len) (n,_,ty,_) ->
1053            (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1054             len+1)
1055         ) ([],0) fl
1056      and safes' = List.map (fun x -> x + len) safes in
1057       List.fold_right
1058        (fun (_,_,ty,bo) i ->
1059          i && guarded_by_destructors ~subst context n nn kl x_plus_len safes' ty &&
1060           guarded_by_destructors ~subst (tys@context) n_plus_len nn_plus_len kl
1061            x_plus_len safes' bo
1062        ) fl true
1063  | C.CoFix (_, fl) ->
1064     let len = List.length fl in
1065      let n_plus_len = n + len
1066      and nn_plus_len = nn + len
1067      and x_plus_len = x + len
1068      and tys,_ =
1069       List.fold_left
1070         (fun (types,len) (n,ty,_) ->
1071            (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1072             len+1)
1073         ) ([],0) fl
1074      and safes' = List.map (fun x -> x + len) safes in
1075       List.fold_right
1076        (fun (_,ty,bo) i ->
1077          i &&
1078           guarded_by_destructors ~subst context n nn kl x_plus_len safes' ty &&
1079           guarded_by_destructors ~subst (tys@context) n_plus_len nn_plus_len kl
1080            x_plus_len safes' bo
1081        ) fl true
1082 *)
1083
1084 and guarded_by_constructors ~subst _ _ _ _ _ _ _ = assert false
1085
1086 and recursive_args ~subst context n nn te =
1087   match R.whd context te with
1088   | C.Rel _ -> []
1089   | C.Prod (name,so,de) ->
1090      (not (does_not_occur ~subst context n nn so)) ::
1091       (recursive_args ~subst ((name,(C.Decl so))::context) (n+1) (nn + 1) de)
1092   | _ -> raise (AssertFailure (lazy ("recursive_args")))
1093
1094 and get_new_safes ~subst (context, recfuns, x, safes as k) p rl =
1095   match R.whd ~subst context p, rl with
1096   | C.Lambda (name,so,ta), b::tl ->
1097       let safes = (if b then [0] else []) @ safes in
1098       get_new_safes ~subst 
1099         (shift_k (name,(C.Decl so)) (context, recfuns, x, safes)) ta tl
1100   | C.Meta _ as e, _ | e, [] -> e, k
1101   | _ -> raise (AssertFailure (lazy "Ill formed pattern"))
1102
1103 and split_prods ~subst context n te =
1104   match n, R.whd ~subst context te with
1105   | 0, _ -> context,te
1106   | n, C.Prod (name,so,ta) when n > 0 ->
1107        split_prods ~subst ((name,(C.Decl so))::context) (n - 1) ta
1108   | _ -> raise (AssertFailure (lazy "split_prods"))
1109
1110 (*CSC: Tutto quello che segue e' l'intuzione di luca ;-) *) 
1111 and is_really_smaller ~subst (context, recfuns, x, safes as k) te =
1112  match R.whd ~subst context te with
1113  | C.Rel m when List.mem m safes -> true
1114  | C.Rel _ -> false
1115  | C.LetIn _ -> raise (AssertFailure (lazy "letin after whd"))
1116  | C.Sort _ | C.Implicit _ | C.Prod _ | C.Lambda _ 
1117  | C.Const (Ref.Ref (_,_,(Ref.Decl | Ref.Def | Ref.Ind _ | Ref.CoFix _))) ->
1118     raise (AssertFailure (lazy "not a constructor"))
1119  | C.Appl ([]|[_]) -> raise (AssertFailure (lazy "empty/unary appl"))
1120  | C.Appl (he::_) ->
1121     (*CSC: sulla coda ci vogliono dei controlli? secondo noi no, ma *)
1122     (*CSC: solo perche' non abbiamo trovato controesempi            *)
1123     is_really_smaller ~subst k he
1124  | C.Const (Ref.Ref (_,_,Ref.Con _)) -> false
1125  | C.Const (Ref.Ref (_,_,Ref.Fix _)) -> assert false
1126    (*| C.Fix (_, fl) ->
1127       let len = List.length fl in
1128        let n_plus_len = n + len
1129        and nn_plus_len = nn + len
1130        and x_plus_len = x + len
1131        and tys,_ =
1132         List.fold_left
1133           (fun (types,len) (n,_,ty,_) ->
1134              (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1135               len+1)
1136           ) ([],0) fl
1137        and safes' = List.map (fun x -> x + len) safes in
1138         List.fold_right
1139          (fun (_,_,ty,bo) i ->
1140            i &&
1141             is_really_smaller ~subst (tys@context) n_plus_len nn_plus_len kl
1142              x_plus_len safes' bo
1143          ) fl true*)
1144  | C.Meta _ -> 
1145      true (* XXX if this check is repeated when the user completes the
1146              definition *)
1147  | C.Match (Ref.Ref (_,uri,_) as ref,outtype,term,pl) ->
1148     (match term with
1149     | C.Rel m | C.Appl (C.Rel m :: _ ) when List.mem m safes || m = x ->
1150         let isinductive, paramsno, tl, _, i = E.get_checked_indtys ref in
1151         if not isinductive then
1152           List.for_all (is_really_smaller ~subst k) pl
1153         else
1154           let c_ctx,len,cl = fix_lefts_in_constrs ~subst uri paramsno tl i in
1155           List.for_all2
1156            (fun p (_,_,debruijnedte) -> 
1157              let rl' = recursive_args ~subst c_ctx 0 len debruijnedte in
1158              let e, k = get_new_safes ~subst k p rl' in
1159              is_really_smaller ~subst k e)
1160            pl cl
1161     | _ -> List.for_all (is_really_smaller ~subst k) pl)
1162
1163 and returns_a_coinductive ~subst _ _ = assert false
1164
1165 and type_of_constant ref = assert false (* USARE typecheck_obj0 *)
1166 (* ALIAS typecheck *)
1167 (*
1168   let cobj,ugraph1 =
1169    match CicEnvironment.is_type_checked ~trust:true ugraph uri with
1170        CicEnvironment.CheckedObj (cobj,ugraph') -> cobj,ugraph'
1171      | CicEnvironment.UncheckedObj uobj ->
1172          logger#log (`Start_type_checking uri) ;
1173          let ugraph1_dust =
1174           typecheck_obj0 ~logger uri CicUniv.empty_ugraph uobj in
1175            try 
1176              CicEnvironment.set_type_checking_info uri ;
1177              logger#log (`Type_checking_completed uri) ;
1178              (match CicEnvironment.is_type_checked ~trust:false ugraph uri with
1179                   CicEnvironment.CheckedObj (cobj,ugraph') -> (cobj,ugraph')
1180                 | CicEnvironment.UncheckedObj _ -> raise CicEnvironmentError
1181              )
1182            with
1183             (*
1184               this is raised if set_type_checking_info is called on an object
1185               that has no associated universe file. If we are in univ_maker 
1186               phase this is OK since univ_maker will properly commit the 
1187               object.
1188             *)
1189                Invalid_argument s ->
1190                  (*debug_print (lazy s);*)
1191                  uobj,ugraph1_dust
1192   in
1193 CASO COSTRUTTORE
1194     match cobj with
1195         C.InductiveDefinition (dl,_,_,_) ->
1196           let (_,_,arity,_) = List.nth dl i in
1197             arity,ugraph1
1198       | _ ->
1199           raise (TypeCheckerFailure
1200            (lazy ("Unknown mutual inductive definition:" ^ U.string_of_uri uri)))
1201 CASO TIPO INDUTTIVO
1202     match cobj with
1203         C.InductiveDefinition (dl,_,_,_) ->
1204           let (_,_,_,cl) = List.nth dl i in
1205           let (_,ty) = List.nth cl (j-1) in
1206             ty,ugraph1
1207       | _ ->
1208           raise (TypeCheckerFailure
1209            (lazy ("Unknown mutual inductive definition:" ^ UriManager.string_of_uri uri)))
1210 CASO COSTANTE
1211 CASO FIX/COFIX
1212 *)
1213
1214 and typecheck_obj0 (uri,height,metasenv,subst,kind) =
1215  (* CSC: here we should typecheck the metasenv and the subst *)
1216  assert (metasenv = [] && subst = []);
1217  match kind with
1218    | C.Constant (_,_,Some te,ty,_) ->
1219       let _ = typeof ~subst ~metasenv [] ty in
1220       let ty_te = typeof ~subst ~metasenv [] te in
1221       if not (R.are_convertible ~subst ~metasenv [] ty_te ty) then
1222        raise (TypeCheckerFailure (lazy (Printf.sprintf
1223         "the type of the body is not the one expected:\n%s\nvs\n%s"
1224         (NCicPp.ppterm ty_te) (NCicPp.ppterm ty))))
1225    | C.Constant (_,_,None,ty,_) -> ignore (typeof ~subst ~metasenv [] ty)
1226    | C.Inductive _ as obj -> check_mutual_inductive_defs uri obj
1227    | C.Fixpoint (inductive,fl,_) ->
1228       let types,kl,len =
1229         List.fold_left
1230          (fun (types,kl,len) (_,name,k,ty,_) ->
1231            let _ = typeof ~subst ~metasenv [] ty in
1232             ((name,(C.Decl (S.lift len ty)))::types, k::kl,len+1)
1233          ) ([],[],0) fl
1234       in
1235         List.iter (fun (_,name,x,ty,bo) ->
1236          let ty_bo = typeof ~subst ~metasenv types bo in
1237          if not (R.are_convertible ~subst ~metasenv types ty_bo (S.lift len ty))
1238          then raise (TypeCheckerFailure (lazy ("(Co)Fix: ill-typed bodies")))
1239          else
1240           if inductive then begin
1241             let m, context = eat_lambdas ~subst types (x + 1) bo in
1242             (* guarded by destructors conditions D{f,k,x,M} *)
1243             let rec enum_from k = 
1244               function [] -> [] | v::tl -> (k,v)::enum_from (k+1) tl 
1245             in
1246             if not (guarded_by_destructors 
1247                       ~subst context (enum_from (x+1) kl) m) then
1248               raise(TypeCheckerFailure(lazy("Fix: not guarded by destructors")))
1249           end else
1250            match returns_a_coinductive ~subst [] ty with
1251             | None ->
1252                 raise (TypeCheckerFailure
1253                   (lazy "CoFix: does not return a coinductive type"))
1254             | Some uri ->
1255                 (* guarded by constructors conditions C{f,M} *)
1256                 if not (guarded_by_constructors ~subst
1257                     types 0 len false bo [] uri)
1258                 then
1259                   raise (TypeCheckerFailure
1260                    (lazy "CoFix: not guarded by constructors"))
1261           ) fl
1262
1263 let typecheck_obj (*uri*) obj = assert false (*
1264  let ugraph = typecheck_obj0 ~logger uri CicUniv.empty_ugraph obj in
1265  let ugraph, univlist, obj = CicUnivUtils.clean_and_fill uri obj ugraph in
1266   CicEnvironment.add_type_checked_obj uri (obj,ugraph,univlist)
1267 *)
1268 ;;