aboutsummaryrefslogtreecommitdiff
path: root/pretyping/indrec.ml
diff options
context:
space:
mode:
Diffstat (limited to 'pretyping/indrec.ml')
-rw-r--r--pretyping/indrec.ml638
1 files changed, 638 insertions, 0 deletions
diff --git a/pretyping/indrec.ml b/pretyping/indrec.ml
new file mode 100644
index 0000000000..7615a17514
--- /dev/null
+++ b/pretyping/indrec.ml
@@ -0,0 +1,638 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(* File initially created by Christine Paulin, 1996 *)
+
+(* This file builds various inductive schemes *)
+
+open Pp
+open CErrors
+open Util
+open Names
+open Libnames
+open Globnames
+open Nameops
+open Term
+open Constr
+open Context
+open Vars
+open Namegen
+open Declarations
+open Declareops
+open Inductive
+open Inductiveops
+open Environ
+open Reductionops
+open Context.Rel.Declaration
+
+type dep_flag = bool
+
+(* Errors related to recursors building *)
+type recursion_scheme_error =
+ | NotAllowedCaseAnalysis of (*isrec:*) bool * Sorts.t * pinductive
+ | NotMutualInScheme of inductive * inductive
+ | NotAllowedDependentAnalysis of (*isrec:*) bool * inductive
+
+exception RecursionSchemeError of env * recursion_scheme_error
+
+let named_hd env t na = named_hd env (Evd.from_env env) (EConstr.of_constr t) na
+let name_assumption env = function
+| LocalAssum (na,t) -> LocalAssum (map_annot (named_hd env t) na, t)
+| LocalDef (na,c,t) -> LocalDef (map_annot (named_hd env c) na, c, t)
+
+let mkLambda_or_LetIn_name env d b = mkLambda_or_LetIn (name_assumption env d) b
+let mkProd_or_LetIn_name env d b = mkProd_or_LetIn (name_assumption env d) b
+let mkLambda_name env (n,a,b) = mkLambda_or_LetIn_name env (LocalAssum (n,a)) b
+let mkProd_name env (n,a,b) = mkProd_or_LetIn_name env (LocalAssum (n,a)) b
+let it_mkProd_or_LetIn_name env b l = List.fold_left (fun c d -> mkProd_or_LetIn_name env d c) b l
+let it_mkLambda_or_LetIn_name env b l = List.fold_left (fun c d -> mkLambda_or_LetIn_name env d c) b l
+
+let make_prod_dep dep env = if dep then mkProd_name env else mkProd
+let mkLambda_string s r t c = mkLambda (make_annot (Name (Id.of_string s)) r, t, c)
+
+
+(*******************************************)
+(* Building curryfied elimination *)
+(*******************************************)
+
+let is_private mib =
+ match mib.mind_private with
+ | Some true -> true
+ | _ -> false
+
+let check_privacy_block mib =
+ if is_private mib then
+ user_err (str"case analysis on a private inductive type")
+
+(**********************************************************************)
+(* Building case analysis schemes *)
+(* Christine Paulin, 1996 *)
+
+let mis_make_case_com dep env sigma (ind, u as pind) (mib,mip as specif) kind =
+ let lnamespar = Vars.subst_instance_context u mib.mind_params_ctxt in
+ let indf = make_ind_family(pind, Context.Rel.to_extended_list mkRel 0 lnamespar) in
+ let constrs = get_constructors env indf in
+ let projs = get_projections env ind in
+ let relevance = Sorts.relevance_of_sort_family kind in
+
+ let () = if Option.is_empty projs then check_privacy_block mib in
+ let () =
+ if not (Sorts.List.mem kind (elim_sorts specif)) then
+ raise
+ (RecursionSchemeError
+ (env, NotAllowedCaseAnalysis (false, fst (UnivGen.fresh_sort_in_family kind), pind)))
+ in
+ let ndepar = mip.mind_nrealdecls + 1 in
+
+ (* Pas génant car env ne sert pas à typer mais juste à renommer les Anonym *)
+ (* mais pas très joli ... (mais manque get_sort_of à ce niveau) *)
+ let env' = push_rel_context lnamespar env in
+
+ let rec add_branch env k =
+ if Int.equal k (Array.length mip.mind_consnames) then
+ let nbprod = k+1 in
+
+ let indf' = lift_inductive_family nbprod indf in
+ let arsign,sort = get_arity env indf' in
+ let r = Sorts.relevance_of_sort_family sort in
+ let depind = build_dependent_inductive env indf' in
+ let deparsign = LocalAssum (make_annot Anonymous r,depind)::arsign in
+
+ let rci = relevance in
+ let ci = make_case_info env (fst pind) rci RegularStyle in
+ let pbody =
+ appvect
+ (mkRel (ndepar + nbprod),
+ if dep then Context.Rel.to_extended_vect mkRel 0 deparsign
+ else Context.Rel.to_extended_vect mkRel 1 arsign) in
+ let p =
+ it_mkLambda_or_LetIn_name env'
+ ((if dep then mkLambda_name env' else mkLambda)
+ (make_annot Anonymous r,depind,pbody))
+ arsign
+ in
+ let obj =
+ match projs with
+ | None -> mkCase (ci, lift ndepar p, mkRel 1,
+ Termops.rel_vect ndepar k)
+ | Some ps ->
+ let term =
+ mkApp (mkRel 2,
+ Array.map
+ (fun p -> mkProj (Projection.make p true, mkRel 1)) ps) in
+ if dep then
+ let ty = mkApp (mkRel 3, [| mkRel 1 |]) in
+ mkCast (term, DEFAULTcast, ty)
+ else term
+ in
+ it_mkLambda_or_LetIn_name env' obj deparsign
+ else
+ let cs = lift_constructor (k+1) constrs.(k) in
+ let t = build_branch_type env sigma dep (mkRel (k+1)) cs in
+ mkLambda_string "f" relevance t
+ (add_branch (push_rel (LocalAssum (make_annot Anonymous relevance, t)) env) (k+1))
+ in
+ let (sigma, s) = Evd.fresh_sort_in_family ~rigid:Evd.univ_flexible_alg sigma kind in
+ let typP = make_arity env' sigma dep indf s in
+ let typP = EConstr.Unsafe.to_constr typP in
+ let c =
+ it_mkLambda_or_LetIn_name env
+ (mkLambda_string "P" Sorts.Relevant typP
+ (add_branch (push_rel (LocalAssum (make_annot Anonymous Sorts.Relevant,typP)) env') 0)) lnamespar
+ in
+ (sigma, c)
+
+(* check if the type depends recursively on one of the inductive scheme *)
+
+(**********************************************************************)
+(* Building the recursive elimination *)
+(* Christine Paulin, 1996 *)
+
+(*
+ * t is the type of the constructor co and recargs is the information on
+ * the recursive calls. (It is assumed to be in form given by the user).
+ * build the type of the corresponding branch of the recurrence principle
+ * assuming f has this type, branch_rec gives also the term
+ * [x1]..[xk](f xi (F xi) ...) to be put in the corresponding branch of
+ * the case operation
+ * FPvect gives for each inductive definition if we want an elimination
+ * on it with which predicate and which recursive function.
+ *)
+
+let type_rec_branch is_rec dep env sigma (vargs,depPvect,decP) tyi cs recargs =
+ let make_prod = make_prod_dep dep in
+ let nparams = List.length vargs in
+ let process_pos env depK pk =
+ let rec prec env i sign p =
+ let p',largs = whd_allnolet_stack env sigma (EConstr.of_constr p) in
+ let p' = EConstr.Unsafe.to_constr p' in
+ let largs = List.map EConstr.Unsafe.to_constr largs in
+ match kind p' with
+ | Prod (n,t,c) ->
+ let d = LocalAssum (n,t) in
+ make_prod env (n,t,prec (push_rel d env) (i+1) (d::sign) c)
+ | LetIn (n,b,t,c) when List.is_empty largs ->
+ let d = LocalDef (n,b,t) in
+ mkLetIn (n,b,t,prec (push_rel d env) (i+1) (d::sign) c)
+ | Ind (_,_) ->
+ let realargs = List.skipn nparams largs in
+ let base = applist (lift i pk,realargs) in
+ if depK then
+ Reduction.beta_appvect
+ base [|applist (mkRel (i+1), Context.Rel.to_extended_list mkRel 0 sign)|]
+ else
+ base
+ | _ ->
+ let t' = whd_all env sigma (EConstr.of_constr p) in
+ let t' = EConstr.Unsafe.to_constr t' in
+ if Constr.equal p' t' then assert false
+ else prec env i sign t'
+ in
+ prec env 0 []
+ in
+ let rec process_constr env i c recargs nhyps li =
+ if nhyps > 0 then match kind c with
+ | Prod (n,t,c_0) ->
+ let (optionpos,rest) =
+ match recargs with
+ | [] -> None,[]
+ | ra::rest ->
+ (match dest_recarg ra with
+ | Mrec (_,j) when is_rec -> (depPvect.(j),rest)
+ | Imbr _ -> (None,rest)
+ | _ -> (None, rest))
+ in
+ (match optionpos with
+ | None ->
+ make_prod env
+ (n,t,
+ process_constr (push_rel (LocalAssum (n,t)) env) (i+1) c_0 rest
+ (nhyps-1) (i::li))
+ | Some(dep',p) ->
+ let nP = lift (i+1+decP) p in
+ let env' = push_rel (LocalAssum (n,t)) env in
+ let t_0 = process_pos env' dep' nP (lift 1 t) in
+ let r_0 = Retyping.relevance_of_type env' sigma (EConstr.of_constr t_0) in
+ make_prod_dep (dep || dep') env
+ (n,t,
+ mkArrow t_0 r_0
+ (process_constr
+ (push_rel (LocalAssum (make_annot Anonymous n.binder_relevance,t_0)) env')
+ (i+2) (lift 1 c_0) rest (nhyps-1) (i::li))))
+ | LetIn (n,b,t,c_0) ->
+ mkLetIn (n,b,t,
+ process_constr
+ (push_rel (LocalDef (n,b,t)) env)
+ (i+1) c_0 recargs (nhyps-1) li)
+ | _ -> assert false
+ else
+ if dep then
+ let realargs = List.rev_map (fun k -> mkRel (i-k)) li in
+ let params = List.map (lift i) vargs in
+ let co = applist (mkConstructU cs.cs_cstr,params@realargs) in
+ Reduction.beta_appvect c [|co|]
+ else c
+ in
+ let nhyps = List.length cs.cs_args in
+ let nP = match depPvect.(tyi) with
+ | Some(_,p) -> lift (nhyps+decP) p
+ | _ -> assert false in
+ let base = appvect (nP,cs.cs_concl_realargs) in
+ let c = it_mkProd_or_LetIn base cs.cs_args in
+ process_constr env 0 c recargs nhyps []
+
+let make_rec_branch_arg env sigma (nparrec,fvect,decF) f cstr recargs =
+ let process_pos env fk =
+ let rec prec env i hyps p =
+ let p',largs = whd_allnolet_stack env sigma (EConstr.of_constr p) in
+ let p' = EConstr.Unsafe.to_constr p' in
+ let largs = List.map EConstr.Unsafe.to_constr largs in
+ match kind p' with
+ | Prod (n,t,c) ->
+ let d = LocalAssum (n,t) in
+ mkLambda_name env (n,t,prec (push_rel d env) (i+1) (d::hyps) c)
+ | LetIn (n,b,t,c) when List.is_empty largs ->
+ let d = LocalDef (n,b,t) in
+ mkLetIn (n,b,t,prec (push_rel d env) (i+1) (d::hyps) c)
+ | Ind _ ->
+ let realargs = List.skipn nparrec largs
+ and arg = appvect (mkRel (i+1), Context.Rel.to_extended_vect mkRel 0 hyps) in
+ applist(lift i fk,realargs@[arg])
+ | _ ->
+ let t' = whd_all env sigma (EConstr.of_constr p) in
+ let t' = EConstr.Unsafe.to_constr t' in
+ if Constr.equal t' p' then assert false
+ else prec env i hyps t'
+ in
+ prec env 0 []
+ in
+ (* ici, cstrprods est la liste des produits du constructeur instantié *)
+ let rec process_constr env i f = function
+ | (LocalAssum (n,t) as d)::cprest, recarg::rest ->
+ let optionpos =
+ match dest_recarg recarg with
+ | Norec -> None
+ | Imbr _ -> None
+ | Mrec (_,i) -> fvect.(i)
+ in
+ (match optionpos with
+ | None ->
+ mkLambda_name env
+ (n,t,process_constr (push_rel d env) (i+1)
+ (EConstr.Unsafe.to_constr (whd_beta Evd.empty (EConstr.of_constr (applist (lift 1 f, [(mkRel 1)])))))
+ (cprest,rest))
+ | Some(_,f_0) ->
+ let nF = lift (i+1+decF) f_0 in
+ let env' = push_rel d env in
+ let arg = process_pos env' nF (lift 1 t) in
+ mkLambda_name env
+ (n,t,process_constr env' (i+1)
+ (EConstr.Unsafe.to_constr (whd_beta Evd.empty (EConstr.of_constr (applist (lift 1 f, [(mkRel 1); arg])))))
+ (cprest,rest)))
+ | (LocalDef (n,c,t) as d)::cprest, rest ->
+ mkLetIn
+ (n,c,t,
+ process_constr (push_rel d env) (i+1) (lift 1 f)
+ (cprest,rest))
+ | [],[] -> f
+ | _,[] | [],_ -> anomaly (Pp.str "process_constr.")
+
+ in
+ process_constr env 0 f (List.rev cstr.cs_args, recargs)
+
+(* Main function *)
+let mis_make_indrec env sigma ?(force_mutual=false) listdepkind mib u =
+ let nparams = mib.mind_nparams in
+ let nparrec = mib.mind_nparams_rec in
+ let evdref = ref sigma in
+ let lnonparrec,lnamesparrec =
+ Termops.context_chop (nparams-nparrec) (Vars.subst_instance_context u mib.mind_params_ctxt) in
+ let nrec = List.length listdepkind in
+ let depPvec =
+ Array.make mib.mind_ntypes (None : (bool * constr) option) in
+ let _ =
+ let rec
+ assign k = function
+ | [] -> ()
+ | ((indi,u),mibi,mipi,dep,_)::rest ->
+ (Array.set depPvec (snd indi) (Some(dep,mkRel k));
+ assign (k-1) rest)
+ in
+ assign nrec listdepkind in
+ let recargsvec =
+ Array.map (fun mip -> mip.mind_recargs) mib.mind_packets in
+ (* recarg information for non recursive parameters *)
+ let rec recargparn l n =
+ if Int.equal n 0 then l else recargparn (mk_norec::l) (n-1) in
+ let recargpar = recargparn [] (nparams-nparrec) in
+ let make_one_rec p =
+ let makefix nbconstruct =
+ let rec mrec i ln lrelevance ltyp ldef = function
+ | ((indi,u),mibi,mipi,dep,target_sort)::rest ->
+ let tyi = snd indi in
+ let nctyi =
+ Array.length mipi.mind_consnames in (* nb constructeurs du type*)
+
+ (* arity in the context of the fixpoint, i.e.
+ P1..P_nrec f1..f_nbconstruct *)
+ let args = Context.Rel.to_extended_list mkRel (nrec+nbconstruct) lnamesparrec in
+ let indf = make_ind_family((indi,u),args) in
+
+ let arsign,s = get_arity env indf in
+ let r = Sorts.relevance_of_sort_family s in
+ let depind = build_dependent_inductive env indf in
+ let deparsign = LocalAssum (make_annot Anonymous r,depind)::arsign in
+
+ let nonrecpar = Context.Rel.length lnonparrec in
+ let larsign = Context.Rel.length deparsign in
+ let ndepar = larsign - nonrecpar in
+ let dect = larsign+nrec+nbconstruct in
+
+ (* constructors in context of the Cases expr, i.e.
+ P1..P_nrec f1..f_nbconstruct F_1..F_nrec a_1..a_nar x:I *)
+ let args' = Context.Rel.to_extended_list mkRel (dect+nrec) lnamesparrec in
+ let args'' = Context.Rel.to_extended_list mkRel ndepar lnonparrec in
+ let indf' = make_ind_family((indi,u),args'@args'') in
+
+ let branches =
+ let constrs = get_constructors env indf' in
+ let fi = Termops.rel_vect (dect-i-nctyi) nctyi in
+ let vecfi = Array.map
+ (fun f -> appvect (f, Context.Rel.to_extended_vect mkRel ndepar lnonparrec))
+ fi
+ in
+ Array.map3
+ (make_rec_branch_arg env !evdref
+ (nparrec,depPvec,larsign))
+ vecfi constrs (dest_subterms recargsvec.(tyi))
+ in
+
+ let j = (match depPvec.(tyi) with
+ | Some (_,c) when isRel c -> destRel c
+ | _ -> assert false)
+ in
+
+ (* Predicate in the context of the case *)
+
+ let depind' = build_dependent_inductive env indf' in
+ let arsign',s = get_arity env indf' in
+ let r = Sorts.relevance_of_sort_family s in
+ let deparsign' = LocalAssum (make_annot Anonymous r,depind')::arsign' in
+
+ let pargs =
+ let nrpar = Context.Rel.to_extended_list mkRel (2*ndepar) lnonparrec
+ and nrar = if dep then Context.Rel.to_extended_list mkRel 0 deparsign'
+ else Context.Rel.to_extended_list mkRel 1 arsign'
+ in nrpar@nrar
+
+ in
+
+ (* body of i-th component of the mutual fixpoint *)
+ let target_relevance = Sorts.relevance_of_sort_family target_sort in
+ let deftyi =
+ let rci = target_relevance in
+ let ci = make_case_info env indi rci RegularStyle in
+ let concl = applist (mkRel (dect+j+ndepar),pargs) in
+ let pred =
+ it_mkLambda_or_LetIn_name env
+ ((if dep then mkLambda_name env else mkLambda)
+ (make_annot Anonymous r,depind',concl))
+ arsign'
+ in
+ let obj =
+ Inductiveops.make_case_or_project env !evdref indf ci (EConstr.of_constr pred)
+ (EConstr.mkRel 1) (Array.map EConstr.of_constr branches)
+ in
+ let obj = EConstr.to_constr !evdref obj in
+ it_mkLambda_or_LetIn_name env obj
+ (Termops.lift_rel_context nrec deparsign)
+ in
+
+ (* type of i-th component of the mutual fixpoint *)
+
+ let typtyi =
+ let concl =
+ let pargs = if dep then Context.Rel.to_extended_vect mkRel 0 deparsign
+ else Context.Rel.to_extended_vect mkRel 1 arsign
+ in appvect (mkRel (nbconstruct+ndepar+nonrecpar+j),pargs)
+ in it_mkProd_or_LetIn_name env
+ concl
+ deparsign
+ in
+ mrec (i+nctyi) (Context.Rel.nhyps arsign ::ln) (target_relevance::lrelevance) (typtyi::ltyp)
+ (deftyi::ldef) rest
+ | [] ->
+ let fixn = Array.of_list (List.rev ln) in
+ let fixtyi = Array.of_list (List.rev ltyp) in
+ let fixdef = Array.of_list (List.rev ldef) in
+ let lrelevance = CArray.rev_of_list lrelevance in
+ let names = Array.map (fun r -> make_annot (Name(Id.of_string "F")) r) lrelevance in
+ mkFix ((fixn,p),(names,fixtyi,fixdef))
+ in
+ mrec 0 [] [] [] []
+ in
+ let rec make_branch env i = function
+ | ((indi,u),mibi,mipi,dep,sfam)::rest ->
+ let tyi = snd indi in
+ let nconstr = Array.length mipi.mind_consnames in
+ let rec onerec env j =
+ if Int.equal j nconstr then
+ make_branch env (i+j) rest
+ else
+ let recarg = (dest_subterms recargsvec.(tyi)).(j) in
+ let recarg = recargpar@recarg in
+ let vargs = Context.Rel.to_extended_list mkRel (nrec+i+j) lnamesparrec in
+ let cs = get_constructor ((indi,u),mibi,mipi,vargs) (j+1) in
+ let p_0 =
+ type_rec_branch
+ true dep env !evdref (vargs,depPvec,i+j) tyi cs recarg
+ in
+ let r_0 = Sorts.relevance_of_sort_family sfam in
+ mkLambda_string "f" r_0 p_0
+ (onerec (push_rel (LocalAssum (make_annot Anonymous r_0,p_0)) env) (j+1))
+ in onerec env 0
+ | [] ->
+ makefix i listdepkind
+ in
+ let rec put_arity env i = function
+ | ((indi,u),_,_,dep,kinds)::rest ->
+ let indf = make_ind_family ((indi,u), Context.Rel.to_extended_list mkRel i lnamesparrec) in
+ let s =
+ let sigma, res = Evd.fresh_sort_in_family ~rigid:Evd.univ_flexible_alg !evdref kinds in
+ evdref := sigma; res
+ in
+ let typP = make_arity env !evdref dep indf s in
+ let typP = EConstr.Unsafe.to_constr typP in
+ mkLambda_string "P" Sorts.Relevant typP
+ (put_arity (push_rel (LocalAssum (anonR,typP)) env) (i+1) rest)
+ | [] ->
+ make_branch env 0 listdepkind
+ in
+
+ (* Body on make_one_rec *)
+ let ((indi,u),mibi,mipi,dep,kind) = List.nth listdepkind p in
+
+ if force_mutual || (mis_is_recursive_subset
+ (List.map (fun ((indi,u),_,_,_,_) -> snd indi) listdepkind)
+ mipi.mind_recargs)
+ then
+ let env' = push_rel_context lnamesparrec env in
+ it_mkLambda_or_LetIn_name env (put_arity env' 0 listdepkind)
+ lnamesparrec
+ else
+ let evd = !evdref in
+ let (evd, c) = mis_make_case_com dep env evd (indi,u) (mibi,mipi) kind in
+ evdref := evd; c
+ in
+ (* Body of mis_make_indrec *)
+ !evdref, List.init nrec make_one_rec
+
+(**********************************************************************)
+(* This builds elimination predicate for Case tactic *)
+
+let build_case_analysis_scheme env sigma pity dep kind =
+ let (mib,mip) = lookup_mind_specif env (fst pity) in
+ if dep && not (Inductiveops.has_dependent_elim mib) then
+ raise (RecursionSchemeError (env, NotAllowedDependentAnalysis (false, fst pity)));
+ mis_make_case_com dep env sigma pity (mib,mip) kind
+
+let is_in_prop mip =
+ match inductive_sort_family mip with
+ | InProp -> true
+ | _ -> false
+
+let build_case_analysis_scheme_default env sigma pity kind =
+ let (mib,mip) = lookup_mind_specif env (fst pity) in
+ let dep = not (is_in_prop mip || not (Inductiveops.has_dependent_elim mib)) in
+ mis_make_case_com dep env sigma pity (mib,mip) kind
+
+(**********************************************************************)
+(* [modify_sort_scheme s rec] replaces the sort of the scheme
+ [rec] by [s] *)
+
+let change_sort_arity sort =
+ let rec drec a = match kind a with
+ | Cast (c,_,_) -> drec c
+ | Prod (n,t,c) -> let s, c' = drec c in s, mkProd (n, t, c')
+ | LetIn (n,b,t,c) -> let s, c' = drec c in s, mkLetIn (n,b,t,c')
+ | Sort s -> s, mkSort sort
+ | _ -> assert false
+ in
+ drec
+
+(* Change the sort in the type of an inductive definition, builds the
+ corresponding eta-expanded term *)
+let weaken_sort_scheme env evd set sort npars term ty =
+ let evdref = ref evd in
+ let rec drec np elim =
+ match kind elim with
+ | Prod (n,t,c) ->
+ if Int.equal np 0 then
+ let osort, t' = change_sort_arity sort t in
+ evdref := (if set then Evd.set_eq_sort else Evd.set_leq_sort) env !evdref sort osort;
+ mkProd (n, t', c),
+ mkLambda (n, t', mkApp(term,Termops.rel_vect 0 (npars+1)))
+ else
+ let c',term' = drec (np-1) c in
+ mkProd (n, t, c'), mkLambda (n, t, term')
+ | LetIn (n,b,t,c) -> let c',term' = drec np c in
+ mkLetIn (n,b,t,c'), mkLetIn (n,b,t,term')
+ | _ -> anomaly ~label:"weaken_sort_scheme" (Pp.str "wrong elimination type.")
+ in
+ let ty, term = drec npars ty in
+ !evdref, ty, term
+
+(**********************************************************************)
+(* Interface to build complex Scheme *)
+(* Check inductive types only occurs once
+(otherwise we obtain a meaning less scheme) *)
+
+let check_arities env listdepkind =
+ let _ = List.fold_left
+ (fun ln (((_,ni as mind),u),mibi,mipi,dep,kind) ->
+ let kelim = elim_sorts (mibi,mipi) in
+ if not (Sorts.List.mem kind kelim) then raise
+ (RecursionSchemeError
+ (env, NotAllowedCaseAnalysis (true, fst (UnivGen.fresh_sort_in_family kind),(mind,u))))
+ else if Int.List.mem ni ln then raise
+ (RecursionSchemeError (env, NotMutualInScheme (mind,mind)))
+ else ni::ln)
+ [] listdepkind
+ in true
+
+let build_mutual_induction_scheme env sigma ?(force_mutual=false) = function
+ | ((mind,u),dep,s)::lrecspec ->
+ let (mib,mip) = lookup_mind_specif env mind in
+ if dep && not (Inductiveops.has_dependent_elim mib) then
+ raise (RecursionSchemeError (env, NotAllowedDependentAnalysis (true, mind)));
+ let (sp,tyi) = mind in
+ let listdepkind =
+ ((mind,u),mib,mip,dep,s)::
+ (List.map
+ (function ((mind',u'),dep',s') ->
+ let (sp',_) = mind' in
+ if MutInd.equal sp sp' then
+ let (mibi',mipi') = lookup_mind_specif env mind' in
+ ((mind',u'),mibi',mipi',dep',s')
+ else
+ raise (RecursionSchemeError (env, NotMutualInScheme (mind,mind'))))
+ lrecspec)
+ in
+ let _ = check_arities env listdepkind in
+ mis_make_indrec env sigma ~force_mutual listdepkind mib u
+ | _ -> anomaly (Pp.str "build_induction_scheme expects a non empty list of inductive types.")
+
+let build_induction_scheme env sigma pind dep kind =
+ let (mib,mip) = lookup_mind_specif env (fst pind) in
+ if dep && not (Inductiveops.has_dependent_elim mib) then
+ raise (RecursionSchemeError (env, NotAllowedDependentAnalysis (true, fst pind)));
+ let sigma, l = mis_make_indrec env sigma [(pind,mib,mip,dep,kind)] mib (snd pind) in
+ sigma, List.hd l
+
+(*s Eliminations. *)
+
+let elimination_suffix = function
+ | InSProp -> "_sind"
+ | InProp -> "_ind"
+ | InSet -> "_rec"
+ | InType -> "_rect"
+
+let case_suffix = "_case"
+
+let make_elimination_ident id s = add_suffix id (elimination_suffix s)
+
+(* Look up function for the default elimination constant *)
+
+let lookup_eliminator env ind_sp s =
+ let kn,i = ind_sp in
+ let mpu = KerName.modpath @@ MutInd.user kn in
+ let mpc = KerName.modpath @@ MutInd.canonical kn in
+ let ind_id = (lookup_mind kn env).mind_packets.(i).mind_typename in
+ let id = add_suffix ind_id (elimination_suffix s) in
+ let l = Label.of_id id in
+ let knu = KerName.make mpu l in
+ let knc = KerName.make mpc l in
+ (* Try first to get an eliminator defined in the same section as the *)
+ (* inductive type *)
+ try
+ let cst = Constant.make knu knc in
+ let _ = lookup_constant cst env in
+ ConstRef cst
+ with Not_found ->
+ (* Then try to get a user-defined eliminator in some other places *)
+ (* using short name (e.g. for "eq_rec") *)
+ try Nametab.locate (qualid_of_ident id)
+ with Not_found ->
+ user_err ~hdr:"default_elim"
+ (strbrk "Cannot find the elimination combinator " ++
+ Id.print id ++ strbrk ", the elimination of the inductive definition " ++
+ Nametab.pr_global_env Id.Set.empty (IndRef ind_sp) ++
+ strbrk " on sort " ++ Sorts.pr_sort_family s ++
+ strbrk " is probably not allowed.")