]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/interface/cicTypeChecker.ml
Initial revision
[helm.git] / helm / interface / cicTypeChecker.ml
diff --git a/helm/interface/cicTypeChecker.ml b/helm/interface/cicTypeChecker.ml
new file mode 100644 (file)
index 0000000..6343393
--- /dev/null
@@ -0,0 +1,1200 @@
+exception NotImplemented;;
+exception Impossible;;
+exception NotWellTyped of string;;
+exception WrongUriToConstant of string;;
+exception WrongUriToVariable of string;;
+exception WrongUriToMutualInductiveDefinitions of string;;
+exception ListTooShort;;
+exception NotPositiveOccurrences of string;;
+exception NotWellFormedTypeOfInductiveConstructor of string;;
+exception WrongRequiredArgument of string;;
+
+let fdebug = ref 0;;
+let debug t env =
+ let rec debug_aux t i =
+  let module C = Cic in
+  let module U = UriManager in
+   CicPp.ppobj (C.Variable ("DEBUG",
+    C.Prod (C.Name "-15", C.Const (U.uri_of_string "cic:/dummy-15",0),
+    C.Prod (C.Name "-14", C.Const (U.uri_of_string "cic:/dummy-14",0),
+    C.Prod (C.Name "-13", C.Const (U.uri_of_string "cic:/dummy-13",0),
+    C.Prod (C.Name "-12", C.Const (U.uri_of_string "cic:/dummy-12",0),
+    C.Prod (C.Name "-11", C.Const (U.uri_of_string "cic:/dummy-11",0),
+    C.Prod (C.Name "-10", C.Const (U.uri_of_string "cic:/dummy-10",0),
+    C.Prod (C.Name "-9", C.Const (U.uri_of_string "cic:/dummy-9",0),
+    C.Prod (C.Name "-8", C.Const (U.uri_of_string "cic:/dummy-8",0),
+    C.Prod (C.Name "-7", C.Const (U.uri_of_string "cic:/dummy-7",0),
+    C.Prod (C.Name "-6", C.Const (U.uri_of_string "cic:/dummy-6",0),
+     C.Prod (C.Name "-5", C.Const (U.uri_of_string "cic:/dummy-5",0),
+      C.Prod (C.Name "-4", C.Const (U.uri_of_string "cic:/dummy-4",0),
+       C.Prod (C.Name "-3", C.Const (U.uri_of_string "cic:/dummy-3",0),
+        C.Prod (C.Name "-2", C.Const (U.uri_of_string "cic:/dummy-2",0),
+         C.Prod (C.Name "-1", C.Const (U.uri_of_string "cic:/dummy-1",0),
+          t
+         )
+        )
+       )
+      )
+     )
+    )
+    )
+    )
+    )))))))
+    )) ^ "\n" ^ i
+ in
+  if !fdebug = 0 then
+   raise (NotWellTyped ("\n" ^ List.fold_right debug_aux (t::env) ""))
+   (*print_endline ("\n" ^ List.fold_right debug_aux (t::env) "") ; flush stdout*)
+;;
+
+let rec split l n =
+ match (l,n) with
+    (l,0) -> ([], l)
+  | (he::tl, n) -> let (l1,l2) = split tl (n-1) in (he::l1,l2)
+  | (_,_) -> raise ListTooShort
+;;
+
+exception CicCacheError;;
+
+let rec cooked_type_of_constant uri cookingsno =
+ let module C = Cic in
+ let module R = CicReduction in
+ let module U = UriManager in
+  let cobj =
+   match CicCache.is_type_checked uri cookingsno with
+      CicCache.CheckedObj cobj -> cobj
+    | CicCache.UncheckedObj uobj ->
+       (* let's typecheck the uncooked obj *)
+       (match uobj with
+           C.Definition (_,te,ty,_) ->
+             let _ = type_of ty in
+              if not (R.are_convertible (type_of te) ty) then
+               raise (NotWellTyped ("Constant " ^ (U.string_of_uri uri)))
+         | C.Axiom (_,ty,_) ->
+           (* only to check that ty is well-typed *)
+           let _ = type_of ty in ()
+         | C.CurrentProof (_,_,te,ty) ->
+             let _ = type_of ty in
+              if not (R.are_convertible (type_of te) ty) then
+               raise (NotWellTyped ("CurrentProof" ^ (U.string_of_uri uri)))
+         | _ -> raise (WrongUriToConstant (U.string_of_uri uri))
+       ) ;
+       CicCache.set_type_checking_info uri ;
+       match CicCache.is_type_checked uri cookingsno with
+          CicCache.CheckedObj cobj -> cobj
+        | CicCache.UncheckedObj _ -> raise CicCacheError
+  in
+   match cobj with
+      C.Definition (_,_,ty,_) -> ty
+    | C.Axiom (_,ty,_) -> ty
+    | C.CurrentProof (_,_,_,ty) -> ty
+    | _ -> raise (WrongUriToConstant (U.string_of_uri uri))
+
+and type_of_variable uri =
+ let module C = Cic in
+ let module R = CicReduction in
+  (* 0 because a variable is never cooked => no partial cooking at one level *)
+  match CicCache.is_type_checked uri 0 with
+     CicCache.CheckedObj (C.Variable (_,ty)) -> ty
+   | CicCache.UncheckedObj (C.Variable (_,ty)) ->
+      (* only to check that ty is well-typed *)
+      let _ = type_of ty in
+       CicCache.set_type_checking_info uri ;
+       ty
+   |  _ -> raise (WrongUriToVariable (UriManager.string_of_uri uri))
+
+and does_not_occur n nn te =
+ let module C = Cic in
+   (*CSC: whd sembra essere superflua perche' un caso in cui l'occorrenza *)
+   (*CSC: venga mangiata durante la whd sembra presentare problemi di *)
+   (*CSC: universi                                                    *)
+   match CicReduction.whd te with
+      C.Rel m when m > n && m <= nn -> false
+    | C.Rel _
+    | C.Var _
+    | C.Meta _
+    | C.Sort _
+    | C.Implicit -> true
+    | C.Cast (te,ty) -> does_not_occur n nn te && does_not_occur n nn ty
+    | C.Prod (_,so,dest) ->
+       does_not_occur n nn so && does_not_occur (n + 1) (nn + 1) dest
+    | C.Lambda (_,so,dest) ->
+       does_not_occur n nn so && does_not_occur (n + 1) (nn + 1) dest
+    | C.Appl l ->
+       List.fold_right (fun x i -> i && does_not_occur n nn x) l true
+    | C.Const _
+    | C.Abst _
+    | C.MutInd _
+    | C.MutConstruct _ -> true
+    | C.MutCase (_,_,_,out,te,pl) ->
+       does_not_occur n nn out && does_not_occur n nn te &&
+        List.fold_right (fun x i -> i && does_not_occur n nn x) pl true
+    | C.Fix (_,fl) ->
+       let len = List.length fl in
+        let n_plus_len = n + len in
+        let nn_plus_len = nn + len in
+         List.fold_right
+          (fun (_,_,ty,bo) i ->
+            i && does_not_occur n_plus_len nn_plus_len ty &&
+            does_not_occur n_plus_len nn_plus_len bo
+          ) fl true
+    | C.CoFix (_,fl) ->
+       let len = List.length fl in
+        let n_plus_len = n + len in
+        let nn_plus_len = nn + len in
+         List.fold_right
+          (fun (_,ty,bo) i ->
+            i && does_not_occur n_plus_len nn_plus_len ty &&
+            does_not_occur n_plus_len nn_plus_len bo
+          ) fl true
+
+(*CSC l'indice x dei tipi induttivi e' t.c. n < x <= nn *)
+(*CSC questa funzione e' simile alla are_all_occurrences_positive, ma fa *)
+(*CSC dei controlli leggermente diversi. Viene invocata solamente dalla  *)
+(*CSC strictly_positive                                                  *)
+(*CSC definizione (giusta???) tratta dalla mail di Hugo ;-)              *)
+and weakly_positive n nn uri te =
+ let module C = Cic in
+  (*CSC mettere in cicSubstitution *)
+  let rec subst_inductive_type_with_dummy_rel =
+   function
+      C.MutInd (uri',_,0) when UriManager.eq uri' uri ->
+       C.Rel 0 (* dummy rel *)
+    | C.Appl ((C.MutInd (uri',_,0))::tl) when UriManager.eq uri' uri ->
+       C.Rel 0 (* dummy rel *)
+    | C.Cast (te,ty) -> subst_inductive_type_with_dummy_rel te
+    | C.Prod (name,so,ta) ->
+       C.Prod (name, subst_inductive_type_with_dummy_rel so,
+        subst_inductive_type_with_dummy_rel ta)
+    | C.Lambda (name,so,ta) ->
+       C.Lambda (name, subst_inductive_type_with_dummy_rel so,
+        subst_inductive_type_with_dummy_rel ta)
+    | C.Appl tl ->
+       C.Appl (List.map subst_inductive_type_with_dummy_rel tl)
+    | C.MutCase (uri,cookingsno,i,outtype,term,pl) ->
+       C.MutCase (uri,cookingsno,i,
+        subst_inductive_type_with_dummy_rel outtype,
+        subst_inductive_type_with_dummy_rel term,
+        List.map subst_inductive_type_with_dummy_rel pl)
+    | C.Fix (i,fl) ->
+       C.Fix (i,List.map (fun (name,i,ty,bo) -> (name,i,
+        subst_inductive_type_with_dummy_rel ty,
+        subst_inductive_type_with_dummy_rel bo)) fl)
+    | C.CoFix (i,fl) ->
+       C.CoFix (i,List.map (fun (name,ty,bo) -> (name,
+        subst_inductive_type_with_dummy_rel ty,
+        subst_inductive_type_with_dummy_rel bo)) fl)
+    | t -> t
+  in
+  match CicReduction.whd te with
+     C.Appl ((C.MutInd (uri',_,0))::tl) when UriManager.eq uri' uri -> true
+   | C.MutInd (uri',_,0) when UriManager.eq uri' uri -> true
+   | C.Prod (C.Anonimous,source,dest) ->
+      strictly_positive n nn (subst_inductive_type_with_dummy_rel source) &&
+       weakly_positive (n + 1) (nn + 1) uri dest
+   | C.Prod (name,source,dest) when does_not_occur 0 n dest ->
+      (* dummy abstraction, so we behave as in the anonimous case *)
+      strictly_positive n nn (subst_inductive_type_with_dummy_rel source) &&
+       weakly_positive (n + 1) (nn + 1) uri dest
+   | C.Prod (_,source,dest) ->
+      does_not_occur n nn (subst_inductive_type_with_dummy_rel source) &&
+       weakly_positive (n + 1) (nn + 1) uri dest
+   | _ -> raise (NotWellFormedTypeOfInductiveConstructor ("Guess where the error is ;-)"))
+
+(* instantiate_parameters ps (x1:T1)...(xn:Tn)C                             *)
+(* returns ((x_|ps|:T_|ps|)...(xn:Tn)C){ps_1 / x1 ; ... ; ps_|ps| / x_|ps|} *)
+and instantiate_parameters params c =
+ let module C = Cic in
+  match (c,params) with
+     (c,[]) -> c
+   | (C.Prod (_,_,ta), he::tl) ->
+       instantiate_parameters tl
+        (CicSubstitution.subst he ta)
+   | (C.Cast (te,_), _) -> instantiate_parameters params te
+   | (t,l) -> raise Impossible
+
+and strictly_positive n nn te =
+ let module C = Cic in
+ let module U = UriManager in
+  match CicReduction.whd te with
+     C.Rel _ -> true
+   | C.Cast (te,ty) ->
+      (*CSC: bisogna controllare ty????*)
+      strictly_positive n nn te
+   | C.Prod (_,so,ta) ->
+      does_not_occur n nn so &&
+       strictly_positive (n+1) (nn+1) ta
+   | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
+      List.fold_right (fun x i -> i && does_not_occur n nn x) tl true
+   | C.Appl ((C.MutInd (uri,_,i))::tl) -> 
+      let (ok,paramsno,cl) =
+       match CicCache.get_obj uri with
+           C.InductiveDefinition (tl,_,paramsno) ->
+            let (_,_,_,cl) = List.nth tl i in
+             (List.length tl = 1, paramsno, cl)
+         | _ -> raise(WrongUriToMutualInductiveDefinitions(U.string_of_uri uri))
+      in
+       let (params,arguments) = split tl paramsno in
+       let lifted_params = List.map (CicSubstitution.lift 1) params in
+       let cl' =
+        List.map (fun (_,te,_) -> instantiate_parameters lifted_params te) cl
+       in
+        ok &&
+         List.fold_right
+          (fun x i -> i && does_not_occur n nn x)
+          arguments true &&
+         (*CSC: MEGAPATCH3 (sara' quella giusta?)*)
+         List.fold_right
+          (fun x i ->
+            i &&
+             weakly_positive (n+1) (nn+1) uri x
+          ) cl' true
+   | C.MutInd (uri,_,i) ->
+      (match CicCache.get_obj uri with
+          C.InductiveDefinition (tl,_,_) ->
+           List.length tl = 1
+        | _ -> raise (WrongUriToMutualInductiveDefinitions(U.string_of_uri uri))
+      )
+   | t -> does_not_occur n nn t
+
+(*CSC l'indice x dei tipi induttivi e' t.c. n < x <= nn *)
+and are_all_occurrences_positive uri indparamsno i n nn te =
+ let module C = Cic in
+  match CicReduction.whd te with
+     C.Appl ((C.Rel m)::tl) when m = i ->
+      (*CSC: riscrivere fermandosi a 0 *)
+      (* let's check if the inductive type is applied at least to *)
+      (* indparamsno parameters                                   *)
+      let last =
+       List.fold_left
+        (fun k x ->
+          if k = 0 then 0
+          else
+           match CicReduction.whd x with
+              C.Rel m when m = n - (indparamsno - k) -> k - 1
+            | _ -> raise (WrongRequiredArgument (UriManager.string_of_uri uri))
+        ) indparamsno tl
+      in
+       if last = 0 then
+        List.fold_right (fun x i -> i && does_not_occur n nn x) tl true
+       else
+        raise (WrongRequiredArgument (UriManager.string_of_uri uri))
+   | C.Rel m when m = i ->
+      if indparamsno = 0 then
+       true
+      else
+       raise (WrongRequiredArgument (UriManager.string_of_uri uri))
+   | C.Prod (C.Anonimous,source,dest) ->
+      strictly_positive n nn source &&
+       are_all_occurrences_positive uri indparamsno (i+1) (n + 1) (nn + 1) dest
+   | C.Prod (name,source,dest) when does_not_occur 0 n dest ->
+      (* dummy abstraction, so we behave as in the anonimous case *)
+      strictly_positive n nn source &&
+       are_all_occurrences_positive uri indparamsno (i+1) (n + 1) (nn + 1) dest
+   | C.Prod (_,source,dest) ->
+      does_not_occur n nn source &&
+       are_all_occurrences_positive uri indparamsno (i+1) (n + 1) (nn + 1) dest
+   | _ -> raise (NotWellFormedTypeOfInductiveConstructor (UriManager.string_of_uri uri))
+
+(*CSC: cambiare il nome, torna unit! *)
+and cooked_mutual_inductive_defs uri =
+ let module U = UriManager in
+  function
+     Cic.InductiveDefinition (itl, _, indparamsno) ->
+      (* let's check if the arity of the inductive types are well *)
+      (* formed                                                   *)
+      List.iter (fun (_,_,x,_) -> let _ = type_of x in ()) itl ;
+
+      (* let's check if the types of the inductive constructors  *)
+      (* are well formed.                                        *)
+      (* In order not to use type_of_aux we put the types of the *)
+      (* mutual inductive types at the head of the types of the  *)
+      (* constructors using Prods                                *)
+      (*CSC: piccola??? inefficienza                             *)
+      let len = List.length itl in
+       let _ =
+        List.fold_right
+         (fun (_,_,_,cl) i ->
+           List.iter
+            (fun (name,te,r) -> 
+              let augmented_term =
+               List.fold_right
+                (fun (name,_,ty,_) i -> Cic.Prod (Cic.Name name, ty, i))
+                itl te
+              in
+               let _ = type_of augmented_term in
+                (* let's check also the positivity conditions *)
+                if not (are_all_occurrences_positive uri indparamsno i 0 len te)
+                then
+                 raise (NotPositiveOccurrences (U.string_of_uri uri))
+                else
+                 match !r with
+                    Some _ -> raise Impossible
+                  | None -> r := Some (recursive_args 0 len te)
+            ) cl ;
+           (i + 1)
+        ) itl 1
+       in
+        ()
+   | _ ->
+     raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
+
+and cooked_type_of_mutual_inductive_defs uri cookingsno i =
+ let module C = Cic in
+ let module R = CicReduction in
+ let module U = UriManager in
+  let cobj =
+   match CicCache.is_type_checked uri cookingsno with
+      CicCache.CheckedObj cobj -> cobj
+    | CicCache.UncheckedObj uobj ->
+       cooked_mutual_inductive_defs uri uobj ;
+       CicCache.set_type_checking_info uri ;
+       (match CicCache.is_type_checked uri cookingsno with
+          CicCache.CheckedObj cobj -> cobj
+        | CicCache.UncheckedObj _ -> raise CicCacheError
+       )
+  in
+   match cobj with
+      C.InductiveDefinition (dl,_,_) ->
+       let (_,_,arity,_) = List.nth dl i in
+        arity
+    | _ -> raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
+
+and cooked_type_of_mutual_inductive_constr uri cookingsno i j =
+ let module C = Cic in
+ let module R = CicReduction in
+ let module U = UriManager in
+  let cobj =
+   match CicCache.is_type_checked uri cookingsno with
+      CicCache.CheckedObj cobj -> cobj
+    | CicCache.UncheckedObj uobj ->
+       cooked_mutual_inductive_defs uri uobj ;
+       CicCache.set_type_checking_info uri ;
+       (match CicCache.is_type_checked uri cookingsno with
+          CicCache.CheckedObj cobj -> cobj
+        | CicCache.UncheckedObj _ -> raise CicCacheError
+       )
+  in
+   match cobj with
+      C.InductiveDefinition (dl,_,_) ->
+       let (_,_,_,cl) = List.nth dl i in
+        let (_,ty,_) = List.nth cl (j-1) in
+         ty
+    | _ -> raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
+
+and recursive_args n nn te =
+ let module C = Cic in
+  match CicReduction.whd te with
+     C.Rel _ -> []
+   | C.Var _
+   | C.Meta _
+   | C.Sort _
+   | C.Implicit
+   | C.Cast _ (*CSC ??? *) -> raise Impossible (* due to type-checking *)
+   | C.Prod (_,so,de) ->
+      (not (does_not_occur n nn so))::(recursive_args (n+1) (nn + 1) de)
+   | C.Lambda _ -> raise Impossible (* due to type-checking *)
+   | C.Appl _ -> []
+   | C.Const _
+   | C.Abst _ -> raise Impossible
+   | C.MutInd _
+   | C.MutConstruct _
+   | C.MutCase _
+   | C.Fix _
+   | C.CoFix _ -> raise Impossible (* due to type-checking *)
+
+and get_new_safes p c rl safes n nn x =
+ let module C = Cic in
+ let module U = UriManager in
+ let module R = CicReduction in
+  match (R.whd c, R.whd p, rl) with
+     (C.Prod (_,_,ta1), C.Lambda (_,_,ta2), b::tl) ->
+       (* we are sure that the two sources are convertible because we *)
+       (* have just checked this. So let's go along ...               *)
+       let safes' =
+        List.map (fun x -> x + 1) safes
+       in
+        let safes'' =
+         if b then 1::safes' else safes'
+        in
+         get_new_safes ta2 ta1 tl safes'' (n+1) (nn+1) (x+1)
+   | (C.MutInd _, e, []) -> (e,safes,n,nn,x)
+   | (C.Appl _, e, []) -> (e,safes,n,nn,x)
+   | (_,_,_) -> raise Impossible
+
+and eat_prods n te =
+ let module C = Cic in
+ let module R = CicReduction in
+  match (n, R.whd te) with
+     (0, _) -> te
+   | (n, C.Prod (_,_,ta)) when n > 0 -> eat_prods (n - 1) ta
+   | (_, _) -> raise Impossible
+
+and eat_lambdas n te =
+ let module C = Cic in
+ let module R = CicReduction in
+  match (n, R.whd te) with
+     (0, _) -> (te, 0)
+   | (n, C.Lambda (_,_,ta)) when n > 0 ->
+      let (te, k) = eat_lambdas (n - 1) ta in
+       (te, k + 1)
+   | (_, _) -> raise Impossible
+
+(*CSC: Tutto quello che segue e' l'intuzione di luca ;-) *)
+and check_is_really_smaller_arg n nn kl x safes te =
+ (*CSC: forse la whd si puo' fare solo quando serve veramente. *)
+ (*CSC: cfr guarded_by_destructors                             *)
+ let module C = Cic in
+ let module U = UriManager in
+ match CicReduction.whd te with
+     C.Rel m when List.mem m safes -> true
+   | C.Rel _ -> false
+   | C.Var _
+   | C.Meta _
+   | C.Sort _
+   | C.Implicit 
+   | C.Cast _
+(*   | C.Cast (te,ty) ->
+      check_is_really_smaller_arg n nn kl x safes te &&
+       check_is_really_smaller_arg n nn kl x safes ty*)
+(*   | C.Prod (_,so,ta) ->
+      check_is_really_smaller_arg n nn kl x safes so &&
+       check_is_really_smaller_arg (n+1) (nn+1) kl (x+1)
+        (List.map (fun x -> x + 1) safes) ta*)
+   | C.Prod _ -> raise Impossible
+   | C.Lambda (_,so,ta) ->
+      check_is_really_smaller_arg n nn kl x safes so &&
+       check_is_really_smaller_arg (n+1) (nn+1) kl (x+1)
+        (List.map (fun x -> x + 1) safes) ta
+   | C.Appl (he::_) ->
+      (*CSC: sulla coda ci vogliono dei controlli? secondo noi no, ma *)
+      (*CSC: solo perche' non abbiamo trovato controesempi            *)
+      check_is_really_smaller_arg n nn kl x safes he
+   | C.Appl [] -> raise Impossible
+   | C.Const _
+   | C.Abst _
+   | C.MutInd _ -> raise Impossible
+   | C.MutConstruct _ -> false
+   | C.MutCase (uri,_,i,outtype,term,pl) ->
+      (match term with
+          C.Rel m when List.mem m safes || m = x ->
+           let (isinductive,paramsno,cl) =
+            match CicCache.get_obj uri with
+               C.InductiveDefinition (tl,_,paramsno) ->
+                let (_,isinductive,_,cl) = List.nth tl i in
+                 let cl' =
+                  List.map (fun (id,ty,r) -> (id, eat_prods paramsno ty, r)) cl
+                 in
+                  (isinductive,paramsno,cl')
+             | _ ->
+               raise (WrongUriToMutualInductiveDefinitions(U.string_of_uri uri))
+           in
+            if not isinductive then
+              List.fold_right
+               (fun p i -> i && check_is_really_smaller_arg n nn kl x safes p)
+               pl true
+            else
+              List.fold_right
+               (fun (p,(_,c,rl)) i ->
+                 let rl' =
+                  match !rl with
+                     Some rl' ->
+                      let (_,rl'') = split rl' paramsno in
+                       rl''
+                   | None -> raise Impossible
+                 in
+                  let (e,safes',n',nn',x') =
+                   get_new_safes p c rl' safes n nn x
+                  in
+                   i &&
+                   check_is_really_smaller_arg n' nn' kl x' safes' e
+               ) (List.combine pl cl) true
+        | C.Appl ((C.Rel m)::tl) when List.mem m safes || m = x ->
+           let (isinductive,paramsno,cl) =
+            match CicCache.get_obj uri with
+               C.InductiveDefinition (tl,_,paramsno) ->
+                let (_,isinductive,_,cl) = List.nth tl i in
+                 let cl' =
+                  List.map (fun (id,ty,r) -> (id, eat_prods paramsno ty, r)) cl
+                 in
+                  (isinductive,paramsno,cl')
+             | _ ->
+               raise (WrongUriToMutualInductiveDefinitions(U.string_of_uri uri))
+           in
+            if not isinductive then
+              List.fold_right
+               (fun p i -> i && check_is_really_smaller_arg n nn kl x safes p)
+               pl true
+            else
+              (*CSC: supponiamo come prima che nessun controllo sia necessario*)
+              (*CSC: sugli argomenti di una applicazione                      *)
+              List.fold_right
+               (fun (p,(_,c,rl)) i ->
+                 let rl' =
+                  match !rl with
+                     Some rl' ->
+                      let (_,rl'') = split rl' paramsno in
+                       rl''
+                   | None -> raise Impossible
+                 in
+                  let (e, safes',n',nn',x') =
+                   get_new_safes p c rl' safes n nn x
+                  in
+                   i &&
+                   check_is_really_smaller_arg n' nn' kl x' safes' e
+               ) (List.combine pl cl) true
+        | _ ->
+          List.fold_right
+           (fun p i -> i && check_is_really_smaller_arg n nn kl x safes p)
+           pl true
+      )
+   | C.Fix (_, fl) ->
+      let len = List.length fl in
+       let n_plus_len = n + len
+       and nn_plus_len = nn + len
+       and x_plus_len = x + len
+       and safes' = List.map (fun x -> x + len) safes in
+        List.fold_right
+         (fun (_,_,ty,bo) i ->
+           i &&
+            check_is_really_smaller_arg n_plus_len nn_plus_len kl x_plus_len
+             safes' bo
+         ) fl true
+   | C.CoFix (_, fl) ->
+      let len = List.length fl in
+       let n_plus_len = n + len
+       and nn_plus_len = nn + len
+       and x_plus_len = x + len
+       and safes' = List.map (fun x -> x + len) safes in
+        List.fold_right
+         (fun (_,ty,bo) i ->
+           i &&
+            check_is_really_smaller_arg n_plus_len nn_plus_len kl x_plus_len
+             safes' bo
+         ) fl true
+
+and guarded_by_destructors n nn kl x safes =
+ let module C = Cic in
+ let module U = UriManager in
+  function
+     C.Rel m when m > n && m <= nn -> false
+   | C.Rel _
+   | C.Var _
+   | C.Meta _
+   | C.Sort _
+   | C.Implicit -> true
+   | C.Cast (te,ty) ->
+      guarded_by_destructors n nn kl x safes te &&
+       guarded_by_destructors n nn kl x safes ty
+   | C.Prod (_,so,ta) ->
+      guarded_by_destructors n nn kl x safes so &&
+       guarded_by_destructors (n+1) (nn+1) kl (x+1)
+        (List.map (fun x -> x + 1) safes) ta
+   | C.Lambda (_,so,ta) ->
+      guarded_by_destructors n nn kl x safes so &&
+       guarded_by_destructors (n+1) (nn+1) kl (x+1)
+        (List.map (fun x -> x + 1) safes) ta
+   | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
+      let k = List.nth kl (m - n - 1) in
+       if not (List.length tl > k) then false
+       else
+        List.fold_right
+         (fun param i ->
+           i && guarded_by_destructors n nn kl x safes param
+         ) tl true &&
+         check_is_really_smaller_arg n nn kl x safes (List.nth tl k)
+   | C.Appl tl ->
+      List.fold_right (fun t i -> i && guarded_by_destructors n nn kl x safes t)
+       tl true
+   | C.Const _
+   | C.Abst _
+   | C.MutInd _
+   | C.MutConstruct _ -> true
+   | C.MutCase (uri,_,i,outtype,term,pl) ->
+      (match term with
+          C.Rel m when List.mem m safes || m = x ->
+           let (isinductive,paramsno,cl) =
+            match CicCache.get_obj uri with
+               C.InductiveDefinition (tl,_,paramsno) ->
+                let (_,isinductive,_,cl) = List.nth tl i in
+                 let cl' =
+                  List.map (fun (id,ty,r) -> (id, eat_prods paramsno ty, r)) cl
+                 in
+                  (isinductive,paramsno,cl')
+             | _ ->
+               raise (WrongUriToMutualInductiveDefinitions(U.string_of_uri uri))
+           in
+            if not isinductive then
+             guarded_by_destructors n nn kl x safes outtype &&
+              guarded_by_destructors n nn kl x safes term &&
+              (*CSC: manca ??? il controllo sul tipo di term? *)
+              List.fold_right
+               (fun p i -> i && guarded_by_destructors n nn kl x safes p)
+               pl true
+            else
+             guarded_by_destructors n nn kl x safes outtype &&
+              (*CSC: manca ??? il controllo sul tipo di term? *)
+              List.fold_right
+               (fun (p,(_,c,rl)) i ->
+                 let rl' =
+                  match !rl with
+                     Some rl' ->
+                      let (_,rl'') = split rl' paramsno in
+                       rl''
+                   | None -> raise Impossible
+                 in
+                  let (e,safes',n',nn',x') =
+                   get_new_safes p c rl' safes n nn x
+                  in
+                   i &&
+                   guarded_by_destructors n' nn' kl x' safes' e
+               ) (List.combine pl cl) true
+        | C.Appl ((C.Rel m)::tl) when List.mem m safes || m = x ->
+           let (isinductive,paramsno,cl) =
+            match CicCache.get_obj uri with
+               C.InductiveDefinition (tl,_,paramsno) ->
+                let (_,isinductive,_,cl) = List.nth tl i in
+                 let cl' =
+                  List.map (fun (id,ty,r) -> (id, eat_prods paramsno ty, r)) cl
+                 in
+                  (isinductive,paramsno,cl')
+             | _ ->
+               raise (WrongUriToMutualInductiveDefinitions(U.string_of_uri uri))
+           in
+            if not isinductive then
+             guarded_by_destructors n nn kl x safes outtype &&
+              guarded_by_destructors n nn kl x safes term &&
+              (*CSC: manca ??? il controllo sul tipo di term? *)
+              List.fold_right
+               (fun p i -> i && guarded_by_destructors n nn kl x safes p)
+               pl true
+            else
+             guarded_by_destructors n nn kl x safes outtype &&
+              (*CSC: manca ??? il controllo sul tipo di term? *)
+              List.fold_right
+               (fun t i -> i && guarded_by_destructors n nn kl x safes t)
+               tl true &&
+              List.fold_right
+               (fun (p,(_,c,rl)) i ->
+                 let rl' =
+                  match !rl with
+                     Some rl' ->
+                      let (_,rl'') = split rl' paramsno in
+                       rl''
+                   | None -> raise Impossible
+                 in
+                  let (e, safes',n',nn',x') =
+                   get_new_safes p c rl' safes n nn x
+                  in
+                   i &&
+                   guarded_by_destructors n' nn' kl x' safes' e
+               ) (List.combine pl cl) true
+        | _ ->
+          guarded_by_destructors n nn kl x safes outtype &&
+           guarded_by_destructors n nn kl x safes term &&
+           (*CSC: manca ??? il controllo sul tipo di term? *)
+           List.fold_right
+            (fun p i -> i && guarded_by_destructors n nn kl x safes p)
+            pl true
+      )
+   | C.Fix (_, fl) ->
+      let len = List.length fl in
+       let n_plus_len = n + len
+       and nn_plus_len = nn + len
+       and x_plus_len = x + len
+       and safes' = List.map (fun x -> x + len) safes in
+        List.fold_right
+         (fun (_,_,ty,bo) i ->
+           i && guarded_by_destructors n_plus_len nn_plus_len kl x_plus_len
+            safes' ty &&
+            guarded_by_destructors n_plus_len nn_plus_len kl x_plus_len
+             safes' bo
+         ) fl true
+   | C.CoFix (_, fl) ->
+      let len = List.length fl in
+       let n_plus_len = n + len
+       and nn_plus_len = nn + len
+       and x_plus_len = x + len
+       and safes' = List.map (fun x -> x + len) safes in
+        List.fold_right
+         (fun (_,ty,bo) i ->
+           i && guarded_by_destructors n_plus_len nn_plus_len kl x_plus_len
+            safes' ty &&
+            guarded_by_destructors n_plus_len nn_plus_len kl x_plus_len safes'
+             bo
+         ) fl true
+
+(*CSC h = 0 significa non ancora protetto *)
+and guarded_by_constructors n nn h =
+ let module C = Cic in
+  function
+     C.Rel m when m > n && m <= nn -> h = 1
+   | C.Rel _
+   | C.Var _ 
+   | C.Meta _
+   | C.Sort _
+   | C.Implicit -> true (*CSC: ma alcuni sono impossibili!!!! vedi Prod *)
+   | C.Cast (te,ty) ->
+      guarded_by_constructors n nn h te &&
+       guarded_by_constructors n nn h ty
+   | C.Prod (_,so,de) ->
+      raise Impossible (* the term has just been type-checked *)
+   | C.Lambda (_,so,de) ->
+      does_not_occur n nn so &&
+       guarded_by_constructors (n + 1) (nn + 1) h de
+   | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
+      h = 1 &&
+       List.fold_right (fun x i -> i && does_not_occur n nn x) tl true
+   | C.Appl ((C.MutConstruct (uri,cookingsno,i,j))::tl) ->
+      let (is_coinductive, rl) =
+       match CicCache.get_cooked_obj uri cookingsno with
+          C.InductiveDefinition (itl,_,_) ->
+           let (_,is_inductive,_,cl) = List.nth itl i in
+            let (_,cons,rrec_args) = List.nth cl (j - 1) in
+             (match !rrec_args with
+                 None -> raise Impossible
+               | Some rec_args -> (not is_inductive, rec_args)
+             )
+        | _ ->
+         raise (WrongUriToMutualInductiveDefinitions
+          (UriManager.string_of_uri uri))
+      in
+       is_coinductive &&
+       List.fold_right
+        (fun (x,r) i ->
+          i &&
+           if r then
+            guarded_by_constructors n nn 1 x
+           else
+            does_not_occur n nn x
+        ) (List.combine tl rl) true
+   | C.Appl l ->
+      List.fold_right (fun x i -> i && does_not_occur n nn x) l true
+   | C.Const _
+   | C.Abst _
+   | C.MutInd _ 
+   | C.MutConstruct _ -> true (*CSC: ma alcuni sono impossibili!!!! vedi Prod *)
+   | C.MutCase (_,_,_,out,te,pl) ->
+      let rec returns_a_coinductive =
+       function
+          (*CSC: per le regole di tipaggio, la chiamata ricorsiva verra' *)
+          (*CSC: effettata solo una volta, per mangiarsi l'astrazione    *)
+          (*CSC: non dummy                                               *)
+          C.Lambda (_,_,de) -> returns_a_coinductive de
+        | C.MutInd (uri,_,i) ->
+           (*CSC: definire una funzioncina per questo codice sempre replicato *)
+           (match CicCache.get_obj uri with
+               C.InductiveDefinition (itl,_,_) ->
+                let (_,is_inductive,_,_) = List.nth itl i in
+                 not is_inductive
+             | _ ->
+               raise (WrongUriToMutualInductiveDefinitions
+                (UriManager.string_of_uri uri))
+            )
+        (*CSC: bug nella prossima riga (manca la whd) *)
+        | C.Appl ((C.MutInd (uri,_,i))::_) ->
+           (match CicCache.get_obj uri with
+               C.InductiveDefinition (itl,_,_) ->
+                let (_,is_inductive,_,_) = List.nth itl i in
+                 not is_inductive
+             | _ ->
+               raise (WrongUriToMutualInductiveDefinitions
+                (UriManager.string_of_uri uri))
+            )
+        | _ -> false
+      in
+       does_not_occur n nn out &&
+        does_not_occur n nn te &&
+        if returns_a_coinductive out then
+         List.fold_right
+          (fun x i -> i && guarded_by_constructors n nn h x) pl true
+        else
+         List.fold_right (fun x i -> i && does_not_occur n nn x) pl true
+   | C.Fix (_,fl) ->
+      let len = List.length fl in
+       let n_plus_len = n + len
+       and nn_plus_len = nn + len in
+        List.fold_right
+         (fun (_,_,ty,bo) i ->
+           i && does_not_occur n_plus_len nn_plus_len ty &&
+            does_not_occur n_plus_len nn_plus_len bo
+         ) fl true
+   | C.CoFix (_,fl) ->
+      let len = List.length fl in
+       let n_plus_len = n + len
+       and nn_plus_len = nn + len in
+        List.fold_right
+         (fun (_,ty,bo) i ->
+           i && does_not_occur n_plus_len nn_plus_len ty &&
+            does_not_occur n_plus_len nn_plus_len bo
+         ) fl true
+
+and check_allowed_sort_elimination uri i need_dummy ind arity1 arity2 =
+ let module C = Cic in
+ let module U = UriManager in
+  match (CicReduction.whd arity1, CicReduction.whd arity2) with
+     (C.Prod (_,so1,de1), C.Prod (_,so2,de2))
+      when CicReduction.are_convertible so1 so2 ->
+       check_allowed_sort_elimination uri i need_dummy
+        (C.Appl [CicSubstitution.lift 1 ind ; C.Rel 1]) de1 de2
+   | (C.Sort C.Prop, C.Sort C.Prop) when need_dummy -> true
+   | (C.Sort C.Prop, C.Sort C.Set) when need_dummy ->
+       (match CicCache.get_obj uri with
+           C.InductiveDefinition (itl,_,_) ->
+            let (_,_,_,cl) = List.nth itl i in
+             (* is a singleton definition? *)
+             List.length cl = 1
+         | _ ->
+           raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
+       )
+   | (C.Sort C.Set, C.Sort C.Prop) when need_dummy -> true
+   | (C.Sort C.Set, C.Sort C.Set) when need_dummy -> true
+   | (C.Sort C.Set, C.Sort C.Type) when need_dummy ->
+       (match CicCache.get_obj uri with
+           C.InductiveDefinition (itl,_,_) ->
+            let (_,_,_,cl) = List.nth itl i in
+             (* is a small inductive type? *)
+             (*CSC: ottimizzare calcolando staticamente *)
+             let rec is_small =
+              function
+                 C.Prod (_,so,de) ->
+                  let s = type_of so in
+                   (s = C.Sort C.Prop || s = C.Sort C.Set) &&
+                   is_small de
+               | _ -> true (*CSC: we trust the type-checker *)
+             in
+              List.fold_right (fun (_,x,_) i -> i && is_small x) cl true
+         | _ ->
+           raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
+       )
+   | (C.Sort C.Type, C.Sort _) when need_dummy -> true
+   | (C.Sort C.Prop, C.Prod (_,so,ta)) when not need_dummy ->
+       let res = CicReduction.are_convertible so ind
+       in
+        res &&
+        (match CicReduction.whd ta with
+            C.Sort C.Prop -> true
+          | C.Sort C.Set ->
+             (match CicCache.get_obj uri with
+                 C.InductiveDefinition (itl,_,_) ->
+                  let (_,_,_,cl) = List.nth itl i in
+                   (* is a singleton definition? *)
+                   List.length cl = 1
+               | _ ->
+                 raise (WrongUriToMutualInductiveDefinitions
+                  (U.string_of_uri uri))
+             )
+          | _ -> false
+        )
+   | (C.Sort C.Set, C.Prod (_,so,ta)) when not need_dummy ->
+       let res = CicReduction.are_convertible so ind
+       in
+        res &&
+        (match CicReduction.whd ta with
+            C.Sort C.Prop
+          | C.Sort C.Set  -> true
+          | C.Sort C.Type ->
+             (match CicCache.get_obj uri with
+                 C.InductiveDefinition (itl,_,_) ->
+                  let (_,_,_,cl) = List.nth itl i in
+                   (* is a small inductive type? *)
+                   let rec is_small =
+                    function
+                       C.Prod (_,so,de) ->
+                        let s = type_of so in
+                         (s = C.Sort C.Prop || s = C.Sort C.Set) &&
+                         is_small de
+                     | _ -> true (*CSC: we trust the type-checker *)
+                   in
+                    List.fold_right (fun (_,x,_) i -> i && is_small x) cl true
+               | _ ->
+                 raise (WrongUriToMutualInductiveDefinitions
+                  (U.string_of_uri uri))
+             )
+          | _ -> raise Impossible
+        )
+   | (C.Sort C.Type, C.Prod (_,so,_)) when not need_dummy ->
+       CicReduction.are_convertible so ind
+   | (_,_) -> false
+  
+and type_of_branch argsno need_dummy outtype term constype =
+ let module C = Cic in
+ let module R = CicReduction in
+  match R.whd constype with
+     C.MutInd (_,_,_) ->
+      if need_dummy then
+       outtype
+      else
+       C.Appl [outtype ; term]
+   | C.Appl (C.MutInd (_,_,_)::tl) ->
+      let (_,arguments) = split tl argsno
+      in
+       if need_dummy && arguments = [] then
+        outtype
+       else
+        C.Appl (outtype::arguments@(if need_dummy then [] else [term]))
+   | C.Prod (name,so,de) ->
+      C.Prod (C.Name "pippo",so,type_of_branch argsno need_dummy 
+       (CicSubstitution.lift 1 outtype)
+       (C.Appl [CicSubstitution.lift 1 term ; C.Rel 1]) de)
+  | _ -> raise Impossible
+       
+and type_of t =
+ let rec type_of_aux env =
+  let module C = Cic in
+  let module R = CicReduction in
+  let module S = CicSubstitution in
+  let module U = UriManager in
+   function
+      C.Rel n -> S.lift n (List.nth env (n - 1))
+    | C.Var uri ->
+      incr fdebug ;
+      let ty = type_of_variable uri in
+       decr fdebug ;
+       ty
+    | C.Meta n -> raise NotImplemented
+    | C.Sort s -> C.Sort C.Type (*CSC manca la gestione degli universi!!! *)
+    | C.Implicit -> raise Impossible
+    | C.Cast (te,ty) ->
+       let _ = type_of ty in
+        if R.are_convertible (type_of_aux env te) ty then ty
+        else raise (NotWellTyped "Cast")
+    | C.Prod (_,s,t) ->
+       let sort1 = type_of_aux env s
+       and sort2 = type_of_aux (s::env) t in
+        sort_of_prod (sort1,sort2)
+   | C.Lambda (n,s,t) ->
+       let sort1 = type_of_aux env s
+       and type2 = type_of_aux (s::env) t in
+        let sort2 = type_of_aux (s::env) type2 in
+         (* only to check if the product is well-typed *)
+         let _ = sort_of_prod (sort1,sort2) in
+          C.Prod (n,s,type2)
+   | C.Appl (he::tl) when List.length tl > 0 ->
+      let hetype = type_of_aux env he
+      and tlbody_and_type = List.map (fun x -> (x, type_of_aux env x)) tl in
+       (try
+        eat_prods hetype tlbody_and_type
+       with _ -> debug (C.Appl (he::tl)) env ; C.Implicit)
+   | C.Appl _ -> raise (NotWellTyped "Appl: no arguments")
+   | C.Const (uri,cookingsno) ->
+      incr fdebug ;
+      let cty = cooked_type_of_constant uri cookingsno in
+       decr fdebug ;
+       cty
+   | C.Abst _ -> raise Impossible
+   | C.MutInd (uri,cookingsno,i) ->
+      incr fdebug ;
+      let cty = cooked_type_of_mutual_inductive_defs uri cookingsno i in
+       decr fdebug ;
+       cty
+   | C.MutConstruct (uri,cookingsno,i,j) ->
+      let cty = cooked_type_of_mutual_inductive_constr uri cookingsno i j
+      in
+       cty
+   | C.MutCase (uri,cookingsno,i,outtype,term,pl) ->
+      let outsort = type_of_aux env outtype in
+      let (need_dummy, k) =
+       let rec guess_args t =
+        match decast t with
+           C.Sort _ -> (true, 0)
+         | C.Prod (_, s, t) ->
+            let (b, n) = guess_args t in
+             if n = 0 then
+              (* last prod before sort *)
+              match CicReduction.whd s with
+                 (*CSC vedi nota delirante su cookingsno in cicReduction.ml *)
+                 C.MutInd (uri',_,i') when U.eq uri' uri && i' = i -> (false, 1)
+               | C.Appl ((C.MutInd (uri',_,i')) :: _)
+                  when U.eq uri' uri && i' = i -> (false, 1)
+               | _ -> (true, 1)
+             else
+              (b, n + 1)
+         | _ -> raise (NotWellTyped "MutCase: outtype ill-formed")
+       in
+        (*CSC whd non serve dopo type_of_aux ? *)
+        let (b, k) = guess_args outsort in
+         if not b then (b, k - 1) else (b, k)
+      in
+      let (parameters, arguments) =
+        match R.whd (type_of_aux env term) with
+           (*CSC manca il caso dei CAST *)
+           C.MutInd (uri',_,i') ->
+            (*CSC vedi nota delirante sui cookingsno in cicReduction.ml*)
+            if U.eq uri uri' && i = i' then ([],[])
+            else raise (NotWellTyped ("MutCase: the term is of type " ^
+             (U.string_of_uri uri') ^ "," ^ string_of_int i' ^
+             " instead of type " ^ (U.string_of_uri uri') ^ "," ^
+             string_of_int i))
+         | C.Appl (C.MutInd (uri',_,i') :: tl) ->
+            if U.eq uri uri' && i = i' then split tl (List.length tl - k)
+            else raise (NotWellTyped ("MutCase: the term is of type " ^
+             (U.string_of_uri uri') ^ "," ^ string_of_int i' ^
+             " instead of type " ^ (U.string_of_uri uri) ^ "," ^
+             string_of_int i))
+         | _ -> raise (NotWellTyped "MutCase: the term is not an inductive one")
+      in
+       (* let's control if the sort elimination is allowed: [(I q1 ... qr)|B] *)
+       let sort_of_ind_type =
+        if parameters = [] then
+         C.MutInd (uri,cookingsno,i)
+        else
+         C.Appl ((C.MutInd (uri,cookingsno,i))::parameters)
+       in
+        if not (check_allowed_sort_elimination uri i need_dummy
+         sort_of_ind_type (type_of_aux env sort_of_ind_type) outsort)
+        then
+         raise (NotWellTyped "MutCase: not allowed sort elimination") ;
+
+        (* let's check if the type of branches are right *)
+        let (cl,parsno) =
+         match CicCache.get_cooked_obj uri cookingsno with
+            C.InductiveDefinition (tl,_,parsno) ->
+             let (_,_,_,cl) = List.nth tl i in (cl,parsno)
+          | _ ->
+            raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
+        in
+         let (_,branches_ok) =
+          List.fold_left
+           (fun (j,b) (p,(_,c,_)) ->
+             let cons =
+              if parameters = [] then
+               (C.MutConstruct (uri,cookingsno,i,j))
+              else
+               (C.Appl (C.MutConstruct (uri,cookingsno,i,j)::parameters))
+             in
+              (j + 1, b &&
+               R.are_convertible (type_of_aux env p)
+                (type_of_branch parsno need_dummy outtype cons
+                  (type_of_aux env cons))
+              )
+           ) (1,true) (List.combine pl cl)
+         in
+          if not branches_ok then
+           raise (NotWellTyped "MutCase: wrong type of a branch") ;
+
+          if not need_dummy then
+           C.Appl ((outtype::arguments)@[term])
+          else if arguments = [] then
+           outtype
+          else
+           C.Appl (outtype::arguments)
+   | C.Fix (i,fl) ->
+      let types_times_kl =
+       List.rev
+        (List.map (fun (_,k,ty,_) -> let _ = type_of_aux env ty in (ty,k)) fl)
+      in
+      let (types,kl) = List.split types_times_kl in
+       let len = List.length types in
+        List.iter
+         (fun (name,x,ty,bo) ->
+           if (R.are_convertible (type_of_aux (types @ env) bo)
+            (CicSubstitution.lift len ty))
+           then
+            begin
+             let (m, eaten) = eat_lambdas (x + 1) bo in
+              (*let's control the guarded by destructors conditions D{f,k,x,M}*)
+              if not (guarded_by_destructors eaten (len + eaten) kl 1 [] m) then
+               raise (NotWellTyped "Fix: not guarded by destructors")
+            end
+           else
+            raise (NotWellTyped "Fix: ill-typed bodies")
+         ) fl ;
+      
+        (*CSC: controlli mancanti solo su D{f,k,x,M} *)
+        let (_,_,ty,_) = List.nth fl i in
+        ty
+   | C.CoFix (i,fl) ->
+      let types =
+       List.rev (List.map (fun (_,ty,_) -> let _ = type_of_aux env ty in ty) fl)
+      in
+       let len = List.length types in
+        List.iter
+         (fun (_,ty,bo) ->
+           if (R.are_convertible (type_of_aux (types @ env) bo)
+            (CicSubstitution.lift len ty))
+           then
+            begin
+             (* let's control the guarded by constructors conditions C{f,M} *)
+             if not (guarded_by_constructors 0 len 0 bo) then
+              raise (NotWellTyped "CoFix: not guarded by constructors")
+            end
+           else
+            raise (NotWellTyped "CoFix: ill-typed bodies")
+         ) fl ;
+      
+        let (_,ty,_) = List.nth fl i in
+         ty
+
+ and decast =
+  let module C = Cic in
+   function
+      C.Cast (t,_) -> t
+    | t -> t
+
+ and sort_of_prod (t1, t2) =
+  let module C = Cic in
+   match (decast t1, decast t2) with
+      (C.Sort s1, C.Sort s2)
+        when (s2 = C.Prop or s2 = C.Set) -> (* different from Coq manual!!! *)
+         C.Sort s2
+    | (C.Sort s1, C.Sort s2) -> C.Sort C.Type (*CSC manca la gestione degli universi!!! *)
+    | (_,_) -> raise (NotWellTyped "Prod")
+
+ and eat_prods hetype =
+  (*CSC: siamo sicuri che le are_convertible non lavorino con termini non *)
+  (*CSC: cucinati                                                         *)
+  function
+     [] -> hetype
+   | (hete, hety)::tl ->
+    (match (CicReduction.whd hetype) with
+        Cic.Prod (n,s,t) ->
+         if CicReduction.are_convertible s hety then
+          (CicReduction.fdebug := -1 ;
+          eat_prods (CicSubstitution.subst hete t) tl
+          )
+         else
+          (
+          CicReduction.fdebug := 0 ;
+          let _ = CicReduction.are_convertible s hety in
+          debug hete [hety ; s] ;
+          raise (NotWellTyped "Appl: wrong parameter-type")
+)
+      | _ -> raise (NotWellTyped "Appl: wrong Prod-type")
+    )
+ in
+  type_of_aux [] t
+;;
+
+let typecheck uri =
+ let module C = Cic in
+ let module R = CicReduction in
+ let module U = UriManager in
+  match CicCache.is_type_checked uri 0 with
+     CicCache.CheckedObj _ -> ()
+   | CicCache.UncheckedObj uobj ->
+      (* let's typecheck the uncooked object *)
+      (match uobj with
+          C.Definition (_,te,ty,_) ->
+           let _ = type_of ty in
+            if not (R.are_convertible (type_of te ) ty) then
+             raise (NotWellTyped ("Constant " ^ (U.string_of_uri uri)))
+        | C.Axiom (_,ty,_) ->
+          (* only to check that ty is well-typed *)
+          let _ = type_of ty in ()
+        | C.CurrentProof (_,_,te,ty) ->
+           (*CSC [] wrong *)
+           let _ = type_of ty in
+            debug (type_of te) [] ;
+            if not (R.are_convertible (type_of te) ty) then
+             raise (NotWellTyped ("CurrentProof" ^ (U.string_of_uri uri)))
+        | C.Variable (_,ty) ->
+           (* only to check that ty is well-typed *)
+           (*CSC [] wrong *)
+           let _ = type_of ty in ()
+        | C.InductiveDefinition _ ->
+           cooked_mutual_inductive_defs uri uobj
+      ) ;
+      CicCache.set_type_checking_info uri
+;;