+(*
+ ||M|| This file is part of HELM, an Hypertextual, Electronic
+ ||A|| Library of Mathematics, developed at the Computer Science
+ ||T|| Department, University of Bologna, Italy.
+ ||I||
+ ||T|| HELM is free software; you can redistribute it and/or
+ ||A|| modify it under the terms of the GNU General Public License
+ \ / version 2 or (at your option) any later version.
+ \ / This software is distributed as is, NO WARRANTY.
+ V_______________________________________________________________ *)
+
+(* $Id: nCicReduction.ml 8250 2008-03-25 17:56:20Z tassi $ *)
+
+(* web interface stuff *)
+
+let logger =
+ ref (function (`Start_type_checking _|`Type_checking_completed _) -> ())
+;;
+
+let set_logger f = logger := f;;
exception TypeCheckerFailure of string Lazy.t
exception AssertFailure of string Lazy.t
-(* typechecks the object, raising an exception if illtyped *)
-let typecheck_obj obj = ()
+let shift_k e (c,rf,x,safes) =
+ e::c,List.map (fun (k,v) -> k+1,v) rf,x+1,List.map ((+)1) safes
+;;
+
+(* $Id: cicTypeChecker.ml 8213 2008-03-13 18:48:26Z sacerdot $ *)
+
+(*
+exception CicEnvironmentError;;
+
+(*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 context n nn uri te =
+ let module C = Cic in
+(*CSC: Che schifo! Bisogna capire meglio e trovare una soluzione ragionevole!*)
+ let dummy_mutind =
+ C.MutInd (HelmLibraryObjects.Datatypes.nat_URI,0,[])
+ in
+ (*CSC: mettere in cicSubstitution *)
+ let rec subst_inductive_type_with_dummy_mutind =
+ function
+ C.MutInd (uri',0,_) when UriManager.eq uri' uri ->
+ dummy_mutind
+ | C.Appl ((C.MutInd (uri',0,_))::tl) when UriManager.eq uri' uri ->
+ dummy_mutind
+ | C.Cast (te,ty) -> subst_inductive_type_with_dummy_mutind te
+ | C.Prod (name,so,ta) ->
+ C.Prod (name, subst_inductive_type_with_dummy_mutind so,
+ subst_inductive_type_with_dummy_mutind ta)
+ | C.Lambda (name,so,ta) ->
+ C.Lambda (name, subst_inductive_type_with_dummy_mutind so,
+ subst_inductive_type_with_dummy_mutind ta)
+ | C.Appl tl ->
+ C.Appl (List.map subst_inductive_type_with_dummy_mutind tl)
+ | C.MutCase (uri,i,outtype,term,pl) ->
+ C.MutCase (uri,i,
+ subst_inductive_type_with_dummy_mutind outtype,
+ subst_inductive_type_with_dummy_mutind term,
+ List.map subst_inductive_type_with_dummy_mutind pl)
+ | C.Fix (i,fl) ->
+ C.Fix (i,List.map (fun (name,i,ty,bo) -> (name,i,
+ subst_inductive_type_with_dummy_mutind ty,
+ subst_inductive_type_with_dummy_mutind bo)) fl)
+ | C.CoFix (i,fl) ->
+ C.CoFix (i,List.map (fun (name,ty,bo) -> (name,
+ subst_inductive_type_with_dummy_mutind ty,
+ subst_inductive_type_with_dummy_mutind bo)) fl)
+ | C.Const (uri,exp_named_subst) ->
+ let exp_named_subst' =
+ List.map
+ (function (uri,t) -> (uri,subst_inductive_type_with_dummy_mutind t))
+ exp_named_subst
+ in
+ C.Const (uri,exp_named_subst')
+ | C.MutInd (uri,typeno,exp_named_subst) ->
+ let exp_named_subst' =
+ List.map
+ (function (uri,t) -> (uri,subst_inductive_type_with_dummy_mutind t))
+ exp_named_subst
+ in
+ C.MutInd (uri,typeno,exp_named_subst')
+ | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
+ let exp_named_subst' =
+ List.map
+ (function (uri,t) -> (uri,subst_inductive_type_with_dummy_mutind t))
+ exp_named_subst
+ in
+ C.MutConstruct (uri,typeno,consno,exp_named_subst')
+ | t -> t
+ in
+ match CicReduction.whd context te with
+(*
+ C.Appl ((C.MutInd (uri',0,_))::tl) when UriManager.eq uri' uri -> true
+*)
+ C.Appl ((C.MutInd (uri',_,_))::tl) when UriManager.eq uri' uri -> true
+ | C.MutInd (uri',0,_) when UriManager.eq uri' uri -> true
+ | C.Prod (C.Anonymous,source,dest) ->
+ strictly_positive context n nn
+ (subst_inductive_type_with_dummy_mutind source) &&
+ weakly_positive ((Some (C.Anonymous,(C.Decl source)))::context)
+ (n + 1) (nn + 1) uri dest
+ | C.Prod (name,source,dest) when
+ does_not_occur ((Some (name,(C.Decl source)))::context) 0 n dest ->
+ (* dummy abstraction, so we behave as in the anonimous case *)
+ strictly_positive context n nn
+ (subst_inductive_type_with_dummy_mutind source) &&
+ weakly_positive ((Some (name,(C.Decl source)))::context)
+ (n + 1) (nn + 1) uri dest
+ | C.Prod (name,source,dest) ->
+ does_not_occur context n nn
+ (subst_inductive_type_with_dummy_mutind source)&&
+ weakly_positive ((Some (name,(C.Decl source)))::context)
+ (n + 1) (nn + 1) uri dest
+ | _ ->
+ raise (TypeCheckerFailure (lazy "Malformed inductive constructor type"))
+
+(* 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 (AssertFailure (lazy "1"))
+
+and strictly_positive context n nn te =
+ let module C = Cic in
+ let module U = UriManager in
+ match CicReduction.whd context te with
+ | t when does_not_occur context n nn t -> true
+ | C.Rel _ -> true
+ | C.Cast (te,ty) ->
+ (*CSC: bisogna controllare ty????*)
+ strictly_positive context n nn te
+ | C.Prod (name,so,ta) ->
+ does_not_occur context n nn so &&
+ strictly_positive ((Some (name,(C.Decl so)))::context) (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 context n nn x) tl true
+ | C.Appl ((C.MutInd (uri,i,exp_named_subst))::tl) ->
+ let (ok,paramsno,ity,cl,name) =
+ let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
+ match o with
+ C.InductiveDefinition (tl,_,paramsno,_) ->
+ let (name,_,ity,cl) = List.nth tl i in
+ (List.length tl = 1, paramsno, ity, cl, name)
+ (* (true, paramsno, ity, cl, name) *)
+ | _ ->
+ raise
+ (TypeCheckerFailure
+ (lazy ("Unknown inductive type:" ^ 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
+ (CicSubstitution.subst_vars exp_named_subst te)
+ ) cl
+ in
+ ok &&
+ List.fold_right
+ (fun x i -> i && does_not_occur context n nn x)
+ arguments true &&
+ (*CSC: MEGAPATCH3 (sara' quella giusta?)*)
+ List.fold_right
+ (fun x i ->
+ i &&
+ weakly_positive
+ ((Some (C.Name name,(Cic.Decl ity)))::context) (n+1) (nn+1) uri
+ x
+ ) cl' true
+ | t -> false
+
+(* the inductive type indexes are s.t. n < x <= nn *)
+and are_all_occurrences_positive context uri indparamsno i n nn te =
+ let module C = Cic in
+ match CicReduction.whd context 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 context x with
+ C.Rel m when m = n - (indparamsno - k) -> k - 1
+ | _ ->
+ raise (TypeCheckerFailure
+ (lazy
+ ("Non-positive occurence in mutual inductive definition(s) [1]" ^
+ UriManager.string_of_uri uri)))
+ ) indparamsno tl
+ in
+ if last = 0 then
+ List.fold_right (fun x i -> i && does_not_occur context n nn x) tl true
+ else
+ raise (TypeCheckerFailure
+ (lazy ("Non-positive occurence in mutual inductive definition(s) [2]"^
+ UriManager.string_of_uri uri)))
+ | C.Rel m when m = i ->
+ if indparamsno = 0 then
+ true
+ else
+ raise (TypeCheckerFailure
+ (lazy ("Non-positive occurence in mutual inductive definition(s) [3]"^
+ UriManager.string_of_uri uri)))
+ | C.Prod (C.Anonymous,source,dest) ->
+ let b = strictly_positive context n nn source in
+ b &&
+ are_all_occurrences_positive
+ ((Some (C.Anonymous,(C.Decl source)))::context) uri indparamsno
+ (i+1) (n + 1) (nn + 1) dest
+ | C.Prod (name,source,dest) when
+ does_not_occur ((Some (name,(C.Decl source)))::context) 0 n dest ->
+ (* dummy abstraction, so we behave as in the anonimous case *)
+ strictly_positive context n nn source &&
+ are_all_occurrences_positive
+ ((Some (name,(C.Decl source)))::context) uri indparamsno
+ (i+1) (n + 1) (nn + 1) dest
+ | C.Prod (name,source,dest) ->
+ does_not_occur context n nn source &&
+ are_all_occurrences_positive ((Some (name,(C.Decl source)))::context)
+ uri indparamsno (i+1) (n + 1) (nn + 1) dest
+ | _ ->
+ raise
+ (TypeCheckerFailure (lazy ("Malformed inductive constructor type " ^
+ (UriManager.string_of_uri uri))))
+
+(* the boolean h means already protected *)
+(* args is the list of arguments the type of the constructor that may be *)
+(* found in head position must be applied to. *)
+and guarded_by_constructors ~subst context n nn h te args coInductiveTypeURI =
+ let module C = Cic in
+ (*CSC: There is a lot of code replication between the cases X and *)
+ (*CSC: (C.Appl X tl). Maybe it will be better to define a function *)
+ (*CSC: that maps X into (C.Appl X []) when X is not already a C.Appl *)
+ match CicReduction.whd ~subst context te with
+ C.Rel m when m > n && m <= nn -> h
+ | C.Rel _ -> true
+ | C.Meta _
+ | C.Sort _
+ | C.Implicit _
+ | C.Cast _
+ | C.Prod _
+ | C.LetIn _ ->
+ (* the term has just been type-checked *)
+ raise (AssertFailure (lazy "17"))
+ | C.Lambda (name,so,de) ->
+ does_not_occur ~subst context n nn so &&
+ guarded_by_constructors ~subst ((Some (name,(C.Decl so)))::context)
+ (n + 1) (nn + 1) h de args coInductiveTypeURI
+ | C.Appl ((C.Rel m)::tl) when m > n && m <= nn ->
+ h &&
+ List.fold_right (fun x i -> i && does_not_occur ~subst context n nn x) tl true
+ | C.Appl ((C.MutConstruct (uri,i,j,exp_named_subst))::tl) ->
+ let consty =
+ let obj,_ =
+ try
+ CicEnvironment.get_cooked_obj ~trust:false CicUniv.empty_ugraph uri
+ with Not_found -> assert false
+ in
+ match obj with
+ C.InductiveDefinition (itl,_,_,_) ->
+ let (_,_,_,cl) = List.nth itl i in
+ let (_,cons) = List.nth cl (j - 1) in
+ CicSubstitution.subst_vars exp_named_subst cons
+ | _ ->
+ raise (TypeCheckerFailure
+ (lazy ("Unknown mutual inductive definition:" ^ UriManager.string_of_uri uri)))
+ in
+ let rec analyse_branch context ty te =
+ match CicReduction.whd ~subst context ty with
+ C.Meta _ -> raise (AssertFailure (lazy "34"))
+ | C.Rel _
+ | C.Var _
+ | C.Sort _ ->
+ does_not_occur ~subst context n nn te
+ | C.Implicit _
+ | C.Cast _ ->
+ raise (AssertFailure (lazy "24"))(* due to type-checking *)
+ | C.Prod (name,so,de) ->
+ analyse_branch ((Some (name,(C.Decl so)))::context) de te
+ | C.Lambda _
+ | C.LetIn _ ->
+ raise (AssertFailure (lazy "25"))(* due to type-checking *)
+ | C.Appl ((C.MutInd (uri,_,_))::_) when uri == coInductiveTypeURI ->
+ guarded_by_constructors ~subst context n nn true te []
+ coInductiveTypeURI
+ | C.Appl ((C.MutInd (uri,_,_))::_) ->
+ guarded_by_constructors ~subst context n nn true te tl
+ coInductiveTypeURI
+ | C.Appl _ ->
+ does_not_occur ~subst context n nn te
+ | C.Const _ -> raise (AssertFailure (lazy "26"))
+ | C.MutInd (uri,_,_) when uri == coInductiveTypeURI ->
+ guarded_by_constructors ~subst context n nn true te []
+ coInductiveTypeURI
+ | C.MutInd _ ->
+ does_not_occur ~subst context n nn te
+ | C.MutConstruct _ -> raise (AssertFailure (lazy "27"))
+ (*CSC: we do not consider backbones with a MutCase, Fix, Cofix *)
+ (*CSC: in head position. *)
+ | C.MutCase _
+ | C.Fix _
+ | C.CoFix _ ->
+ raise (AssertFailure (lazy "28"))(* due to type-checking *)
+ in
+ let rec analyse_instantiated_type context ty l =
+ match CicReduction.whd ~subst context ty with
+ C.Rel _
+ | C.Var _
+ | C.Meta _
+ | C.Sort _
+ | C.Implicit _
+ | C.Cast _ -> raise (AssertFailure (lazy "29"))(* due to type-checking *)
+ | C.Prod (name,so,de) ->
+ begin
+ match l with
+ [] -> true
+ | he::tl ->
+ analyse_branch context so he &&
+ analyse_instantiated_type
+ ((Some (name,(C.Decl so)))::context) de tl
+ end
+ | C.Lambda _
+ | C.LetIn _ ->
+ raise (AssertFailure (lazy "30"))(* due to type-checking *)
+ | C.Appl _ ->
+ List.fold_left
+ (fun i x -> i && does_not_occur ~subst context n nn x) true l
+ | C.Const _ -> raise (AssertFailure (lazy "31"))
+ | C.MutInd _ ->
+ List.fold_left
+ (fun i x -> i && does_not_occur ~subst context n nn x) true l
+ | C.MutConstruct _ -> raise (AssertFailure (lazy "32"))
+ (*CSC: we do not consider backbones with a MutCase, Fix, Cofix *)
+ (*CSC: in head position. *)
+ | C.MutCase _
+ | C.Fix _
+ | C.CoFix _ ->
+ raise (AssertFailure (lazy "33"))(* due to type-checking *)
+ in
+ let rec instantiate_type args consty =
+ function
+ [] -> true
+ | tlhe::tltl as l ->
+ let consty' = CicReduction.whd ~subst context consty in
+ match args with
+ he::tl ->
+ begin
+ match consty' with
+ C.Prod (_,_,de) ->
+ let instantiated_de = CicSubstitution.subst he de in
+ (*CSC: siamo sicuri che non sia troppo forte? *)
+ does_not_occur ~subst context n nn tlhe &
+ instantiate_type tl instantiated_de tltl
+ | _ ->
+ (*CSC:We do not consider backbones with a MutCase, a *)
+ (*CSC:FixPoint, a CoFixPoint and so on in head position.*)
+ raise (AssertFailure (lazy "23"))
+ end
+ | [] -> analyse_instantiated_type context consty' l
+ (* These are all the other cases *)
+ in
+ instantiate_type args consty tl
+ | C.Appl ((C.CoFix (_,fl))::tl) ->
+ List.fold_left (fun i x -> i && does_not_occur ~subst context n nn x) true tl &&
+ let len = List.length fl in
+ let n_plus_len = n + len
+ and nn_plus_len = nn + len
+ (*CSC: Is a Decl of the ty ok or should I use Def of a Fix? *)
+ and tys,_ =
+ List.fold_left
+ (fun (types,len) (n,ty,_) ->
+ (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+ len+1)
+ ) ([],0) fl
+ in
+ List.fold_right
+ (fun (_,ty,bo) i ->
+ i && does_not_occur ~subst context n nn ty &&
+ guarded_by_constructors ~subst (tys@context) n_plus_len nn_plus_len
+ h bo args coInductiveTypeURI
+ ) fl true
+ | C.Appl ((C.MutCase (_,_,out,te,pl))::tl) ->
+ List.fold_left (fun i x -> i && does_not_occur ~subst context n nn x) true tl &&
+ does_not_occur ~subst context n nn out &&
+ does_not_occur ~subst context n nn te &&
+ List.fold_right
+ (fun x i ->
+ i &&
+ guarded_by_constructors ~subst context n nn h x args
+ coInductiveTypeURI
+ ) pl true
+ | C.Appl l ->
+ List.fold_right (fun x i -> i && does_not_occur ~subst context n nn x) l true
+ | C.Var (_,exp_named_subst)
+ | C.Const (_,exp_named_subst) ->
+ List.fold_right
+ (fun (_,x) i -> i && does_not_occur ~subst context n nn x) exp_named_subst true
+ | C.MutInd _ -> assert false
+ | C.MutConstruct (_,_,_,exp_named_subst) ->
+ List.fold_right
+ (fun (_,x) i -> i && does_not_occur ~subst context n nn x) exp_named_subst true
+ | C.MutCase (_,_,out,te,pl) ->
+ does_not_occur ~subst context n nn out &&
+ does_not_occur ~subst context n nn te &&
+ List.fold_right
+ (fun x i ->
+ i &&
+ guarded_by_constructors ~subst context n nn h x args
+ coInductiveTypeURI
+ ) pl true
+ | C.Fix (_,fl) ->
+ let len = List.length fl in
+ let n_plus_len = n + len
+ and nn_plus_len = nn + len
+ (*CSC: Is a Decl of the ty ok or should I use Def of a Fix? *)
+ and tys,_ =
+ List.fold_left
+ (fun (types,len) (n,_,ty,_) ->
+ (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+ len+1)
+ ) ([],0) fl
+ in
+ List.fold_right
+ (fun (_,_,ty,bo) i ->
+ i && does_not_occur ~subst context n nn ty &&
+ does_not_occur ~subst (tys@context) 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
+ (*CSC: Is a Decl of the ty ok or should I use Def of a Fix? *)
+ and tys,_ =
+ List.fold_left
+ (fun (types,len) (n,ty,_) ->
+ (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+ len+1)
+ ) ([],0) fl
+ in
+ List.fold_right
+ (fun (_,ty,bo) i ->
+ i && does_not_occur ~subst context n nn ty &&
+ guarded_by_constructors ~subst (tys@context) n_plus_len nn_plus_len
+ h bo
+ args coInductiveTypeURI
+ ) fl true
+
+ in
+ type_of_aux ~logger context t ugraph
+
+;;
+
+(** wrappers which instantiate fresh loggers *)
+
+(* check_allowed_sort_elimination uri i s1 s2
+ This function is used outside the kernel to determine in advance whether
+ a MutCase will be allowed or not.
+ [uri,i] is the type of the term to match
+ [s1] is the sort of the term to eliminate (i.e. the head of the arity
+ of the inductive type [uri,i])
+ [s2] is the sort of the goal (i.e. the head of the type of the outtype
+ of the MutCase) *)
+let check_allowed_sort_elimination uri i s1 s2 =
+ fst (check_allowed_sort_elimination ~subst:[] ~metasenv:[]
+ ~logger:(new CicLogger.logger) [] uri i true
+ (Cic.Implicit None) (* never used *) (Cic.Sort s1) (Cic.Sort s2)
+ CicUniv.empty_ugraph)
+;;
+
+Deannotate.type_of_aux' := fun context t -> fst (type_of_aux' [] context t CicUniv.oblivion_ugraph);;
+
+*)
+
+module C = NCic
+module R = NCicReduction
+module Ref = NReference
+module S = NCicSubstitution
+module U = NCicUtils
+module E = NCicEnvironment
+
+let rec split_prods ~subst context n te =
+ match (n, R.whd ~subst context te) with
+ | (0, _) -> context,te
+ | (n, C.Prod (name,so,ta)) when n > 0 ->
+ split_prods ~subst ((name,(C.Decl so))::context) (n - 1) ta
+ | (_, _) -> raise (AssertFailure (lazy "split_prods"))
+;;
+
+let debruijn ?(cb=fun _ _ -> ()) uri number_of_types =
+ let rec aux k t =
+ let res =
+ match t with
+ | C.Meta (i,(s,C.Ctx l)) ->
+ let l1 = NCicUtils.sharing_map (aux (k-s)) l in
+ if l1 == l then t else C.Meta (i,(s,C.Ctx l1))
+ | C.Meta _ -> t
+ | C.Const (Ref.Ref (_,uri1,(Ref.Fix (no,_) | Ref.CoFix no)))
+ | C.Const (Ref.Ref (_,uri1,Ref.Ind no)) when NUri.eq uri uri1 ->
+ C.Rel (k + number_of_types - no)
+ | t -> NCicUtils.map (fun _ k -> k+1) k aux t
+ in
+ cb t res; res
+ in
+ aux 0
+;;
+
+let sort_of_prod ~metasenv ~subst context (name,s) (t1, t2) =
+ let t1 = R.whd ~subst context t1 in
+ let t2 = R.whd ~subst ((name,C.Decl s)::context) t2 in
+ match t1, t2 with
+ | C.Sort s1, C.Sort C.Prop -> t2
+ | C.Sort (C.Type u1), C.Sort (C.Type u2) -> C.Sort (C.Type (max u1 u2))
+ | C.Sort _,C.Sort (C.Type _) -> t2
+ | C.Sort (C.Type _) , C.Sort C.CProp -> t1
+ | C.Sort _, C.Sort C.CProp -> t2
+ | C.Meta _, C.Sort _
+ | C.Meta _, C.Meta _
+ | C.Sort _, C.Meta _ when U.is_closed t2 -> t2
+ | _ ->
+ raise (TypeCheckerFailure (lazy (Printf.sprintf
+ "Prod: expected two sorts, found = %s, %s"
+ (NCicPp.ppterm ~subst ~metasenv ~context t1)
+ (NCicPp.ppterm ~subst ~metasenv ~context t2))))
+;;
+
+let eat_prods ~subst ~metasenv context he ty_he args_with_ty =
+ let rec aux ty_he = function
+ | [] -> ty_he
+ | (arg, ty_arg)::tl ->
+ match R.whd ~subst context ty_he with
+ | C.Prod (n,s,t) ->
+(*
+ prerr_endline (NCicPp.ppterm ~subst ~metasenv ~context s ^ " - Vs - "
+ ^ NCicPp.ppterm ~subst ~metasenv
+ ~context ty_arg);
+ prerr_endline (NCicPp.ppterm ~subst ~metasenv ~context (S.subst ~avoid_beta_redexes:true arg t));
+*)
+ if R.are_convertible ~subst ~metasenv context ty_arg s then
+ aux (S.subst ~avoid_beta_redexes:true arg t) tl
+ else
+ raise
+ (TypeCheckerFailure
+ (lazy (Printf.sprintf
+ ("Appl: wrong application of %s: the parameter %s has type"^^
+ "\n%s\nbut it should have type \n%s\n")
+ (NCicPp.ppterm ~subst ~metasenv ~context he)
+ (NCicPp.ppterm ~subst ~metasenv ~context arg)
+ (NCicPp.ppterm ~subst ~metasenv ~context ty_arg)
+ (NCicPp.ppterm ~subst ~metasenv ~context s))))
+ | _ ->
+ raise
+ (TypeCheckerFailure
+ (lazy (Printf.sprintf
+ "Appl: %s is not a function, it cannot be applied"
+ (NCicPp.ppterm ~subst ~metasenv ~context
+ (let res = List.length tl in
+ let eaten = List.length args_with_ty - res in
+ (NCic.Appl
+ (he::List.map fst
+ (fst (HExtlib.split_nth eaten args_with_ty)))))))))
+ in
+ aux ty_he args_with_ty
+;;
+
+let fix_lefts_in_constrs ~subst uri paramsno tyl i =
+ let len = List.length tyl in
+ let _,_,arity,cl = List.nth tyl i in
+ let tys = List.map (fun (_,n,ty,_) -> n,C.Decl ty) tyl in
+ let cl' =
+ List.map
+ (fun (_,id,ty) ->
+ let debruijnedty = debruijn uri len ty in
+ id, snd (split_prods ~subst tys paramsno ty),
+ snd (split_prods ~subst tys paramsno debruijnedty))
+ cl
+ in
+ let lefts = fst (split_prods ~subst [] paramsno arity) in
+ lefts@tys, len, cl'
+;;
+
+exception DoesOccur;;
+
+let does_not_occur ~subst context n nn t =
+ let rec aux (context,n,nn as k) _ = function
+ | C.Rel m when m > n && m <= nn -> raise DoesOccur
+ | C.Rel m ->
+ (try (match List.nth context (m-1) with
+ | _,C.Def (bo,_) -> aux k () (S.lift m bo)
+ | _ -> ())
+ with Failure _ -> assert false)
+ | C.Meta (_,(_,(C.Irl 0 | C.Ctx []))) -> (* closed meta *) ()
+ | C.Meta (mno,(s,l)) ->
+ (try
+ let _,_,term,_ = U.lookup_subst mno subst in
+ aux (context,n+s,nn+s) () (S.subst_meta (0,l) term)
+ with CicUtil.Subst_not_found _ -> match l with
+ | C.Irl len -> if not (n >= s+len || s > nn) then raise DoesOccur
+ | C.Ctx lc -> List.iter (aux (context,n+s,nn+s) ()) lc)
+ | t -> U.fold (fun e (ctx,n,nn) -> (e::ctx,n+1,nn+1)) k aux () t
+ in
+ try aux (context,n,nn) () t; true
+ with DoesOccur -> false
+;;
+
+exception NotGuarded of string Lazy.t;;
+
+let rec typeof ~subst ~metasenv context term =
+ let rec typeof_aux context =
+ fun t -> (*prerr_endline (NCicPp.ppterm ~context t); *)
+ match t with
+ | C.Rel n ->
+ (try
+ match List.nth context (n - 1) with
+ | (_,C.Decl ty) -> S.lift n ty
+ | (_,C.Def (_,ty)) -> S.lift n ty
+ with Failure _ -> raise (TypeCheckerFailure (lazy "unbound variable")))
+ | C.Sort (C.Type i) -> C.Sort (C.Type (i+1))
+ | C.Sort s -> C.Sort (C.Type 0)
+ | C.Implicit _ -> raise (AssertFailure (lazy "Implicit found"))
+ | C.Meta (n,l) as t ->
+ let canonical_ctx,ty =
+ try
+ let _,c,_,ty = U.lookup_subst n subst in c,ty
+ with U.Subst_not_found _ -> try
+ let _,_,c,ty = U.lookup_meta n metasenv in c,ty
+ with U.Meta_not_found _ ->
+ raise (AssertFailure (lazy (Printf.sprintf
+ "%s not found" (NCicPp.ppterm ~subst ~metasenv ~context t))))
+ in
+ check_metasenv_consistency t ~subst ~metasenv context canonical_ctx l;
+ S.subst_meta l ty
+ | C.Const ref -> type_of_constant ref
+ | C.Prod (name,s,t) ->
+ let sort1 = typeof_aux context s in
+ let sort2 = typeof_aux ((name,(C.Decl s))::context) t in
+ sort_of_prod ~metasenv ~subst context (name,s) (sort1,sort2)
+ | C.Lambda (n,s,t) ->
+ let sort = typeof_aux context s in
+ (match R.whd ~subst context sort with
+ | C.Meta _ | C.Sort _ -> ()
+ | _ ->
+ raise
+ (TypeCheckerFailure (lazy (Printf.sprintf
+ ("Not well-typed lambda-abstraction: " ^^
+ "the source %s should be a type; instead it is a term " ^^
+ "of type %s") (NCicPp.ppterm ~subst ~metasenv ~context s)
+ (NCicPp.ppterm ~subst ~metasenv ~context sort)))));
+ let ty = typeof_aux ((n,(C.Decl s))::context) t in
+ C.Prod (n,s,ty)
+ | C.LetIn (n,ty,t,bo) ->
+ let ty_t = typeof_aux context t in
+ let _ = typeof_aux context ty in
+ if not (R.are_convertible ~subst ~metasenv context ty ty_t) then
+ raise
+ (TypeCheckerFailure
+ (lazy (Printf.sprintf
+ "The type of %s is %s but it is expected to be %s"
+ (NCicPp.ppterm ~subst ~metasenv ~context t)
+ (NCicPp.ppterm ~subst ~metasenv ~context ty_t)
+ (NCicPp.ppterm ~subst ~metasenv ~context ty))))
+ else
+ let ty_bo = typeof_aux ((n,C.Def (t,ty))::context) bo in
+ S.subst ~avoid_beta_redexes:true t ty_bo
+ | C.Appl (he::(_::_ as args)) ->
+ let ty_he = typeof_aux context he in
+ let args_with_ty = List.map (fun t -> t, typeof_aux context t) args in
+(*
+ prerr_endline ("HEAD: " ^ NCicPp.ppterm ~subst ~metasenv ~context ty_he);
+ prerr_endline ("TARGS: " ^ String.concat " | " (List.map (NCicPp.ppterm
+ ~subst ~metasenv ~context) (List.map snd args_with_ty)));
+ prerr_endline ("ARGS: " ^ String.concat " | " (List.map (NCicPp.ppterm
+ ~subst ~metasenv ~context) (List.map fst args_with_ty)));
+*)
+ eat_prods ~subst ~metasenv context he ty_he args_with_ty
+ | C.Appl _ -> raise (AssertFailure (lazy "Appl of length < 2"))
+ | C.Match (Ref.Ref (_,_,Ref.Ind tyno) as r,outtype,term,pl) ->
+ let outsort = typeof_aux context outtype in
+ let inductive,leftno,itl,_,_ = E.get_checked_indtys r in
+ let constructorsno =
+ let _,_,_,cl = List.nth itl tyno in List.length cl
+ in
+ let parameters, arguments =
+ let ty = R.whd ~subst context (typeof_aux context term) in
+ let r',tl =
+ match ty with
+ C.Const (Ref.Ref (_,_,Ref.Ind _) as r') -> r',[]
+ | C.Appl (C.Const (Ref.Ref (_,_,Ref.Ind _) as r') :: tl) -> r',tl
+ | _ ->
+ raise
+ (TypeCheckerFailure (lazy (Printf.sprintf
+ "Case analysis: analysed term %s is not an inductive one"
+ (NCicPp.ppterm ~subst ~metasenv ~context term)))) in
+ if not (Ref.eq r r') then
+ raise
+ (TypeCheckerFailure (lazy (Printf.sprintf
+ ("Case analysys: analysed term type is %s, but is expected " ^^
+ "to be (an application of) %s")
+ (NCicPp.ppterm ~subst ~metasenv ~context ty)
+ (NCicPp.ppterm ~subst ~metasenv ~context (C.Const r')))))
+ else
+ try HExtlib.split_nth leftno tl
+ with
+ Failure _ ->
+ raise (TypeCheckerFailure (lazy (Printf.sprintf
+ "%s is partially applied"
+ (NCicPp.ppterm ~subst ~metasenv ~context ty)))) in
+ (* let's control if the sort elimination is allowed: [(I q1 ... qr)|B] *)
+ let sort_of_ind_type =
+ if parameters = [] then C.Const r
+ else C.Appl ((C.Const r)::parameters) in
+ let type_of_sort_of_ind_ty = typeof_aux context sort_of_ind_type in
+ check_allowed_sort_elimination ~subst ~metasenv r context
+ sort_of_ind_type type_of_sort_of_ind_ty outsort;
+ (* let's check if the type of branches are right *)
+ if List.length pl <> constructorsno then
+ raise (TypeCheckerFailure (lazy ("Wrong number of cases in a match")));
+ let j,branches_ok,p_ty, exp_p_ty =
+ List.fold_left
+ (fun (j,b,old_p_ty,old_exp_p_ty) p ->
+ if b then
+ let cons =
+ let cons = Ref.mk_constructor j r in
+ if parameters = [] then C.Const cons
+ else C.Appl (C.Const cons::parameters)
+ in
+ let ty_p = typeof_aux context p in
+ let ty_cons = typeof_aux context cons in
+ let ty_branch =
+ type_of_branch ~subst context leftno outtype cons ty_cons 0
+ in
+ j+1, R.are_convertible ~subst ~metasenv context ty_p ty_branch,
+ ty_p, ty_branch
+ else
+ j,false,old_p_ty,old_exp_p_ty
+ ) (1,true,C.Sort C.Prop,C.Sort C.Prop) pl
+ in
+ if not branches_ok then
+ raise
+ (TypeCheckerFailure
+ (lazy (Printf.sprintf ("Branch for constructor %s :=\n%s\n"^^
+ "has type %s\nnot convertible with %s")
+ (NCicPp.ppterm ~subst ~metasenv ~context
+ (C.Const (Ref.mk_constructor (j-1) r)))
+ (NCicPp.ppterm ~metasenv ~subst ~context (List.nth pl (j-2)))
+ (NCicPp.ppterm ~metasenv ~subst ~context p_ty)
+ (NCicPp.ppterm ~metasenv ~subst ~context exp_p_ty))));
+ let res = outtype::arguments@[term] in
+ R.head_beta_reduce (C.Appl res)
+ | C.Match _ -> assert false
+
+ and type_of_branch ~subst context leftno outty cons tycons liftno =
+ match R.whd ~subst context tycons with
+ | C.Const (Ref.Ref (_,_,Ref.Ind _)) -> C.Appl [S.lift liftno outty ; cons]
+ | C.Appl (C.Const (Ref.Ref (_,_,Ref.Ind _))::tl) ->
+ let _,arguments = HExtlib.split_nth leftno tl in
+ C.Appl (S.lift liftno outty::arguments@[cons])
+ | C.Prod (name,so,de) ->
+ let cons =
+ match S.lift 1 cons with
+ | C.Appl l -> C.Appl (l@[C.Rel 1])
+ | t -> C.Appl [t ; C.Rel 1]
+ in
+ C.Prod (name,so,
+ type_of_branch ~subst ((name,(C.Decl so))::context)
+ leftno outty cons de (liftno+1))
+ | _ -> raise (AssertFailure (lazy "type_of_branch"))
+
+ (* check_metasenv_consistency checks that the "canonical" context of a
+ metavariable is consitent - up to relocation via the relocation list l -
+ with the actual context *)
+ and check_metasenv_consistency
+ ~subst ~metasenv term context canonical_context l
+ =
+ match l with
+ | shift, NCic.Irl n ->
+ let context = snd (HExtlib.split_nth shift context) in
+ let rec compare = function
+ | 0,_,[] -> ()
+ | 0,_,_::_
+ | _,_,[] ->
+ raise (AssertFailure (lazy (Printf.sprintf
+ "Local and canonical context %s have different lengths"
+ (NCicPp.ppterm ~subst ~context ~metasenv term))))
+ | m,[],_::_ ->
+ raise (TypeCheckerFailure (lazy (Printf.sprintf
+ "Unbound variable -%d in %s" m
+ (NCicPp.ppterm ~subst ~metasenv ~context term))))
+ | m,t::tl,ct::ctl ->
+ (match t,ct with
+ (_,C.Decl t1), (_,C.Decl t2)
+ | (_,C.Def (t1,_)), (_,C.Def (t2,_))
+ | (_,C.Def (_,t1)), (_,C.Decl t2) ->
+ if not (R.are_convertible ~subst ~metasenv tl t1 t2) then
+ raise
+ (TypeCheckerFailure
+ (lazy (Printf.sprintf
+ ("Not well typed metavariable local context for %s: " ^^
+ "%s expected, which is not convertible with %s")
+ (NCicPp.ppterm ~subst ~metasenv ~context term)
+ (NCicPp.ppterm ~subst ~metasenv ~context t2)
+ (NCicPp.ppterm ~subst ~metasenv ~context t1))))
+ | _,_ ->
+ raise
+ (TypeCheckerFailure (lazy (Printf.sprintf
+ ("Not well typed metavariable local context for %s: " ^^
+ "a definition expected, but a declaration found")
+ (NCicPp.ppterm ~subst ~metasenv ~context term)))));
+ compare (m - 1,tl,ctl)
+ in
+ compare (n,context,canonical_context)
+ | shift, lc_kind ->
+ (* we avoid useless lifting by shortening the context*)
+ let l,context = (0,lc_kind), snd (HExtlib.split_nth shift context) in
+ let lifted_canonical_context =
+ let rec lift_metas i = function
+ | [] -> []
+ | (n,C.Decl t)::tl ->
+ (n,C.Decl (S.subst_meta l (S.lift i t)))::(lift_metas (i+1) tl)
+ | (n,C.Def (t,ty))::tl ->
+ (n,C.Def ((S.subst_meta l (S.lift i t)),
+ S.subst_meta l (S.lift i ty)))::(lift_metas (i+1) tl)
+ in
+ lift_metas 1 canonical_context in
+ let l = U.expand_local_context lc_kind in
+ try
+ List.iter2
+ (fun t ct ->
+ match (t,ct) with
+ | t, (_,C.Def (ct,_)) ->
+ (*CSC: the following optimization is to avoid a possibly expensive
+ reduction that can be easily avoided and that is quite
+ frequent. However, this is better handled using levels to
+ control reduction *)
+ let optimized_t =
+ match t with
+ | C.Rel n ->
+ (try
+ match List.nth context (n - 1) with
+ | (_,C.Def (te,_)) -> S.lift n te
+ | _ -> t
+ with Failure _ -> t)
+ | _ -> t
+ in
+ if not (R.are_convertible ~subst ~metasenv context optimized_t ct)
+ then
+ raise
+ (TypeCheckerFailure
+ (lazy (Printf.sprintf
+ ("Not well typed metavariable local context: " ^^
+ "expected a term convertible with %s, found %s")
+ (NCicPp.ppterm ~subst ~metasenv ~context ct)
+ (NCicPp.ppterm ~subst ~metasenv ~context t))))
+ | t, (_,C.Decl ct) ->
+ let type_t = typeof_aux context t in
+ if not (R.are_convertible ~subst ~metasenv context type_t ct) then
+ raise (TypeCheckerFailure
+ (lazy (Printf.sprintf
+ ("Not well typed metavariable local context: "^^
+ "expected a term of type %s, found %s of type %s")
+ (NCicPp.ppterm ~subst ~metasenv ~context ct)
+ (NCicPp.ppterm ~subst ~metasenv ~context t)
+ (NCicPp.ppterm ~subst ~metasenv ~context type_t))))
+ ) l lifted_canonical_context
+ with
+ Invalid_argument _ ->
+ raise (AssertFailure (lazy (Printf.sprintf
+ "Local and canonical context %s have different lengths"
+ (NCicPp.ppterm ~subst ~metasenv ~context term))))
+
+ and is_non_informative context paramsno c =
+ let rec aux context c =
+ match R.whd context c with
+ | C.Prod (n,so,de) ->
+ let s = typeof_aux context so in
+ s = C.Sort C.Prop && aux ((n,(C.Decl so))::context) de
+ | _ -> true in
+ let context',dx = split_prods ~subst:[] context paramsno c in
+ aux context' dx
+
+ and check_allowed_sort_elimination ~subst ~metasenv r =
+ let mkapp he arg =
+ match he with
+ | C.Appl l -> C.Appl (l @ [arg])
+ | t -> C.Appl [t;arg] in
+ let rec aux context ind arity1 arity2 =
+ let arity1 = R.whd ~subst context arity1 in
+ let arity2 = R.whd ~subst context arity2 in
+ match arity1,arity2 with
+ | C.Prod (name,so1,de1), C.Prod (_,so2,de2) ->
+ if not (R.are_convertible ~subst ~metasenv context so1 so2) then
+ raise (TypeCheckerFailure (lazy (Printf.sprintf
+ "In outtype: expected %s, found %s"
+ (NCicPp.ppterm ~subst ~metasenv ~context so1)
+ (NCicPp.ppterm ~subst ~metasenv ~context so2)
+ )));
+ aux ((name, C.Decl so1)::context)
+ (mkapp (S.lift 1 ind) (C.Rel 1)) de1 de2
+ | C.Sort _, C.Prod (name,so,ta) ->
+ if not (R.are_convertible ~subst ~metasenv context so ind) then
+ raise (TypeCheckerFailure (lazy (Printf.sprintf
+ "In outtype: expected %s, found %s"
+ (NCicPp.ppterm ~subst ~metasenv ~context ind)
+ (NCicPp.ppterm ~subst ~metasenv ~context so)
+ )));
+ (match arity1,ta with
+ | (C.Sort (C.CProp | C.Type _), C.Sort _)
+ | (C.Sort C.Prop, C.Sort C.Prop) -> ()
+ | (C.Sort C.Prop, C.Sort (C.CProp | C.Type _)) ->
+ (* TODO: we should pass all these parameters since we
+ * have them already *)
+ let inductive,leftno,itl,_,i = E.get_checked_indtys r in
+ let itl_len = List.length itl in
+ let _,name,ty,cl = List.nth itl i in
+ let cl_len = List.length cl in
+ (* is it a singleton or empty non recursive and non informative
+ definition? *)
+ if not
+ (cl_len = 0 ||
+ (itl_len = 1 && cl_len = 1 &&
+ is_non_informative [name,C.Decl ty] leftno
+ (let _,_,x = List.nth cl 0 in x)))
+ then
+ raise (TypeCheckerFailure (lazy
+ ("Sort elimination not allowed")));
+ | _,_ -> ())
+ | _,_ -> ()
+ in
+ aux
+
+ in
+ typeof_aux context term
+
+and check_mutual_inductive_defs uri ~metasenv ~subst is_ind leftno tyl =
+ (* let's check if the arity of the inductive types are well formed *)
+ List.iter (fun (_,_,x,_) -> ignore (typeof ~subst ~metasenv [] x)) tyl;
+ (* let's check if the types of the inductive constructors are well formed. *)
+ let len = List.length tyl in
+ let tys = List.rev (List.map (fun (_,n,ty,_) -> (n,(C.Decl ty))) tyl) in
+ ignore
+ (List.fold_right
+ (fun (_,_,_,cl) i ->
+ List.iter
+ (fun (_,name,te) ->
+ let debruijnedte = debruijn uri len te in
+ ignore (typeof ~subst ~metasenv tys debruijnedte);
+ (* let's check also the positivity conditions *)
+ if false (*
+ not
+ (are_all_occurrences_positive tys uri indparamsno i 0 len
+ debruijnedte) *)
+ then
+ raise
+ (TypeCheckerFailure
+ (lazy ("Non positive occurence in "^NUri.string_of_uri uri))))
+ cl;
+ i + 1)
+ tyl 1)
+
+and eat_lambdas ~subst ~metasenv context n te =
+ match (n, R.whd ~subst context te) with
+ | (0, _) -> (te, context)
+ | (n, C.Lambda (name,so,ta)) when n > 0 ->
+ eat_lambdas ~subst ~metasenv ((name,(C.Decl so))::context) (n - 1) ta
+ | (n, te) ->
+ raise (AssertFailure (lazy (Printf.sprintf "9 (%d, %s)" n
+ (NCicPp.ppterm ~subst ~metasenv ~context te))))
+
+and guarded_by_destructors ~subst ~metasenv context recfuns t =
+ let recursor f k t = NCicUtils.fold shift_k k (fun k () -> f k) () t in
+ let rec aux (context, recfuns, x, safes as k) = function
+ | C.Rel m as t when List.mem_assoc m recfuns ->
+ raise (NotGuarded (lazy
+ (NCicPp.ppterm ~subst ~metasenv ~context t ^ " passed around")))
+ | C.Rel m ->
+ (match List.nth context (m-1) with
+ | _,C.Decl _ -> ()
+ | _,C.Def (bo,_) -> aux (context, recfuns, x, safes) (S.lift m bo))
+ | C.Meta _ -> ()
+ | C.Appl ((C.Rel m)::tl) as t when List.mem_assoc m recfuns ->
+ let rec_no = List.assoc m recfuns in
+ if not (List.length tl > rec_no) then
+ raise (NotGuarded (lazy
+ (NCicPp.ppterm ~context ~subst ~metasenv t ^
+ " is a partial application of a fix")))
+ else
+ let rec_arg = List.nth tl rec_no in
+ if not (is_really_smaller ~subst ~metasenv k rec_arg) then
+ raise (NotGuarded (lazy
+ (NCicPp.ppterm ~context ~subst ~metasenv rec_arg ^ " not smaller")));
+ List.iter (aux k) tl
+ | C.Match (Ref.Ref (_,uri,_) as ref,outtype,term,pl) as t ->
+ (match R.whd ~subst context term with
+ | C.Rel m | C.Appl (C.Rel m :: _ ) as t when List.mem m safes || m = x ->
+ let isinductive, paramsno, tl, _, i = E.get_checked_indtys ref in
+ if not isinductive then recursor aux k t
+ else
+ let c_ctx,len,cl = fix_lefts_in_constrs ~subst uri paramsno tl i in
+ let args = match t with C.Appl (_::tl) -> tl | _ -> [] in
+ aux k outtype;
+ List.iter (aux k) args;
+ List.iter2
+ (fun p (_,_,bruijnedc) ->
+ let rl = recursive_args ~subst ~metasenv c_ctx 0 len bruijnedc in
+ let p, k = get_new_safes ~subst k p rl in
+ aux k p)
+ pl cl
+ | _ -> recursor aux k t)
+ | t -> recursor aux k t
+ in
+ try aux (context, recfuns, 1, []) t
+ with NotGuarded s -> raise (TypeCheckerFailure s)
+
+(*
+ | 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 tys,_ =
+ List.fold_left
+ (fun (types,len) (n,_,ty,_) ->
+ (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+ len+1)
+ ) ([],0) fl
+ and safes' = List.map (fun x -> x + len) safes in
+ List.fold_right
+ (fun (_,_,ty,bo) i ->
+ i && guarded_by_destructors ~subst context n nn kl x_plus_len safes' ty &&
+ guarded_by_destructors ~subst (tys@context) 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 tys,_ =
+ List.fold_left
+ (fun (types,len) (n,ty,_) ->
+ (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+ len+1)
+ ) ([],0) fl
+ and safes' = List.map (fun x -> x + len) safes in
+ List.fold_right
+ (fun (_,ty,bo) i ->
+ i &&
+ guarded_by_destructors ~subst context n nn kl x_plus_len safes' ty &&
+ guarded_by_destructors ~subst (tys@context) n_plus_len nn_plus_len kl
+ x_plus_len safes' bo
+ ) fl true
+*)
+
+and guarded_by_constructors ~subst ~metasenv _ _ _ _ _ _ _ = true
+
+and recursive_args ~subst ~metasenv context n nn te =
+ match R.whd context te with
+ | C.Rel _ | C.Appl _ -> []
+ | C.Prod (name,so,de) ->
+ (not (does_not_occur ~subst context n nn so)) ::
+ (recursive_args ~subst ~metasenv
+ ((name,(C.Decl so))::context) (n+1) (nn + 1) de)
+ | t ->
+ raise (AssertFailure (lazy ("recursive_args:" ^ NCicPp.ppterm ~subst
+ ~metasenv ~context:[] t)))
+
+and get_new_safes ~subst (context, recfuns, x, safes as k) p rl =
+ match R.whd ~subst context p, rl with
+ | C.Lambda (name,so,ta), b::tl ->
+ let safes = (if b then [0] else []) @ safes in
+ get_new_safes ~subst
+ (shift_k (name,(C.Decl so)) (context, recfuns, x, safes)) ta tl
+ | C.Meta _ as e, _ | e, [] -> e, k
+ | _ -> raise (AssertFailure (lazy "Ill formed pattern"))
+
+and split_prods ~subst context n te =
+ match n, R.whd ~subst context te with
+ | 0, _ -> context,te
+ | n, C.Prod (name,so,ta) when n > 0 ->
+ split_prods ~subst ((name,(C.Decl so))::context) (n - 1) ta
+ | _ -> raise (AssertFailure (lazy "split_prods"))
+
+and is_really_smaller ~subst ~metasenv (context, recfuns, x, safes as k) te =
+ match R.whd ~subst context te with
+ | C.Rel m when List.mem m safes -> true
+ | C.Rel _ -> false
+ | C.LetIn _ -> raise (AssertFailure (lazy "letin after whd"))
+ | C.Sort _ | C.Implicit _ | C.Prod _ | C.Lambda _
+ | C.Const (Ref.Ref (_,_,(Ref.Decl | Ref.Def | Ref.Ind _ | Ref.CoFix _))) ->
+ raise (AssertFailure (lazy "not a constructor"))
+ | C.Appl ([]|[_]) -> raise (AssertFailure (lazy "empty/unary appl"))
+ | C.Appl (he::_) ->
+ (*CSC: sulla coda ci vogliono dei controlli? secondo noi no, ma *)
+ (*CSC: solo perche' non abbiamo trovato controesempi *)
+ (*TASSI: da capire soprattutto se he รจ un altro fix che non ha ridotto...*)
+ is_really_smaller ~subst ~metasenv k he
+ | C.Const (Ref.Ref (_,_,Ref.Con _)) -> false
+ | C.Const (Ref.Ref (_,_,Ref.Fix _)) -> assert false
+ (*| 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 tys,_ =
+ List.fold_left
+ (fun (types,len) (n,_,ty,_) ->
+ (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+ len+1)
+ ) ([],0) fl
+ and safes' = List.map (fun x -> x + len) safes in
+ List.fold_right
+ (fun (_,_,ty,bo) i ->
+ i &&
+ is_really_smaller ~subst (tys@context) n_plus_len nn_plus_len kl
+ x_plus_len safes' bo
+ ) fl true*)
+ | C.Meta _ ->
+ true (* XXX if this check is repeated when the user completes the
+ definition *)
+ | C.Match (Ref.Ref (_,uri,_) as ref,outtype,term,pl) ->
+ (match term with
+ | C.Rel m | C.Appl (C.Rel m :: _ ) when List.mem m safes || m = x ->
+ let isinductive, paramsno, tl, _, i = E.get_checked_indtys ref in
+ if not isinductive then
+ List.for_all (is_really_smaller ~subst ~metasenv k) pl
+ else
+ let c_ctx,len,cl = fix_lefts_in_constrs ~subst uri paramsno tl i in
+ List.for_all2
+ (fun p (_,_,debruijnedte) ->
+ let rl'=recursive_args ~subst ~metasenv c_ctx 0 len debruijnedte in
+ let e, k = get_new_safes ~subst k p rl' in
+ is_really_smaller ~subst ~metasenv k e)
+ pl cl
+ | _ -> List.for_all (is_really_smaller ~subst ~metasenv k) pl)
+
+and returns_a_coinductive ~subst context ty =
+ match R.whd ~subst context ty with
+ | C.Const (Ref.Ref (_,uri,Ref.Ind _) as ref)
+ | C.Appl (C.Const (Ref.Ref (_,uri,Ref.Ind _) as ref)::_) ->
+ let isinductive, _, _, _, _ = E.get_checked_indtys ref in
+ if isinductive then None else (Some uri)
+ | C.Prod (n,so,de) ->
+ returns_a_coinductive ~subst ((n,C.Decl so)::context) de
+ | _ -> None
+
+and type_of_constant ((Ref.Ref (_,uri,_)) as ref) =
+ let cobj =
+ match E.get_obj uri with
+ | true, cobj -> cobj
+ | false, uobj ->
+ !logger (`Start_type_checking uri);
+ check_obj_well_typed uobj;
+ E.add_obj uobj;
+ !logger (`Type_checking_completed uri);
+ uobj
+ in
+ match cobj, ref with
+ | (_,_,_,_,C.Inductive (_,_,tl,_)), Ref.Ref (_,_,Ref.Ind i) ->
+ let _,_,arity,_ = List.nth tl i in arity
+ | (_,_,_,_,C.Inductive (_,_,tl,_)), Ref.Ref (_,_,Ref.Con (i,j)) ->
+ let _,_,_,cl = List.nth tl i in
+ let _,_,arity = List.nth cl (j-1) in
+ arity
+ | (_,_,_,_,C.Fixpoint (_,fl,_)), Ref.Ref (_,_,(Ref.Fix (i,_)|Ref.CoFix i)) ->
+ let _,_,_,arity,_ = List.nth fl i in
+ arity
+ | (_,_,_,_,C.Constant (_,_,_,ty,_)), Ref.Ref (_,_,(Ref.Def |Ref.Decl)) -> ty
+ | _ -> raise (AssertFailure (lazy "type_of_constant: environment/reference"))
+
+and check_obj_well_typed (uri,height,metasenv,subst,kind) =
+ (* CSC: here we should typecheck the metasenv and the subst *)
+ assert (metasenv = [] && subst = []);
+ match kind with
+ | C.Constant (_,_,Some te,ty,_) ->
+(*
+ prerr_endline ("TY: " ^ NCicPp.ppterm ~subst ~metasenv ~context:[] ty);
+ prerr_endline ("BO: " ^ NCicPp.ppterm ~subst ~metasenv ~context:[] te);
+*)
+ let _ = typeof ~subst ~metasenv [] ty in
+ let ty_te = typeof ~subst ~metasenv [] te in
+(* prerr_endline "XXXX"; *)
+ if not (R.are_convertible ~subst ~metasenv [] ty_te ty) then
+ raise (TypeCheckerFailure (lazy (Printf.sprintf
+ "the type of the body is not the one expected:\n%s\nvs\n%s"
+ (NCicPp.ppterm ~subst ~metasenv ~context:[] ty_te)
+ (NCicPp.ppterm ~subst ~metasenv ~context:[] ty))))
+ | C.Constant (_,_,None,ty,_) -> ignore (typeof ~subst ~metasenv [] ty)
+ | C.Inductive (is_ind, leftno, tyl, _) ->
+ check_mutual_inductive_defs uri ~metasenv ~subst is_ind leftno tyl
+ | C.Fixpoint (inductive,fl,_) ->
+ let types,kl,len =
+ List.fold_left
+ (fun (types,kl,len) (_,name,k,ty,_) ->
+ let _ = typeof ~subst ~metasenv [] ty in
+ ((name,(C.Decl (S.lift len ty)))::types, k::kl,len+1)
+ ) ([],[],0) fl
+ in
+ List.iter (fun (_,name,x,ty,bo) ->
+ let bo = debruijn uri len bo in
+ let ty_bo = typeof ~subst ~metasenv types bo in
+ if not (R.are_convertible ~subst ~metasenv types ty_bo (S.lift len ty))
+ then raise (TypeCheckerFailure (lazy ("(Co)Fix: ill-typed bodies")))
+ else
+ if inductive then begin
+ let m, context = eat_lambdas ~subst ~metasenv types (x + 1) bo in
+ (* guarded by destructors conditions D{f,k,x,M} *)
+ let rec enum_from k =
+ function [] -> [] | v::tl -> (k,v)::enum_from (k+1) tl
+ in
+ guarded_by_destructors
+ ~subst ~metasenv context (enum_from (x+2) kl) m
+ end else
+ match returns_a_coinductive ~subst [] ty with
+ | None ->
+ raise (TypeCheckerFailure
+ (lazy "CoFix: does not return a coinductive type"))
+ | Some uri ->
+ (* guarded by constructors conditions C{f,M} *)
+ if not (guarded_by_constructors ~subst ~metasenv
+ types 0 len false bo [] uri)
+ then
+ raise (TypeCheckerFailure
+ (lazy "CoFix: not guarded by constructors"))
+ ) fl
+
+let typecheck_obj = check_obj_well_typed;;
+
+(* EOF *)