summaryrefslogtreecommitdiff
path: root/pretyping
diff options
context:
space:
mode:
authorGravatar Samuel Mimram <samuel.mimram@ens-lyon.org>2004-07-28 21:54:47 +0000
committerGravatar Samuel Mimram <samuel.mimram@ens-lyon.org>2004-07-28 21:54:47 +0000
commit6b649aba925b6f7462da07599fe67ebb12a3460e (patch)
tree43656bcaa51164548f3fa14e5b10de5ef1088574 /pretyping
Imported Upstream version 8.0pl1upstream/8.0pl1
Diffstat (limited to 'pretyping')
-rw-r--r--pretyping/cases.ml1773
-rw-r--r--pretyping/cases.mli56
-rw-r--r--pretyping/cbv.ml352
-rw-r--r--pretyping/cbv.mli55
-rwxr-xr-xpretyping/classops.ml397
-rw-r--r--pretyping/classops.mli116
-rw-r--r--pretyping/coercion.ml211
-rw-r--r--pretyping/coercion.mli46
-rw-r--r--pretyping/detyping.ml492
-rw-r--r--pretyping/detyping.mli42
-rw-r--r--pretyping/doc.tex14
-rw-r--r--pretyping/evarconv.ml397
-rw-r--r--pretyping/evarconv.mli28
-rw-r--r--pretyping/evarutil.ml579
-rw-r--r--pretyping/evarutil.mli97
-rw-r--r--pretyping/evd.ml74
-rw-r--r--pretyping/evd.mli57
-rw-r--r--pretyping/indrec.ml553
-rw-r--r--pretyping/indrec.mli56
-rw-r--r--pretyping/inductiveops.ml352
-rw-r--r--pretyping/inductiveops.mli93
-rw-r--r--pretyping/instantiate.ml68
-rw-r--r--pretyping/instantiate.mli25
-rw-r--r--pretyping/matching.ml254
-rw-r--r--pretyping/matching.mli52
-rw-r--r--pretyping/pattern.ml287
-rw-r--r--pretyping/pattern.mli91
-rw-r--r--pretyping/pretype_errors.ml164
-rw-r--r--pretyping/pretype_errors.mli100
-rw-r--r--pretyping/pretyping.ml1024
-rw-r--r--pretyping/pretyping.mli86
-rw-r--r--pretyping/rawterm.ml365
-rw-r--r--pretyping/rawterm.mli139
-rwxr-xr-xpretyping/recordops.ml176
-rwxr-xr-xpretyping/recordops.mli58
-rw-r--r--pretyping/reductionops.ml717
-rw-r--r--pretyping/reductionops.mli190
-rw-r--r--pretyping/retyping.ml131
-rw-r--r--pretyping/retyping.mli36
-rw-r--r--pretyping/tacred.ml953
-rw-r--r--pretyping/tacred.mli85
-rw-r--r--pretyping/termops.ml938
-rw-r--r--pretyping/termops.mli186
-rw-r--r--pretyping/typing.ml174
-rw-r--r--pretyping/typing.mli27
45 files changed, 12166 insertions, 0 deletions
diff --git a/pretyping/cases.ml b/pretyping/cases.ml
new file mode 100644
index 00000000..2126f015
--- /dev/null
+++ b/pretyping/cases.ml
@@ -0,0 +1,1773 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: cases.ml,v 1.111.2.1 2004/07/16 19:30:43 herbelin Exp $ *)
+
+open Util
+open Names
+open Nameops
+open Term
+open Termops
+open Declarations
+open Inductiveops
+open Environ
+open Sign
+open Reductionops
+open Typeops
+open Type_errors
+
+open Rawterm
+open Retyping
+open Pretype_errors
+open Evarutil
+open Evarconv
+
+(* Pattern-matching errors *)
+
+type pattern_matching_error =
+ | BadPattern of constructor * constr
+ | BadConstructor of constructor * inductive
+ | WrongNumargConstructor of constructor * int
+ | WrongPredicateArity of constr * constr * constr
+ | NeedsInversion of constr * constr
+ | UnusedClause of cases_pattern list
+ | NonExhaustive of cases_pattern list
+ | CannotInferPredicate of (constr * types) array
+
+exception PatternMatchingError of env * pattern_matching_error
+
+let raise_pattern_matching_error (loc,ctx,te) =
+ Stdpp.raise_with_loc loc (PatternMatchingError(ctx,te))
+
+let error_bad_pattern_loc loc cstr ind =
+ raise_pattern_matching_error (loc, Global.env(), BadPattern (cstr,ind))
+
+let error_bad_constructor_loc loc cstr ind =
+ raise_pattern_matching_error (loc, Global.env(), BadConstructor (cstr,ind))
+
+let error_wrong_numarg_constructor_loc loc c n =
+ raise_pattern_matching_error (loc, Global.env(), WrongNumargConstructor (c,n))
+
+let error_wrong_predicate_arity_loc loc env c n1 n2 =
+ raise_pattern_matching_error (loc, env, WrongPredicateArity (c,n1,n2))
+
+let error_needs_inversion env x t =
+ raise (PatternMatchingError (env, NeedsInversion (x,t)))
+
+(*********************************************************************)
+(* A) Typing old cases *)
+(* This was previously in Indrec but creates existential holes *)
+
+let mkExistential isevars env loc = new_isevar isevars env loc (new_Type ())
+
+let norec_branch_scheme env isevars cstr =
+ let rec crec env = function
+ | d::rea -> mkProd_or_LetIn d (crec (push_rel d env) rea)
+ | [] -> mkExistential isevars env (dummy_loc, InternalHole) in
+ crec env (List.rev cstr.cs_args)
+
+let rec_branch_scheme env isevars (sp,j) recargs cstr =
+ let rec crec env (args,recargs) =
+ match args, recargs with
+ | (name,None,c as d)::rea,(ra::reca) ->
+ let d =
+ match dest_recarg ra with
+ | Mrec k when k=j ->
+ let t = mkExistential isevars env (dummy_loc, InternalHole)
+ in
+ mkArrow t
+ (crec (push_rel (Anonymous,None,t) env)
+ (List.rev (lift_rel_context 1 (List.rev rea)),reca))
+ | _ -> crec (push_rel d env) (rea,reca) in
+ mkProd (name, c, d)
+
+ | (name,Some b,c as d)::rea, reca ->
+ mkLetIn (name,b, c,crec (push_rel d env) (rea,reca))
+ | [],[] -> mkExistential isevars env (dummy_loc, InternalHole)
+ | _ -> anomaly "rec_branch_scheme"
+ in
+ crec env (List.rev cstr.cs_args,recargs)
+
+let branch_scheme env isevars isrec indf =
+ let (ind,params) = dest_ind_family indf in
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let cstrs = get_constructors env indf in
+ if isrec then
+ array_map2
+ (rec_branch_scheme env isevars ind)
+ (dest_subterms mip.mind_recargs) cstrs
+ else
+ Array.map (norec_branch_scheme env isevars) cstrs
+
+(******************************************************)
+(* B) Building ML like case expressions without types *)
+
+let concl_n env sigma =
+ let rec decrec m c = if m = 0 then (nf_evar sigma c) else
+ match kind_of_term (whd_betadeltaiota env sigma c) with
+ | Prod (n,_,c_0) -> decrec (m-1) c_0
+ | _ -> failwith "Typing.concl_n"
+ in
+ decrec
+
+let count_rec_arg j =
+ let rec crec i = function
+ | [] -> i
+ | ra::l ->
+ (match dest_recarg ra with
+ Mrec k -> crec (if k=j then (i+1) else i) l
+ | _ -> crec i l)
+ in
+ crec 0
+
+(* if arity of mispec is (p_bar:P_bar)(a_bar:A_bar)s where p_bar are the
+ * K parameters. Then then build_notdep builds the predicate
+ * [a_bar:A'_bar](lift k pred)
+ * where A'_bar = A_bar[p_bar <- globargs] *)
+
+let build_dep_pred env sigma indf pred =
+ let arsign,_ = get_arity env indf in
+ let psign = (Anonymous,None,build_dependent_inductive env indf)::arsign in
+ let nar = List.length psign in
+ it_mkLambda_or_LetIn_name env (lift nar pred) psign
+
+type ml_case_error =
+ | MlCaseAbsurd
+ | MlCaseDependent
+
+exception NotInferable of ml_case_error
+
+
+let pred_case_ml env sigma isrec (IndType (indf,realargs)) (i,ft) =
+ let pred =
+ let (ind,params) = dest_ind_family indf in
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let recargs = dest_subterms mip.mind_recargs in
+ if Array.length recargs = 0 then raise (NotInferable MlCaseAbsurd);
+ let recargi = recargs.(i) in
+ let j = snd ind in (* index of inductive *)
+ let nbrec = if isrec then count_rec_arg j recargi else 0 in
+ let nb_arg = List.length (recargs.(i)) + nbrec in
+ let pred = Evarutil.refresh_universes (concl_n env sigma nb_arg ft) in
+ if noccur_between 1 nb_arg pred then
+ lift (-nb_arg) pred
+ else
+ raise (NotInferable MlCaseDependent)
+ in
+ build_dep_pred env sigma indf pred
+
+(************************************************************************)
+(* Pattern-matching compilation (Cases) *)
+(************************************************************************)
+
+(************************************************************************)
+(* Configuration, errors and warnings *)
+
+open Pp
+
+let mssg_may_need_inversion () =
+ str "This pattern-matching is not exhaustive."
+
+let mssg_this_case_cannot_occur () =
+ "This pattern-matching is not exhaustive."
+
+(* Utils *)
+let make_anonymous_patvars =
+ list_tabulate (fun _ -> PatVar (dummy_loc,Anonymous))
+
+(* Environment management *)
+let push_rels vars env = List.fold_right push_rel vars env
+
+let push_rel_defs =
+ List.fold_right (fun (x,d,t) e -> push_rel (x,Some d,t) e)
+
+(* We have x1:t1...xn:tn,xi':ti,y1..yk |- c and re-generalize
+ over xi:ti to get x1:t1...xn:tn,xi':ti,y1..yk |- c[xi:=xi'] *)
+
+let regeneralize_rel i k j = if j = i+k then k else if j < i+k then j else j
+
+let rec regeneralize_index i k t = match kind_of_term t with
+ | Rel j when j = i+k -> mkRel (k+1)
+ | Rel j when j < i+k -> t
+ | Rel j when j > i+k -> t
+ | _ -> map_constr_with_binders succ (regeneralize_index i) k t
+
+type alias_constr =
+ | DepAlias
+ | NonDepAlias
+
+let mkSpecialLetInJudge j (na,(deppat,nondeppat,d,t)) =
+ { uj_val =
+ (match d with
+ | DepAlias -> mkLetIn (na,deppat,t,j.uj_val)
+ | NonDepAlias ->
+ if (not (dependent (mkRel 1) j.uj_type))
+ or (* A leaf: *) isRel deppat
+ then
+ (* The body of pat is not needed to type j - see *)
+ (* insert_aliases - and both deppat and nondeppat have the *)
+ (* same type, then one can freely substitute one by the other *)
+ subst1 nondeppat j.uj_val
+ else
+ (* The body of pat is not needed to type j but its value *)
+ (* is dependent in the type of j; our choice is to *)
+ (* enforce this dependency *)
+ mkLetIn (na,deppat,t,j.uj_val));
+ uj_type = subst1 deppat j.uj_type }
+
+(**********************************************************************)
+(* Structures used in compiling pattern-matching *)
+type 'a lifted = int * 'a
+
+let insert_lifted a = (0,a);;
+
+(* The pattern variables for [it] are in [user_ids] and the variables
+ to avoid are in [other_ids].
+*)
+
+type rhs =
+ { rhs_env : env;
+ other_ids : identifier list;
+ user_ids : identifier list;
+ rhs_lift : int;
+ it : rawconstr }
+
+type equation =
+ { dependencies : constr lifted list;
+ patterns : cases_pattern list;
+ rhs : rhs;
+ alias_stack : name list;
+ eqn_loc : loc;
+ used : bool ref;
+ tag : pattern_source }
+
+type matrix = equation list
+
+(* 1st argument of IsInd is the original ind before extracting the summary *)
+type tomatch_type =
+ | IsInd of types * inductive_type
+ | NotInd of constr option * types
+
+type tomatch_status =
+ | Pushed of ((constr * tomatch_type) * int list)
+ | Alias of (constr * constr * alias_constr * constr)
+ | Abstract of rel_declaration
+
+type tomatch_stack = tomatch_status list
+
+(* The type [predicate_signature] types the terms to match and the rhs:
+
+ - [PrLetIn (n,dep,pred)] types a pushed term ([Pushed]), if dep is true,
+ the term is dependent, if n<>0 then the type of the pushed term is
+ necessarily inductive with n real arguments. Otherwise, it may be
+ non inductive, or inductive without real arguments, or inductive
+ originating from a subterm in which case real args are not dependent;
+ it accounts for n+1 binders if dep or n binders if not dep
+ - [PrProd] types abstracted term ([Abstract]); it accounts for one binder
+ - [PrCcl] types the right-hand-side
+ - Aliases [Alias] have no trace in [predicate_signature]
+*)
+
+type predicate_signature =
+ | PrLetIn of (int * bool) * predicate_signature
+ | PrProd of predicate_signature
+ | PrCcl of constr
+
+(* We keep a constr for aliases and a cases_pattern for error message *)
+
+type alias_builder =
+ | AliasLeaf
+ | AliasConstructor of constructor
+
+type pattern_history =
+ | Top
+ | MakeAlias of alias_builder * pattern_continuation
+
+and pattern_continuation =
+ | Continuation of int * cases_pattern list * pattern_history
+ | Result of cases_pattern list
+
+let start_history n = Continuation (n, [], Top)
+
+let initial_history = function Continuation (_,[],Top) -> true | _ -> false
+
+let feed_history arg = function
+ | Continuation (n, l, h) when n>=1 ->
+ Continuation (n-1, arg :: l, h)
+ | Continuation (n, _, _) ->
+ anomaly ("Bad number of expected remaining patterns: "^(string_of_int n))
+ | Result _ ->
+ anomaly "Exhausted pattern history"
+
+(* This is for non exhaustive error message *)
+
+let rec rawpattern_of_partial_history args2 = function
+ | Continuation (n, args1, h) ->
+ let args3 = make_anonymous_patvars (n - (List.length args2)) in
+ build_rawpattern (List.rev_append args1 (args2@args3)) h
+ | Result pl -> pl
+
+and build_rawpattern args = function
+ | Top -> args
+ | MakeAlias (AliasLeaf, rh) ->
+ assert (args = []);
+ rawpattern_of_partial_history [PatVar (dummy_loc, Anonymous)] rh
+ | MakeAlias (AliasConstructor pci, rh) ->
+ rawpattern_of_partial_history
+ [PatCstr (dummy_loc, pci, args, Anonymous)] rh
+
+let complete_history = rawpattern_of_partial_history []
+
+(* This is to build glued pattern-matching history and alias bodies *)
+
+let rec simplify_history = function
+ | Continuation (0, l, Top) -> Result (List.rev l)
+ | Continuation (0, l, MakeAlias (f, rh)) ->
+ let pargs = List.rev l in
+ let pat = match f with
+ | AliasConstructor pci ->
+ PatCstr (dummy_loc,pci,pargs,Anonymous)
+ | AliasLeaf ->
+ assert (l = []);
+ PatVar (dummy_loc, Anonymous) in
+ feed_history pat rh
+ | h -> h
+
+(* Builds a continuation expecting [n] arguments and building [ci] applied
+ to this [n] arguments *)
+
+let push_history_pattern n current cont =
+ Continuation (n, [], MakeAlias (current, cont))
+
+(* A pattern-matching problem has the following form:
+
+ env, isevars |- <pred> Cases tomatch of mat end
+
+ where tomatch is some sequence of "instructions" (t1 ... tn)
+
+ and mat is some matrix
+ (p11 ... p1n -> rhs1)
+ ( ... )
+ (pm1 ... pmn -> rhsm)
+
+ Terms to match: there are 3 kinds of instructions
+
+ - "Pushed" terms to match are typed in [env]; these are usually just
+ Rel(n) except for the initial terms given by user and typed in [env]
+ - "Abstract" instructions means an abstraction has to be inserted in the
+ current branch to build (this means a pattern has been detected dependent
+ in another one and generalisation is necessary to ensure well-typing)
+ - "Alias" instructions means an alias has to be inserted (this alias
+ is usually removed at the end, except when its type is not the
+ same as the type of the matched term from which it comes -
+ typically because the inductive types are "real" parameters)
+
+ Right-hand-sides:
+
+ They consist of a raw term to type in an environment specific to the
+ clause they belong to: the names of declarations are those of the
+ variables present in the patterns. Therefore, they come with their
+ own [rhs_env] (actually it is the same as [env] except for the names
+ of variables).
+
+*)
+type pattern_matching_problem =
+ { env : env;
+ isevars : evar_defs;
+ pred : predicate_signature option;
+ tomatch : tomatch_stack;
+ history : pattern_continuation;
+ mat : matrix;
+ caseloc : loc;
+ typing_function: type_constraint -> env -> rawconstr -> unsafe_judgment }
+
+(*--------------------------------------------------------------------------*
+ * A few functions to infer the inductive type from the patterns instead of *
+ * checking that the patterns correspond to the ind. type of the *
+ * destructurated object. Allows type inference of examples like *
+ * [n]Cases n of O => true | _ => false end *
+ *--------------------------------------------------------------------------*)
+
+(* Computing the inductive type from the matrix of patterns *)
+
+let rec find_row_ind = function
+ [] -> None
+ | PatVar _ :: l -> find_row_ind l
+ | PatCstr(loc,c,_,_) :: _ -> Some (loc,c)
+
+exception NotCoercible
+
+let inh_coerce_to_ind isevars env tmloc ty tyi =
+ let (mib,mip) = Inductive.lookup_mind_specif env tyi in
+ let (ntys,_) = splay_prod env (evars_of isevars) mip.mind_nf_arity in
+ let hole_source = match tmloc with
+ | Some loc -> fun i -> (loc, TomatchTypeParameter (tyi,i))
+ | None -> fun _ -> (dummy_loc, InternalHole) in
+ let (_,evarl,_) =
+ List.fold_right
+ (fun (na,ty) (env,evl,n) ->
+ (push_rel (na,None,ty) env,
+ (new_isevar isevars env (hole_source n) ty)::evl,n+1))
+ ntys (env,[],1) in
+ let expected_typ = applist (mkInd tyi,evarl) in
+ (* devrait être indifférent d'exiger leq ou pas puisque pour
+ un inductif cela doit être égal *)
+ if the_conv_x_leq env isevars expected_typ ty then ty
+ else raise NotCoercible
+
+(* We do the unification for all the rows that contain
+ * constructor patterns. This is what we do at the higher level of patterns.
+ * For nested patterns, we do this unif when we ``expand'' the matrix, and we
+ * use the function above.
+ *)
+
+let unify_tomatch_with_patterns isevars env tmloc typ = function
+ | Some (cloc,(cstr,_ as c)) ->
+ (let tyi = inductive_of_constructor c in
+ try
+ let indtyp = inh_coerce_to_ind isevars env tmloc typ tyi in
+ IsInd (typ,find_rectype env (evars_of isevars) typ)
+ with NotCoercible ->
+ (* 2 cases : Not the right inductive or not an inductive at all *)
+ try
+ IsInd (typ,find_rectype env (evars_of isevars) typ)
+ (* will try to coerce later in check_and_adjust_constructor.. *)
+ with Not_found ->
+ NotInd (None,typ))
+ (* error will be detected in check_all_variables *)
+ | None ->
+ try IsInd (typ,find_rectype env (evars_of isevars) typ)
+ with Not_found -> NotInd (None,typ)
+
+let coerce_row typing_fun isevars env cstropt tomatch =
+ let j = typing_fun empty_tycon env tomatch in
+ let typ = body_of_type j.uj_type in
+ let loc = loc_of_rawconstr tomatch in
+ let t = unify_tomatch_with_patterns isevars env (Some loc) typ cstropt in
+ (j.uj_val,t)
+
+let coerce_to_indtype typing_fun isevars env matx tomatchl =
+ let pats = List.map (fun r -> r.patterns) matx in
+ let matx' = match matrix_transpose pats with
+ | [] -> List.map (fun _ -> None) tomatchl (* no patterns at all *)
+ | m -> List.map find_row_ind m in
+ List.map2 (coerce_row typing_fun isevars env) matx' tomatchl
+
+(************************************************************************)
+(* Utils *)
+
+ (* extract some ind from [t], possibly coercing from constructors in [tm] *)
+let to_mutind env isevars tm c t =
+ match c with
+ | Some body -> NotInd (c,t)
+ | None -> unify_tomatch_with_patterns isevars env None t (find_row_ind tm)
+
+let type_of_tomatch = function
+ | IsInd (t,_) -> t
+ | NotInd (_,t) -> t
+
+let mkDeclTomatch na = function
+ | IsInd (t,_) -> (na,None,t)
+ | NotInd (c,t) -> (na,c,t)
+
+let map_tomatch_type f = function
+ | IsInd (t,ind) -> IsInd (f t,map_inductive_type f ind)
+ | NotInd (c,t) -> NotInd (option_app f c, f t)
+
+let liftn_tomatch_type n depth = map_tomatch_type (liftn n depth)
+let lift_tomatch_type n = liftn_tomatch_type n 1
+
+let lift_tomatch n ((current,typ),info) =
+ ((lift n current,lift_tomatch_type n typ),info)
+
+(**********************************************************************)
+(* Utilities on patterns *)
+
+let current_pattern eqn =
+ match eqn.patterns with
+ | pat::_ -> pat
+ | [] -> anomaly "Empty list of patterns"
+
+let alias_of_pat = function
+ | PatVar (_,name) -> name
+ | PatCstr(_,_,_,name) -> name
+
+let unalias_pat = function
+ | PatVar (c,name) as p ->
+ if name = Anonymous then p else PatVar (c,Anonymous)
+ | PatCstr(a,b,c,name) as p ->
+ if name = Anonymous then p else PatCstr (a,b,c,Anonymous)
+
+let remove_current_pattern eqn =
+ match eqn.patterns with
+ | pat::pats ->
+ { eqn with
+ patterns = pats;
+ alias_stack = alias_of_pat pat :: eqn.alias_stack }
+ | [] -> anomaly "Empty list of patterns"
+
+let prepend_pattern tms eqn = {eqn with patterns = tms@eqn.patterns }
+
+(**********************************************************************)
+(* Dealing with regular and default patterns *)
+let is_regular eqn = eqn.tag = RegularPat
+
+let lower_pattern_status = function
+ | RegularPat -> DefaultPat 0
+ | DefaultPat n -> DefaultPat (n+1)
+
+let pattern_status pats =
+ if array_exists ((=) RegularPat) pats then RegularPat
+ else
+ let min =
+ Array.fold_right
+ (fun pat n -> match pat with
+ | DefaultPat i when i<n -> i
+ | _ -> n)
+ pats 0 in
+ DefaultPat min
+
+(**********************************************************************)
+(* Well-formedness tests *)
+(* Partial check on patterns *)
+
+exception NotAdjustable
+
+let rec adjust_local_defs loc = function
+ | (pat :: pats, (_,None,_) :: decls) ->
+ pat :: adjust_local_defs loc (pats,decls)
+ | (pats, (_,Some _,_) :: decls) ->
+ PatVar (loc, Anonymous) :: adjust_local_defs loc (pats,decls)
+ | [], [] -> []
+ | _ -> raise NotAdjustable
+
+let check_and_adjust_constructor ind cstrs = function
+ | PatVar _ as pat -> pat
+ | PatCstr (loc,((_,i) as cstr),args,alias) as pat ->
+ (* Check it is constructor of the right type *)
+ let ind' = inductive_of_constructor cstr in
+ if ind' = ind then
+ (* Check the constructor has the right number of args *)
+ let ci = cstrs.(i-1) in
+ let nb_args_constr = ci.cs_nargs in
+ if List.length args = nb_args_constr then pat
+ else
+ try
+ let args' = adjust_local_defs loc (args, List.rev ci.cs_args)
+ in PatCstr (loc, cstr, args', alias)
+ with NotAdjustable ->
+ error_wrong_numarg_constructor_loc loc cstr nb_args_constr
+ else
+ (* Try to insert a coercion *)
+ try
+ Coercion.inh_pattern_coerce_to loc pat ind' ind
+ with Not_found ->
+ error_bad_constructor_loc loc cstr ind
+
+let check_all_variables typ mat =
+ List.iter
+ (fun eqn -> match current_pattern eqn with
+ | PatVar (_,id) -> ()
+ | PatCstr (loc,cstr_sp,_,_) ->
+ error_bad_pattern_loc loc cstr_sp typ)
+ mat
+
+let check_unused_pattern env eqn =
+ if not !(eqn.used) then
+ raise_pattern_matching_error
+ (eqn.eqn_loc, env, UnusedClause eqn.patterns)
+
+let set_used_pattern eqn = eqn.used := true
+
+let extract_rhs pb =
+ match pb.mat with
+ | [] -> errorlabstrm "build_leaf" (mssg_may_need_inversion())
+ | eqn::_ ->
+ set_used_pattern eqn;
+ eqn.tag, eqn.rhs
+
+(**********************************************************************)
+(* Functions to deal with matrix factorization *)
+
+let occur_in_rhs na rhs =
+ match na with
+ | Anonymous -> false
+ | Name id -> occur_rawconstr id rhs.it
+
+let is_dep_patt eqn = function
+ | PatVar (_,name) -> occur_in_rhs name eqn.rhs
+ | PatCstr _ -> true
+
+let dependencies_in_rhs nargs eqns =
+ if eqns = [] then list_tabulate (fun _ -> false) nargs (* Only "_" patts *)
+ else
+ let deps = List.map (fun (tms,eqn) -> List.map (is_dep_patt eqn) tms) eqns in
+ let columns = matrix_transpose deps in
+ List.map (List.exists ((=) true)) columns
+
+let dependent_decl a = function
+ | (na,None,t) -> dependent a t
+ | (na,Some c,t) -> dependent a t || dependent a c
+
+(* Computing the matrix of dependencies *)
+
+(* We are in context d1...dn |- and [find_dependencies k 1 nextlist]
+ computes for declaration [k+1] in which of declarations in
+ [nextlist] (which corresponds to d(k+2)...dn) it depends;
+ declarations are expressed by index, e.g. in dependency list
+ [n-2;1], [1] points to [dn] and [n-2] to [d3] *)
+
+let rec find_dependency_list k n = function
+ | [] -> []
+ | (used,tdeps,d)::rest ->
+ let deps = find_dependency_list k (n+1) rest in
+ if used && dependent_decl (mkRel n) d
+ then list_add_set (List.length rest + 1) (list_union deps tdeps)
+ else deps
+
+let find_dependencies is_dep_or_cstr_in_rhs d (k,nextlist) =
+ let deps = find_dependency_list k 1 nextlist in
+ if is_dep_or_cstr_in_rhs || deps <> []
+ then (k-1,(true ,deps,d)::nextlist)
+ else (k-1,(false,[] ,d)::nextlist)
+
+let find_dependencies_signature deps_in_rhs typs =
+ let k = List.length deps_in_rhs in
+ let _,l = List.fold_right2 find_dependencies deps_in_rhs typs (k,[]) in
+ List.map (fun (_,deps,_) -> deps) l
+
+(******)
+
+(* A Pushed term to match has just been substituted by some
+ constructor t = (ci x1...xn) and the terms x1 ... xn have been added to
+ match
+
+ - all terms to match and to push (dependent on t by definition)
+ must have (Rel depth) substituted by t and Rel's>depth lifted by n
+ - all pushed terms to match (non dependent on t by definition) must
+ be lifted by n
+
+ We start with depth=1
+*)
+
+let regeneralize_index_tomatch n =
+ let rec genrec depth = function
+ | [] -> []
+ | Pushed ((c,tm),l)::rest ->
+ let c = regeneralize_index n depth c in
+ let tm = map_tomatch_type (regeneralize_index n depth) tm in
+ let l = List.map (regeneralize_rel n depth) l in
+ Pushed ((c,tm),l)::(genrec depth rest)
+ | Alias (c1,c2,d,t)::rest ->
+ Alias (regeneralize_index n depth c1,c2,d,t)::(genrec depth rest)
+ | Abstract d::rest ->
+ Abstract (map_rel_declaration (regeneralize_index n depth) d)
+ ::(genrec (depth+1) rest) in
+ genrec 0
+
+let rec replace_term n c k t =
+ if t = mkRel (n+k) then lift k c
+ else map_constr_with_binders succ (replace_term n c) k t
+
+let replace_tomatch n c =
+ let rec replrec depth = function
+ | [] -> []
+ | Pushed ((b,tm),l)::rest ->
+ let b = replace_term n c depth b in
+ let tm = map_tomatch_type (replace_term n c depth) tm in
+ List.iter (fun i -> if i=n+depth then anomaly "replace_tomatch") l;
+ Pushed ((b,tm),l)::(replrec depth rest)
+ | Alias (c1,c2,d,t)::rest ->
+ Alias (replace_term n c depth c1,c2,d,t)::(replrec depth rest)
+ | Abstract d::rest ->
+ Abstract (map_rel_declaration (replace_term n c depth) d)
+ ::(replrec (depth+1) rest) in
+ replrec 0
+
+let liftn_rel_declaration n k = map_rel_declaration (liftn n k)
+let substnl_rel_declaration sigma k = map_rel_declaration (substnl sigma k)
+
+let rec liftn_tomatch_stack n depth = function
+ | [] -> []
+ | Pushed ((c,tm),l)::rest ->
+ let c = liftn n depth c in
+ let tm = liftn_tomatch_type n depth tm in
+ let l = List.map (fun i -> if i<depth then i else i+n) l in
+ Pushed ((c,tm),l)::(liftn_tomatch_stack n depth rest)
+ | Alias (c1,c2,d,t)::rest ->
+ Alias (liftn n depth c1,liftn n depth c2,d,liftn n depth t)
+ ::(liftn_tomatch_stack n depth rest)
+ | Abstract d::rest ->
+ Abstract (map_rel_declaration (liftn n depth) d)
+ ::(liftn_tomatch_stack n (depth+1) rest)
+
+
+let lift_tomatch_stack n = liftn_tomatch_stack n 1
+
+(* if [current] has type [I(p1...pn u1...um)] and we consider the case
+ of constructor [ci] of type [I(p1...pn u'1...u'm)], then the
+ default variable [name] is expected to have which type?
+ Rem: [current] is [(Rel i)] except perhaps for initial terms to match *)
+
+(************************************************************************)
+(* Some heuristics to get names for variables pushed in pb environment *)
+(* Typical requirement:
+
+ [Cases y of (S (S x)) => x | x => x end] should be compiled into
+ [Cases y of O => y | (S n) => Cases n of O => y | (S x) => x end end]
+
+ and [Cases y of (S (S n)) => n | n => n end] into
+ [Cases y of O => y | (S n0) => Cases n0 of O => y | (S n) => n end end]
+
+ i.e. user names should be preserved and created names should not
+ interfere with user names *)
+
+let merge_name get_name obj = function
+ | Anonymous -> get_name obj
+ | na -> na
+
+let merge_names get_name = List.map2 (merge_name get_name)
+
+let get_names env sign eqns =
+ let names1 = list_tabulate (fun _ -> Anonymous) (List.length sign) in
+ (* If any, we prefer names used in pats, from top to bottom *)
+ let names2 =
+ List.fold_right
+ (fun (pats,eqn) names -> merge_names alias_of_pat pats names)
+ eqns names1 in
+ (* Otherwise, we take names from the parameters of the constructor but
+ avoiding conflicts with user ids *)
+ let allvars =
+ List.fold_left (fun l (_,eqn) -> list_union l eqn.rhs.other_ids) [] eqns in
+ let names4,_ =
+ List.fold_left2
+ (fun (l,avoid) d na ->
+ let na =
+ merge_name
+ (fun (na,_,t) -> Name (next_name_away (named_hd env t na) avoid))
+ d na
+ in
+ (na::l,(out_name na)::avoid))
+ ([],allvars) (List.rev sign) names2 in
+ names4
+
+(************************************************************************)
+(* Recovering names for variables pushed to the rhs' environment *)
+
+let recover_alias_names get_name = List.map2 (fun x (_,c,t) ->(get_name x,c,t))
+
+let push_rels_eqn sign eqn =
+ {eqn with rhs = {eqn.rhs with rhs_env = push_rels sign eqn.rhs.rhs_env} }
+
+let push_rels_eqn_with_names sign eqn =
+ let pats = List.rev (list_firstn (List.length sign) eqn.patterns) in
+ let sign = recover_alias_names alias_of_pat pats sign in
+ push_rels_eqn sign eqn
+
+let build_aliases_context env sigma names allpats pats =
+ (* pats is the list of bodies to push as an alias *)
+ (* They all are defined in env and we turn them into a sign *)
+ (* cuts in sign need to be done in allpats *)
+ let rec insert env sign1 sign2 n newallpats oldallpats = function
+ | (deppat,_,_,_)::pats, Anonymous::names when not (isRel deppat) ->
+ (* Anonymous leaves must be considered named and treated in the *)
+ (* next clause because they may occur in implicit arguments *)
+ insert env sign1 sign2
+ n newallpats (List.map List.tl oldallpats) (pats,names)
+ | (deppat,nondeppat,d,t)::pats, na::names ->
+ let nondeppat = lift n nondeppat in
+ let deppat = lift n deppat in
+ let newallpats =
+ List.map2 (fun l1 l2 -> List.hd l2::l1) newallpats oldallpats in
+ let oldallpats = List.map List.tl oldallpats in
+ let u = Retyping.get_type_of env sigma deppat in
+ let decl = (na,Some deppat,t) in
+ let a = (deppat,nondeppat,d,t) in
+ insert (push_rel decl env) (decl::sign1) ((na,a)::sign2) (n+1)
+ newallpats oldallpats (pats,names)
+ | [], [] -> newallpats, sign1, sign2, env
+ | _ -> anomaly "Inconsistent alias and name lists" in
+ let allpats = List.map (fun x -> [x]) allpats
+ in insert env [] [] 0 (List.map (fun _ -> []) allpats) allpats (pats, names)
+
+let insert_aliases_eqn sign eqnnames alias_rest eqn =
+ let thissign = List.map2 (fun na (_,c,t) -> (na,c,t)) eqnnames sign in
+ { eqn with
+ alias_stack = alias_rest;
+ rhs = {eqn.rhs with rhs_env = push_rels thissign eqn.rhs.rhs_env } }
+
+let insert_aliases env sigma alias eqns =
+ (* Là, y a une faiblesse, si un alias est utilisé dans un cas par *)
+ (* défaut présent mais inutile, ce qui est le cas général, l'alias *)
+ (* est introduit même s'il n'est pas utilisé dans les cas réguliers *)
+ let eqnsnames = List.map (fun eqn -> List.hd eqn.alias_stack) eqns in
+ let alias_rests = List.map (fun eqn -> List.tl eqn.alias_stack) eqns in
+ (* names2 takes the meet of all needed aliases *)
+ let names2 =
+ List.fold_right (merge_name (fun x -> x)) eqnsnames Anonymous in
+ (* Only needed aliases are kept by build_aliases_context *)
+ let eqnsnames, sign1, sign2, env =
+ build_aliases_context env sigma [names2] eqnsnames [alias] in
+ let eqns = list_map3 (insert_aliases_eqn sign1) eqnsnames alias_rests eqns in
+ sign2, env, eqns
+
+(**********************************************************************)
+(* Functions to deal with elimination predicate *)
+
+exception Occur
+let noccur_between_without_evar n m term =
+ let rec occur_rec n c = match kind_of_term c with
+ | Rel p -> if n<=p && p<n+m then raise Occur
+ | Evar (_,cl) -> ()
+ | _ -> iter_constr_with_binders succ occur_rec n c
+ in
+ try occur_rec n term; true with Occur -> false
+
+(* Infering the predicate *)
+let prepare_unif_pb typ cs =
+ let n = List.length (assums_of_rel_context cs.cs_args) in
+
+ (* We may need to invert ci if its parameters occur in typ *)
+ let typ' =
+ if noccur_between_without_evar 1 n typ then lift (-n) typ
+ else (* TODO4-1 *)
+ error "Inference of annotation not yet implemented in this case" in
+ let args = extended_rel_list (-n) cs.cs_args in
+ let ci = applist (mkConstruct cs.cs_cstr, cs.cs_params@args) in
+
+ (* This is the problem: finding P s.t. cs_args |- (P realargs ci) = typ' *)
+ (Array.map (lift (-n)) cs.cs_concl_realargs, ci, typ')
+
+
+(* Infering the predicate *)
+(*
+The problem to solve is the following:
+
+We match Gamma |- t : I(u01..u0q) against the following constructors:
+
+ Gamma, x11...x1p1 |- C1(x11..x1p1) : I(u11..u1q)
+ ...
+ Gamma, xn1...xnpn |- Cn(xn1..xnp1) : I(un1..unq)
+
+Assume the types in the branches are the following
+
+ Gamma, x11...x1p1 |- branch1 : T1
+ ...
+ Gamma, xn1...xnpn |- branchn : Tn
+
+Assume the type of the global case expression is Gamma |- T
+
+The predicate has the form phi = [y1..yq][z:I(y1..yq)]? and must satisfy
+the following n+1 equations:
+
+ Gamma, x11...x1p1 |- (phi u11..u1q (C1 x11..x1p1)) = T1
+ ...
+ Gamma, xn1...xnpn |- (phi un1..unq (Cn xn1..xnpn)) = Tn
+ Gamma |- (phi u01..u0q t) = T
+
+Some hints:
+
+- Clearly, if xij occurs in Ti, then, a "Cases z of (Ci xi1..xipi) => ..."
+ should be inserted somewhere in Ti.
+
+- If T is undefined, an easy solution is to insert a "Cases z of (Ci
+ xi1..xipi) => ..." in front of each Ti
+
+- Otherwise, T1..Tn and T must be step by step unified, if some of them
+ diverge, then try to replace the diverging subterm by one of y1..yq or z.
+
+- The main problem is what to do when an existential variables is encountered
+
+let prepare_unif_pb typ cs =
+ let n = cs.cs_nargs in
+ let _,p = decompose_prod_n n typ in
+ let ci = build_dependent_constructor cs in
+ (* This is the problem: finding P s.t. cs_args |- (P realargs ci) = p *)
+ (n, cs.cs_concl_realargs, ci, p)
+
+let eq_operator_lift k (n,n') = function
+ | OpRel p, OpRel p' when p > k & p' > k ->
+ if p < k+n or p' < k+n' then false else p - n = p' - n'
+ | op, op' -> op = op'
+
+let rec transpose_args n =
+ if n=0 then []
+ else
+ (Array.map (fun l -> List.hd l) lv)::
+ (transpose_args (m-1) (Array.init (fun l -> List.tl l)))
+
+let shift_operator k = function OpLambda _ | OpProd _ -> k+1 | _ -> k
+
+let reloc_operator (k,n) = function OpRel p when p > k ->
+let rec unify_clauses k pv =
+ let pv'= Array.map (fun (n,sign,_,p) -> n,splay_constr (whd_betaiotaevar (push_rels (List.rev sign) env) (evars_of isevars)) p) pv in
+ let n1,op1 = let (n1,(op1,args1)) = pv'.(0) in n1,op1 in
+ if Array.for_all (fun (ni,(opi,_)) -> eq_operator_lift k (n1,ni) (op1,opi)) pv'
+ then
+ let argvl = transpose_args (List.length args1) pv' in
+ let k' = shift_operator k op1 in
+ let argl = List.map (unify_clauses k') argvl in
+ gather_constr (reloc_operator (k,n1) op1) argl
+*)
+
+let abstract_conclusion typ cs =
+ let n = List.length (assums_of_rel_context cs.cs_args) in
+ let (sign,p) = decompose_prod_n n typ in
+ lam_it p sign
+
+let infer_predicate loc env isevars typs cstrs indf =
+ let (mis,_) = dest_ind_family indf in
+ (* Il faudra substituer les isevars a un certain moment *)
+ if Array.length cstrs = 0 then (* "TODO4-3" *)
+ error "Inference of annotation for empty inductive types not implemented"
+ else
+ (* Empiric normalization: p may depend in a irrelevant way on args of the*)
+ (* cstr as in [c:{_:Alpha & Beta}] Cases c of (existS a b)=>(a,b) end *)
+ let typs =
+ Array.map (local_strong (whd_betaevar empty_env (evars_of isevars))) typs
+ in
+ let eqns = array_map2 prepare_unif_pb typs cstrs in
+ (* First strategy: no dependencies at all *)
+(* let (cclargs,_,typn) = eqns.(mis_nconstr mis -1) in*)
+ let (sign,_) = get_arity env indf in
+ let mtyp =
+ if array_exists is_Type typs then
+ (* Heuristic to avoid comparison between non-variables algebric univs*)
+ new_Type ()
+ else
+ mkExistential isevars env (loc, CasesType)
+ in
+ if array_for_all (fun (_,_,typ) -> the_conv_x_leq env isevars typ mtyp) eqns
+ then
+ (* Non dependent case -> turn it into a (dummy) dependent one *)
+ let sign = (Anonymous,None,build_dependent_inductive env indf)::sign in
+ let pred = it_mkLambda_or_LetIn (lift (List.length sign) mtyp) sign in
+ (true,pred) (* true = dependent -- par défaut *)
+ else
+(*
+ let s = get_sort_of env (evars_of isevars) typs.(0) in
+ let predpred = it_mkLambda_or_LetIn (mkSort s) sign in
+ let caseinfo = make_default_case_info mis in
+ let brs = array_map2 abstract_conclusion typs cstrs in
+ let predbody = mkCase (caseinfo, (nf_betaiota predpred), mkRel 1, brs) in
+ let pred = it_mkLambda_or_LetIn (lift (List.length sign) mtyp) sign in
+*)
+ (* "TODO4-2" *)
+ (* We skip parameters *)
+ let cis =
+ Array.map
+ (fun cs ->
+ applist (mkConstruct cs.cs_cstr, extended_rel_list 0 cs.cs_args))
+ cstrs in
+ let ct = array_map2 (fun ci (_,_,t) -> (ci,t)) cis eqns in
+ raise_pattern_matching_error (loc,env, CannotInferPredicate ct)
+(*
+ (true,pred)
+*)
+
+(* Propagation of user-provided predicate through compilation steps *)
+
+let rec map_predicate f k = function
+ | PrCcl ccl -> PrCcl (f k ccl)
+ | PrProd pred ->
+ PrProd (map_predicate f (k+1) pred)
+ | PrLetIn ((nargs,dep as tm),pred) ->
+ let k' = nargs + (if dep then 1 else 0) in
+ PrLetIn (tm, map_predicate f (k+k') pred)
+
+let liftn_predicate n = map_predicate (liftn n)
+
+let lift_predicate n = liftn_predicate n 1
+
+let regeneralize_index_predicate n = map_predicate (regeneralize_index n) 0
+
+let substnl_predicate sigma = map_predicate (substnl sigma)
+
+(* This is parallel bindings *)
+let subst_predicate (args,copt) pred =
+ let sigma = match copt with
+ | None -> List.rev args
+ | Some c -> c::(List.rev args) in
+ substnl_predicate sigma 0 pred
+
+let specialize_predicate_var (cur,typ) = function
+ | PrProd _ | PrCcl _ ->
+ anomaly "specialize_predicate_var: a pattern-variable must be pushed"
+ | PrLetIn ((0,dep),pred) ->
+ subst_predicate ([],if dep then Some cur else None) pred
+ | PrLetIn ((_,dep),pred) ->
+ (match typ with
+ | IsInd (_,IndType (_,realargs)) ->
+ subst_predicate (realargs,if dep then Some cur else None) pred
+ | _ -> anomaly "specialize_predicate_var")
+
+let ungeneralize_predicate = function
+ | PrLetIn _ | PrCcl _ -> anomaly "ungeneralize_predicate: expects a product"
+ | PrProd pred -> pred
+
+(*****************************************************************************)
+(* We have pred = [X:=realargs;x:=c]P typed in Gamma1, x:I(realargs), Gamma2 *)
+(* and we want to abstract P over y:t(x) typed in the same context to get *)
+(* *)
+(* pred' = [X:=realargs;x':=c](y':t(x'))P[y:=y'] *)
+(* *)
+(* We first need to lift t(x) s.t. it is typed in Gamma, X:=rargs, x' *)
+(* then we have to replace x by x' in t(x) and y by y' in P *)
+(*****************************************************************************)
+let generalize_predicate c ny d = function
+ | PrLetIn ((nargs,dep as tm),pred) ->
+ if not dep then anomaly "Undetected dependency";
+ let p = nargs + 1 in
+ let pred = lift_predicate 1 pred in
+ let pred = regeneralize_index_predicate (ny+p+1) pred in
+ PrLetIn (tm, PrProd pred)
+ | PrProd _ | PrCcl _ ->
+ anomaly "generalize_predicate: expects a non trivial pattern"
+
+let rec extract_predicate l = function
+ | pred, Alias (deppat,nondeppat,_,_)::tms ->
+ let tms' = match kind_of_term nondeppat with
+ | Rel i -> replace_tomatch i deppat tms
+ | _ -> (* initial terms are not dependent *) tms in
+ extract_predicate l (pred,tms')
+ | PrProd pred, Abstract d'::tms ->
+ let d' = map_rel_declaration (lift (List.length l)) d' in
+ substl l (mkProd_or_LetIn d' (extract_predicate [] (pred,tms)))
+ | PrLetIn ((0,dep),pred), Pushed ((cur,_),_)::tms ->
+ extract_predicate (if dep then cur::l else l) (pred,tms)
+ | PrLetIn ((_,dep),pred), Pushed ((cur,IsInd (_,(IndType(_,realargs)))),_)::tms ->
+ let l = List.rev realargs@l in
+ extract_predicate (if dep then cur::l else l) (pred,tms)
+ | PrCcl ccl, [] ->
+ substl l ccl
+ | _ -> anomaly"extract_predicate: predicate inconsistent with terms to match"
+
+let abstract_predicate env sigma indf cur tms = function
+ | (PrProd _ | PrCcl _) -> anomaly "abstract_predicate: must be some LetIn"
+ | PrLetIn ((nrealargs,dep),pred) ->
+ let sign = make_arity_signature env true indf in
+ (* n is the number of real args + 1 *)
+ let n = List.length sign in
+ let tms = lift_tomatch_stack n tms in
+ let tms =
+ match kind_of_term cur with
+ | Rel i -> regeneralize_index_tomatch (i+n) tms
+ | _ -> (* Initial case *) tms in
+ (* Depending on whether the predicate is dependent or not, and has real
+ args or not, we lift it to make room for [sign] *)
+ (* Even if not intrinsically dep, we move the predicate into a dep one *)
+ let k =
+ if nrealargs = 0 & n <> 1 then
+ (* Real args were not considered *) if dep then n-1 else n
+ else
+ (* Real args are OK *) if dep then 0 else 1 in
+ let pred = lift_predicate k pred in
+ let pred = extract_predicate [] (pred,tms) in
+ (true, it_mkLambda_or_LetIn_name env pred sign)
+
+let rec known_dependent = function
+ | None -> false
+ | Some (PrLetIn ((_,dep),_)) -> dep
+ | Some (PrCcl _) -> false
+ | Some (PrProd _) ->
+ anomaly "known_dependent: can only be used when patterns remain"
+
+(* [expand_arg] is used by [specialize_predicate]
+ it replaces gamma, x1...xn, x1...xk |- pred
+ by gamma, x1...xn, x1...xk-1 |- [X=realargs,xk=xk]pred (if dep) or
+ by gamma, x1...xn, x1...xk-1 |- [X=realargs]pred (if not dep) *)
+
+let expand_arg n alreadydep (na,t) deps (k,pred) =
+ (* current can occur in pred even if the original problem is not dependent *)
+ let dep = deps <> [] || alreadydep in
+ let pred = if dep then pred else lift_predicate (-1) pred in
+ (* There is no dependency in realargs for subpattern *)
+ (k-1, PrLetIn ((0,dep), pred))
+
+
+(*****************************************************************************)
+(* pred = [X:=realargs;x:=c]P types the following problem: *)
+(* *)
+(* Gamma |- Cases Pushed(c:I(realargs)) rest of...end: pred *)
+(* *)
+(* where the branch with constructor Ci:(x1:T1)...(xn:Tn)->I(realargsi) *)
+(* is considered. Assume each Ti is some Ii(argsi). *)
+(* We let e=Ci(x1,...,xn) and replace pred by *)
+(* *)
+(* pred' = [X1:=rargs1,x1:=x1']...[Xn:=rargsn,xn:=xn'](P[X:=realargsi;x:=e]) *)
+(* *)
+(* s.t Gamma,x1'..xn' |- Cases Pushed(x1')..Pushed(xn') rest of...end: pred' *)
+(* *)
+(*****************************************************************************)
+let specialize_predicate tomatchs deps cs = function
+ | (PrProd _ | PrCcl _) ->
+ anomaly "specialize_predicate: a matched pattern must be pushed"
+ | PrLetIn ((nrealargs,isdep),pred) ->
+ (* Assume some gamma st: gamma, (X,x:=realargs,copt) |- pred *)
+ let k = nrealargs + (if isdep then 1 else 0) in
+ (* We adjust pred st: gamma, x1..xn, (X,x:=realargs,copt) |- pred' *)
+ let n = cs.cs_nargs in
+ let pred' = liftn_predicate n (k+1) pred in
+ let argsi = if nrealargs <> 0 then Array.to_list cs.cs_concl_realargs else [] in
+ let copti = if isdep then Some (build_dependent_constructor cs) else None in
+ (* The substituends argsi, copti are all defined in gamma, x1...xn *)
+ (* We need _parallel_ bindings to get gamma, x1...xn |- pred'' *)
+ let pred'' = subst_predicate (argsi, copti) pred' in
+ (* We adjust pred st: gamma, x1..xn, x1..xn |- pred'' *)
+ let pred''' = liftn_predicate n (n+1) pred'' in
+ (* We finally get gamma,x1..xn |- [X1,x1:=R1,x1]..[Xn,xn:=Rn,xn]pred'''*)
+ snd (List.fold_right2 (expand_arg n isdep) tomatchs deps (n,pred'''))
+
+let find_predicate loc env isevars p typs cstrs current
+ (IndType (indf,realargs)) tms =
+ let (dep,pred) =
+ match p with
+ | Some p -> abstract_predicate env (evars_of isevars) indf current tms p
+ | None -> infer_predicate loc env isevars typs cstrs indf in
+ let typ = whd_beta (applist (pred, realargs)) in
+ if dep then
+ (pred, whd_beta (applist (typ, [current])), new_Type ())
+ else
+ (pred, typ, new_Type ())
+
+(************************************************************************)
+(* Sorting equations by constructor *)
+
+type inversion_problem =
+ (* the discriminating arg in some Ind and its order in Ind *)
+ | Incompatible of int * (int * int)
+ | Constraints of (int * constr) list
+
+let solve_constraints constr_info indt =
+ (* TODO *)
+ Constraints []
+
+let rec irrefutable env = function
+ | PatVar (_,name) -> true
+ | PatCstr (_,cstr,args,_) ->
+ let ind = inductive_of_constructor cstr in
+ let (_,mip) = Inductive.lookup_mind_specif env ind in
+ let one_constr = Array.length mip.mind_user_lc = 1 in
+ one_constr & List.for_all (irrefutable env) args
+
+let first_clause_irrefutable env = function
+ | eqn::mat -> List.for_all (irrefutable env) eqn.patterns
+ | _ -> false
+
+let group_equations pb mind current cstrs mat =
+ let mat =
+ if first_clause_irrefutable pb.env mat then [List.hd mat] else mat in
+ let brs = Array.create (Array.length cstrs) [] in
+ let only_default = ref true in
+ let _ =
+ List.fold_right (* To be sure it's from bottom to top *)
+ (fun eqn () ->
+ let rest = remove_current_pattern eqn in
+ let pat = current_pattern eqn in
+ match check_and_adjust_constructor mind cstrs pat with
+ | PatVar (_,name) ->
+ (* This is a default clause that we expand *)
+ for i=1 to Array.length cstrs do
+ let args = make_anonymous_patvars cstrs.(i-1).cs_nargs in
+ let rest = {rest with tag = lower_pattern_status rest.tag} in
+ brs.(i-1) <- (args, rest) :: brs.(i-1)
+ done
+ | PatCstr (loc,((_,i) as cstr),args,_) as pat ->
+ (* This is a regular clause *)
+ only_default := false;
+ brs.(i-1) <- (args,rest) :: brs.(i-1)) mat () in
+ (brs,!only_default)
+
+(************************************************************************)
+(* Here starts the pattern-matching compilation algorithm *)
+
+(* Abstracting over dependent subterms to match *)
+let rec generalize_problem pb current = function
+ | [] -> pb
+ | i::l ->
+ let d = map_rel_declaration (lift i) (Environ.lookup_rel i pb.env) in
+ let pb' = generalize_problem pb current l in
+ let tomatch = lift_tomatch_stack 1 pb'.tomatch in
+ let tomatch = regeneralize_index_tomatch (i+1) tomatch in
+ { pb with
+ tomatch = Abstract d :: tomatch;
+ pred = option_app (generalize_predicate current i d) pb'.pred }
+
+(* No more patterns: typing the right-hand-side of equations *)
+let build_leaf pb =
+ let tag, rhs = extract_rhs pb in
+ let tycon = match pb.pred with
+ | None -> empty_tycon
+ | Some (PrCcl typ) -> mk_tycon typ
+ | Some _ -> anomaly "not all parameters of pred have been consumed" in
+ tag, pb.typing_function tycon rhs.rhs_env rhs.it
+
+(* Building the sub-problem when all patterns are variables *)
+let shift_problem (current,t) pb =
+ {pb with
+ tomatch = Alias (current,current,NonDepAlias,type_of_tomatch t)::pb.tomatch;
+ pred = option_app (specialize_predicate_var (current,t)) pb.pred;
+ history = push_history_pattern 0 AliasLeaf pb.history;
+ mat = List.map remove_current_pattern pb.mat }
+
+(* Building the sub-pattern-matching problem for a given branch *)
+let build_branch current deps pb eqns const_info =
+ (* We remember that we descend through a constructor *)
+ let alias_type =
+ if Array.length const_info.cs_concl_realargs = 0
+ & not (known_dependent pb.pred) & deps = []
+ then
+ NonDepAlias
+ else
+ DepAlias
+ in
+ let partialci =
+ applist (mkConstruct const_info.cs_cstr, const_info.cs_params) in
+ let history =
+ push_history_pattern const_info.cs_nargs
+ (AliasConstructor const_info.cs_cstr)
+ pb.history in
+
+ (* We find matching clauses *)
+ let cs_args = (*assums_of_rel_context*) const_info.cs_args in
+ let names = get_names pb.env cs_args eqns in
+ let submat = List.map (fun (tms,eqn) -> prepend_pattern tms eqn) eqns in
+ if submat = [] then
+ raise_pattern_matching_error
+ (dummy_loc, pb.env, NonExhaustive (complete_history history));
+ let typs = List.map2 (fun (_,c,t) na -> (na,c,t)) cs_args names in
+ let _,typs',_ =
+ List.fold_right
+ (fun (na,c,t as d) (env,typs,tms) ->
+ let tm1 = List.map List.hd tms in
+ let tms = List.map List.tl tms in
+ (push_rel d env, (na,to_mutind env pb.isevars tm1 c t)::typs,tms))
+ typs (pb.env,[],List.map fst eqns) in
+
+ let dep_sign =
+ find_dependencies_signature
+ (dependencies_in_rhs const_info.cs_nargs eqns) (List.rev typs) in
+
+ (* The dependent term to subst in the types of the remaining UnPushed
+ terms is relative to the current context enriched by topushs *)
+ let ci = build_dependent_constructor const_info in
+
+ (* We replace [(mkRel 1)] by its expansion [ci] *)
+ (* and context "Gamma = Gamma1, current, Gamma2" by "Gamma;typs;curalias" *)
+ (* This is done in two steps : first from "Gamma |- tms" *)
+ (* into "Gamma; typs; curalias |- tms" *)
+ let tomatch = lift_tomatch_stack const_info.cs_nargs pb.tomatch in
+
+ let currents =
+ list_map2_i
+ (fun i (na,t) deps -> Pushed ((mkRel i, lift_tomatch_type i t), deps))
+ 1 typs' (List.rev dep_sign) in
+
+ let sign = List.map (fun (na,t) -> mkDeclTomatch na t) typs' in
+
+ let ind =
+ appvect (
+ applist (mkInd (inductive_of_constructor const_info.cs_cstr),
+ List.map (lift const_info.cs_nargs) const_info.cs_params),
+ const_info.cs_concl_realargs) in
+
+ let cur_alias = lift (List.length sign) current in
+ let currents = Alias (ci,cur_alias,alias_type,ind) :: currents in
+
+ sign,
+ { pb with
+ env = push_rels sign pb.env;
+ tomatch = List.rev_append currents tomatch;
+ pred = option_app (specialize_predicate (List.rev typs') dep_sign const_info) pb.pred;
+ history = history;
+ mat = List.map (push_rels_eqn_with_names sign) submat }
+
+(**********************************************************************
+ INVARIANT:
+
+ pb = { env, subst, tomatch, mat, ...}
+ tomatch = list of Pushed (c:T) or Abstract (na:T) or Alias (c:T)
+
+ "Pushed" terms and types are relative to env
+ "Abstract" types are relative to env enriched by the previous terms to match
+
+ Concretely, each term "c" or type "T" comes with a delayed lift
+ index, but it works as if the lifting were effective.
+
+*)
+
+(**********************************************************************)
+(* Main compiling descent *)
+let rec compile pb =
+ match pb.tomatch with
+ | (Pushed cur)::rest -> match_current { pb with tomatch = rest } cur
+ | (Alias x)::rest -> compile_alias pb x rest
+ | (Abstract d)::rest -> compile_generalization pb d rest
+ | [] -> build_leaf pb
+
+and match_current pb ((current,typ as ct),deps) =
+ let tm1 = List.map (fun eqn -> List.hd eqn.patterns) pb.mat in
+ let (_,c,t) = mkDeclTomatch Anonymous typ in
+ let typ = to_mutind pb.env pb.isevars tm1 c t in
+ match typ with
+ | NotInd (_,typ) ->
+ check_all_variables typ pb.mat;
+ compile (shift_problem ct pb)
+ | IsInd (_,(IndType(indf,realargs) as indt)) ->
+ let mind,_ = dest_ind_family indf in
+ let cstrs = get_constructors pb.env indf in
+ let eqns,onlydflt = group_equations pb mind current cstrs pb.mat in
+ if (cstrs <> [||] or not (initial_history pb.history)) & onlydflt then
+ compile (shift_problem ct pb)
+ else
+ let constraints = Array.map (solve_constraints indt) cstrs in
+
+ (* We generalize over terms depending on current term to match *)
+ let pb = generalize_problem pb current deps in
+
+ (* We compile branches *)
+ let brs = array_map2 (compile_branch current deps pb) eqns cstrs in
+
+ (* We build the (elementary) case analysis *)
+ let tags = Array.map (fun (t,_,_) -> t) brs in
+ let brvals = Array.map (fun (_,v,_) -> v) brs in
+ let brtyps = Array.map (fun (_,_,t) -> t) brs in
+ let (pred,typ,s) =
+ find_predicate pb.caseloc pb.env pb.isevars
+ pb.pred brtyps cstrs current indt pb.tomatch in
+ let ci = make_case_info pb.env mind RegularStyle tags in
+ let case = mkCase (ci,nf_betaiota pred,current,brvals) in
+ let inst = List.map mkRel deps in
+ pattern_status tags,
+ { uj_val = applist (case, inst);
+ uj_type = substl inst typ }
+
+and compile_branch current deps pb eqn cstr =
+ let sign, pb = build_branch current deps pb eqn cstr in
+ let tag, j = compile pb in
+ (tag, it_mkLambda_or_LetIn j.uj_val sign, j.uj_type)
+
+and compile_generalization pb d rest =
+ let pb =
+ { pb with
+ env = push_rel d pb.env;
+ tomatch = rest;
+ pred = option_app ungeneralize_predicate pb.pred;
+ mat = List.map (push_rels_eqn [d]) pb.mat } in
+ let patstat,j = compile pb in
+ patstat,
+ { uj_val = mkLambda_or_LetIn d j.uj_val;
+ uj_type = mkProd_or_LetIn d j.uj_type }
+
+and compile_alias pb (deppat,nondeppat,d,t) rest =
+ let history = simplify_history pb.history in
+ let sign, newenv, mat =
+ insert_aliases pb.env (evars_of pb.isevars) (deppat,nondeppat,d,t) pb.mat in
+ let n = List.length sign in
+
+ (* We had Gamma1; x:current; Gamma2 |- tomatch(x) and we rebind x to get *)
+ (* Gamma1; x:current; Gamma2; typs; x':=curalias |- tomatch(x') *)
+ let tomatch = lift_tomatch_stack n rest in
+ let tomatch = match kind_of_term nondeppat with
+ | Rel i ->
+ if n = 1 then regeneralize_index_tomatch (i+n) tomatch
+ else replace_tomatch i deppat tomatch
+ | _ -> (* initial terms are not dependent *) tomatch in
+
+ let pb =
+ {pb with
+ env = newenv;
+ tomatch = tomatch;
+ pred = option_app (lift_predicate n) pb.pred;
+ history = history;
+ mat = mat } in
+ let patstat,j = compile pb in
+ patstat,
+ List.fold_left mkSpecialLetInJudge j sign
+
+(* pour les alias des initiaux, enrichir les env de ce qu'il faut et
+substituer après par les initiaux *)
+
+(**************************************************************************)
+(* Preparation of the pattern-matching problem *)
+
+(* Qu'est-ce qui faut pas faire pour traiter les alias ... *)
+
+(* On ne veut pas ajouter de primitive à Environ et le problème, c'est
+ donc de faire un renommage en se contraignant à parcourir l'env
+ dans le sens croissant. Ici, subst renomme des variables repérées
+ par leur numéro et seen_ids collecte celles dont on sait que les
+ variables de subst annule le scope *)
+let rename_env subst env =
+ let n = ref (rel_context_length (rel_context env)) in
+ let seen_ids = ref [] in
+ process_rel_context
+ (fun (na,c,t as d) env ->
+ let d =
+ try
+ let id = List.assoc !n subst in
+ seen_ids := id :: !seen_ids;
+ (Name id,c,t)
+ with Not_found ->
+ match na with
+ | Name id when List.mem id !seen_ids -> (Anonymous,c,t)
+ | _ -> d in
+ decr n;
+ push_rel d env) env
+
+let is_dependent_indtype = function
+ | NotInd _ -> false
+ | IsInd (_, IndType(_,realargs)) -> List.length realargs <> 0
+
+let prepare_initial_alias_eqn isdep tomatchl eqn =
+ let (subst, pats) =
+ List.fold_right2
+ (fun pat (tm,tmtyp) (subst, stripped_pats) ->
+ match alias_of_pat pat with
+ | Anonymous -> (subst, pat::stripped_pats)
+ | Name idpat as na ->
+ match kind_of_term tm with
+ | Rel n when not (is_dependent_indtype tmtyp) & not isdep
+ -> (n, idpat)::subst, (unalias_pat pat::stripped_pats)
+ | _ -> (subst, pat::stripped_pats))
+ eqn.patterns tomatchl ([], []) in
+ let env = rename_env subst eqn.rhs.rhs_env in
+ { eqn with patterns = pats; rhs = { eqn.rhs with rhs_env = env } }
+
+let prepare_initial_aliases isdep tomatchl mat = mat
+(* List.map (prepare_initial_alias_eqn isdep tomatchl) mat*)
+
+(*
+let prepare_initial_alias lpat tomatchl rhs =
+ List.fold_right2
+ (fun pat tm (stripped_pats, rhs) ->
+ match alias_of_pat pat with
+ | Anonymous -> (pat::stripped_pats, rhs)
+ | Name _ as na ->
+ match tm with
+ | RVar _ ->
+ (unalias_pat pat::stripped_pats,
+ RLetIn (dummy_loc, na, tm, rhs))
+ | _ -> (pat::stripped_pats, rhs))
+ lpat tomatchl ([], rhs)
+*)
+(* builds the matrix of equations testing that each eqn has n patterns
+ * and linearizing the _ patterns.
+ * Syntactic correctness has already been done in astterm *)
+let matx_of_eqns env tomatchl eqns =
+ let build_eqn (loc,ids,lpat,rhs) =
+(* let initial_lpat,initial_rhs = prepare_initial_alias lpat tomatchl rhs in*)
+ let initial_lpat,initial_rhs = lpat,rhs in
+ let initial_rhs = rhs in
+ let rhs =
+ { rhs_env = env;
+ other_ids = ids@(ids_of_named_context (named_context env));
+ user_ids = ids;
+ rhs_lift = 0;
+ it = initial_rhs } in
+ { dependencies = [];
+ patterns = initial_lpat;
+ tag = RegularPat;
+ alias_stack = [];
+ eqn_loc = loc;
+ used = ref false;
+ rhs = rhs }
+ in List.map build_eqn eqns
+
+(************************************************************************)
+(* preparing the elimination predicate if any *)
+
+let build_expected_arity env isevars isdep tomatchl =
+ let cook n = function
+ | _,IsInd (_,IndType(indf,_)) ->
+ let indf' = lift_inductive_family n indf in
+ Some (build_dependent_inductive env indf', fst (get_arity env indf'))
+ | _,NotInd _ -> None
+ in
+ let rec buildrec n env = function
+ | [] -> new_Type ()
+ | tm::ltm ->
+ match cook n tm with
+ | None -> buildrec n env ltm
+ | Some (ty1,aritysign) ->
+ let rec follow n env = function
+ | d::sign ->
+ mkProd_or_LetIn_name env
+ (follow (n+1) (push_rel d env) sign) d
+ | [] ->
+ if isdep then
+ mkProd (Anonymous, ty1,
+ buildrec (n+1)
+ (push_rel_assum (Anonymous, ty1) env)
+ ltm)
+ else buildrec n env ltm
+ in follow n env (List.rev aritysign)
+ in buildrec 0 env tomatchl
+
+let extract_predicate_conclusion isdep tomatchl pred =
+ let cook = function
+ | _,IsInd (_,IndType(_,args)) -> Some (List.length args)
+ | _,NotInd _ -> None in
+ let decomp_lam_force p =
+ match kind_of_term p with
+ | Lambda (_,_,c) -> c
+ | _ -> (* eta-expansion *) applist (lift 1 p, [mkRel 1]) in
+ let rec buildrec p = function
+ | [] -> p
+ | tm::ltm ->
+ match cook tm with
+ | None ->
+ let p =
+ (* adjust to a sign containing the NotInd's *)
+ if isdep then lift 1 p else p in
+ buildrec p ltm
+ | Some n ->
+ let n = if isdep then n+1 else n in
+ let p = iterate decomp_lam_force n p in
+ buildrec p ltm
+ in buildrec pred tomatchl
+
+let set_arity_signature dep n arsign tomatchl pred x =
+ (* avoid is not exhaustive ! *)
+ let rec decomp_lam_force n avoid l p =
+ if n = 0 then (List.rev l,p,avoid) else
+ match p with
+ | RLambda (_,(Name id as na),_,c) ->
+ decomp_lam_force (n-1) (id::avoid) (na::l) c
+ | RLambda (_,(Anonymous as na),_,c) -> decomp_lam_force (n-1) avoid (na::l) c
+ | _ ->
+ let x = next_ident_away (id_of_string "x") avoid in
+ decomp_lam_force (n-1) (x::avoid) (Name x :: l)
+ (* eta-expansion *)
+ (let a = RVar (dummy_loc,x) in
+ match p with
+ | RApp (loc,p,l) -> RApp (loc,p,l@[a])
+ | _ -> (RApp (dummy_loc,p,[a]))) in
+ let rec decomp_block avoid p = function
+ | ([], _) -> x := Some p
+ | ((_,IsInd (_,IndType(indf,realargs)))::l),(y::l') ->
+ let (ind,params) = dest_ind_family indf in
+ let (nal,p,avoid') = decomp_lam_force (List.length realargs) avoid [] p
+ in
+ let na,p,avoid' =
+ if dep then decomp_lam_force 1 avoid' [] p else [Anonymous],p,avoid'
+ in
+ y :=
+ (List.hd na,
+ if List.for_all ((=) Anonymous) nal then
+ None
+ else
+ Some (dummy_loc, ind, (List.map (fun _ -> Anonymous) params)@nal));
+ decomp_block avoid' p (l,l')
+ | (_::l),(y::l') ->
+ y := (Anonymous,None);
+ decomp_block avoid p (l,l')
+ | _ -> anomaly "set_arity_signature"
+ in
+ decomp_block [] pred (tomatchl,arsign)
+
+let prepare_predicate_from_tycon loc dep env isevars tomatchs c =
+ let cook (n, l, env) = function
+ | c,IsInd (_,IndType(indf,realargs)) ->
+ let indf' = lift_inductive_family n indf in
+ let sign = make_arity_signature env dep indf' in
+ let p = List.length realargs in
+ if dep then
+ (n + p + 1, c::(List.rev realargs)@l, push_rels sign env)
+ else
+ (n + p, (List.rev realargs)@l, push_rels sign env)
+ | c,NotInd _ ->
+ (n, l, env) in
+ let n, allargs, env = List.fold_left cook (0, [], env) tomatchs in
+ let allargs =
+ List.map (fun c -> lift n (nf_betadeltaiota env (evars_of isevars) c)) allargs in
+ let rec build_skeleton env c =
+ (* Don't put into normal form, it has effects on the synthesis of evars *)
+ (* let c = whd_betadeltaiota env (evars_of isevars) c in *)
+ (* We turn all subterms possibly dependent into an evar with maximum ctxt*)
+ if isEvar c or List.exists (eq_constr c) allargs then
+ mkExistential isevars env (loc, CasesType)
+ else
+ map_constr_with_full_binders push_rel build_skeleton env c in
+ build_skeleton env (lift n c)
+
+(* Here, [pred] is assumed to be in the context built from all *)
+(* realargs and terms to match *)
+let build_initial_predicate isdep pred tomatchl =
+ let nar = List.fold_left (fun n (_,t) ->
+ let p = match t with IsInd (_,IndType(_,a)) -> List.length a | _ -> 0 in
+ if isdep then n+p+1 else n+p) 0 tomatchl in
+ let cook = function
+ | _,IsInd (_,IndType(_,realargs)) -> List.length realargs
+ | _,NotInd _ -> 0 in
+ let rec buildrec n pred = function
+ | [] -> PrCcl pred
+ | tm::ltm ->
+ let nrealargs = cook tm in
+ let pred, p, user_p =
+ if isdep then
+ if dependent (mkRel (nar-n)) pred then pred, 1, 1
+ else liftn (-1) (nar-n) pred, 0, 1
+ else pred, 0, 0 in
+ PrLetIn ((nrealargs,p=1), buildrec (n+nrealargs+user_p) pred ltm)
+ in buildrec 0 pred tomatchl
+
+let extract_arity_signature env0 tomatchl tmsign =
+ let get_one_sign n tm {contents = (na,t)} =
+ match tm with
+ | NotInd (bo,typ) ->
+ (match t with
+ | None -> [na,option_app (lift n) bo,lift n typ]
+ | Some (loc,_,_) ->
+ user_err_loc (loc,"",
+ str "Unexpected type annotation for a term of non inductive type"))
+ | IsInd (_,IndType(indf,realargs)) ->
+ let indf' = lift_inductive_family n indf in
+ let (ind,params) = dest_ind_family indf' in
+ let nrealargs = List.length realargs in
+ let realnal =
+ match t with
+ | Some (loc,ind',nal) ->
+ let nparams = List.length params in
+ if ind <> ind' then
+ user_err_loc (loc,"",str "Wrong inductive type");
+ if List.length nal <> nparams + nrealargs then
+ user_err_loc (loc,"",
+ str "Wrong number of arguments for inductive type");
+ let parnal,realnal = list_chop nparams nal in
+ if List.exists ((<>) Anonymous) parnal then
+ user_err_loc (loc,"",
+ str "The parameters of inductive type must be implicit");
+ List.rev realnal
+ | None -> list_tabulate (fun _ -> Anonymous) nrealargs in
+ let arsign = fst (get_arity env0 indf') in
+ (na,None,build_dependent_inductive env0 indf')
+ ::(List.map2 (fun x (_,c,t) ->(x,c,t)) realnal arsign) in
+ let rec buildrec n = function
+ | [],[] -> []
+ | (_,tm)::ltm, x::tmsign ->
+ let l = get_one_sign n tm x in
+ (buildrec (n + List.length l) (ltm,tmsign)) @ l
+ | _ -> assert false
+ in buildrec 0 (tomatchl,tmsign)
+
+(* Builds the predicate. If the predicate is dependent, its context is
+ * made of 1+nrealargs assumptions for each matched term in an inductive
+ * type and 1 assumption for each term not _syntactically_ in an
+ * inductive type.
+
+ * V7 case: determines whether the multiple case is dependent or not
+ * - if its arity is made of nrealargs assumptions for each matched
+ * term in an inductive type and nothing for terms not _syntactically_
+ * in an inductive type, then it is non dependent
+ * - if its arity is made of 1+nrealargs assumptions for each matched
+ * term in an inductive type and nothing for terms not _syntactically_
+ * in an inductive type, then it is dependent and needs an adjustement
+ * to fulfill the criterion above that terms not in an inductive type
+ * counts for 1 in the dependent case
+
+ * V8 case: each matched terms are independently considered dependent
+ * or not
+
+ * A type constraint but no annotation case: it is assumed non dependent
+ *)
+
+let prepare_predicate loc typing_fun isevars env tomatchs sign tycon = function
+ (* No type annotation at all *)
+ | (None,{contents = None}) ->
+ (match tycon with
+ | None -> None
+ | Some t ->
+ let pred = prepare_predicate_from_tycon loc false env isevars tomatchs t in
+ Some (build_initial_predicate false pred tomatchs))
+
+ (* v8 style type annotation *)
+ | (None,{contents = Some rtntyp}) ->
+
+ (* We extract the signature of the arity *)
+ let arsign = extract_arity_signature env tomatchs sign in
+ let env = push_rels arsign env in
+ let predccl = (typing_fun (mk_tycon (new_Type ())) env rtntyp).uj_val in
+ Some (build_initial_predicate true predccl tomatchs)
+
+ (* v7 style type annotation; set the v8 annotation by side effect *)
+ | (Some pred,x) ->
+ let loc = loc_of_rawconstr pred in
+ let dep, n, predj =
+ let isevars_copy = evars_of isevars in
+ (* We first assume the predicate is non dependent *)
+ let ndep_arity = build_expected_arity env isevars false tomatchs in
+ try
+ false, nb_prod ndep_arity, typing_fun (mk_tycon ndep_arity) env pred
+ with PretypeError _ | TypeError _ |
+ Stdpp.Exc_located (_,(PretypeError _ | TypeError _)) ->
+ evars_reset_evd isevars_copy isevars;
+ (* We then assume the predicate is dependent *)
+ let dep_arity = build_expected_arity env isevars true tomatchs in
+ try
+ true, nb_prod dep_arity, typing_fun (mk_tycon dep_arity) env pred
+ with PretypeError _ | TypeError _ |
+ Stdpp.Exc_located (_,(PretypeError _ | TypeError _)) ->
+ evars_reset_evd isevars_copy isevars;
+ (* Otherwise we attempt to type it without constraints, possibly *)
+ (* failing with an error message; it may also be well-typed *)
+ (* but fails to satisfy arity constraints in case_dependent *)
+ let predj = typing_fun empty_tycon env pred in
+ error_wrong_predicate_arity_loc
+ loc env predj.uj_val ndep_arity dep_arity
+ in
+ let predccl = extract_predicate_conclusion dep tomatchs predj.uj_val in
+(*
+ let etapred,cdep = case_dependent env (evars_of isevars) loc predj tomatchs in
+*)
+ set_arity_signature dep n sign tomatchs pred x;
+ Some (build_initial_predicate dep predccl tomatchs)
+
+
+(**************************************************************************)
+(* Main entry of the matching compilation *)
+
+let compile_cases loc (typing_fun,isevars) tycon env (predopt, tomatchl, eqns)=
+
+ (* We build the matrix of patterns and right-hand-side *)
+ let matx = matx_of_eqns env tomatchl eqns in
+
+ (* We build the vector of terms to match consistently with the *)
+ (* constructors found in patterns *)
+ let rawtms, tmsign = List.split tomatchl in
+ let tomatchs = coerce_to_indtype typing_fun isevars env matx rawtms in
+
+ (* We build the elimination predicate if any and check its consistency *)
+ (* with the type of arguments to match *)
+ let pred = prepare_predicate loc typing_fun isevars env tomatchs tmsign tycon predopt in
+
+ (* We deal with initial aliases *)
+ let matx = prepare_initial_aliases (known_dependent pred) tomatchs matx in
+
+ (* We push the initial terms to match and push their alias to rhs' envs *)
+ (* names of aliases will be recovered from patterns (hence Anonymous here) *)
+ let initial_pushed = List.map (fun tm -> Pushed (tm,[])) tomatchs in
+
+ let pb =
+ { env = env;
+ isevars = isevars;
+ pred = pred;
+ tomatch = initial_pushed;
+ history = start_history (List.length initial_pushed);
+ mat = matx;
+ caseloc = loc;
+ typing_function = typing_fun } in
+
+ let _, j = compile pb in
+
+ (* We check for unused patterns *)
+ List.iter (check_unused_pattern env) matx;
+
+ match tycon with
+ | Some p -> Coercion.inh_conv_coerce_to loc env isevars j p
+ | None -> j
diff --git a/pretyping/cases.mli b/pretyping/cases.mli
new file mode 100644
index 00000000..1d2f9025
--- /dev/null
+++ b/pretyping/cases.mli
@@ -0,0 +1,56 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: cases.mli,v 1.22.2.2 2004/07/16 19:30:43 herbelin Exp $ i*)
+
+(*i*)
+open Util
+open Names
+open Term
+open Evd
+open Environ
+open Inductiveops
+open Rawterm
+open Evarutil
+(*i*)
+
+type pattern_matching_error =
+ | BadPattern of constructor * constr
+ | BadConstructor of constructor * inductive
+ | WrongNumargConstructor of constructor * int
+ | WrongPredicateArity of constr * constr * constr
+ | NeedsInversion of constr * constr
+ | UnusedClause of cases_pattern list
+ | NonExhaustive of cases_pattern list
+ | CannotInferPredicate of (constr * types) array
+
+exception PatternMatchingError of env * pattern_matching_error
+
+(*s Used for old cases in pretyping *)
+
+val branch_scheme :
+ env -> evar_defs -> bool -> inductive_family -> constr array
+
+type ml_case_error =
+ | MlCaseAbsurd
+ | MlCaseDependent
+
+exception NotInferable of ml_case_error
+
+val pred_case_ml : (* raises [NotInferable] if not inferable *)
+ env -> evar_map -> bool -> inductive_type -> int * types -> constr
+
+(*s Compilation of pattern-matching. *)
+
+val compile_cases :
+ loc -> (type_constraint -> env -> rawconstr -> unsafe_judgment)
+ * evar_defs -> type_constraint -> env ->
+ (rawconstr option * rawconstr option ref) *
+ (rawconstr * (name * (loc * inductive * name list) option) ref) list *
+ (loc * identifier list * cases_pattern list * rawconstr) list ->
+ unsafe_judgment
diff --git a/pretyping/cbv.ml b/pretyping/cbv.ml
new file mode 100644
index 00000000..88f59ded
--- /dev/null
+++ b/pretyping/cbv.ml
@@ -0,0 +1,352 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: cbv.ml,v 1.12.2.1 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Util
+open Pp
+open Term
+open Names
+open Environ
+open Instantiate
+open Univ
+open Evd
+open Closure
+open Esubst
+
+(**** Call by value reduction ****)
+
+(* The type of terms with closure. The meaning of the constructors and
+ * the invariants of this datatype are the following:
+ * VAL(k,c) represents the constr c with a delayed shift of k. c must be
+ * in normal form and neutral (i.e. not a lambda, a construct or a
+ * (co)fix, because they may produce redexes by applying them,
+ * or putting them in a case)
+ * LAM(x,a,b,S) is the term [S]([x:a]b). the bindings is propagated
+ * only when the abstraction is applied, and then we use the rule
+ * ([S]([x:a]b) c) --> [S.c]b
+ * This corresponds to the usual strategy of weak reduction
+ * FIXP(op,bd,S,args) is the fixpoint (Fix or Cofix) of bodies bd under
+ * the bindings S, and then applied to args. Here again,
+ * weak reduction.
+ * CONSTR(c,args) is the constructor [c] applied to [args].
+ *
+ * Note that any term has not an equivalent in cbv_value: for example,
+ * a product (x:A)B must be in normal form because only VAL may
+ * represent it, and the argument of VAL is always in normal
+ * form. This remark precludes coding a head reduction with these
+ * functions. Anyway, does it make sense to head reduce with a
+ * call-by-value strategy ?
+ *)
+type cbv_value =
+ | VAL of int * constr
+ | LAM of name * constr * constr * cbv_value subs
+ | FIXP of fixpoint * cbv_value subs * cbv_value list
+ | COFIXP of cofixpoint * cbv_value subs * cbv_value list
+ | CONSTR of constructor * cbv_value list
+
+(* les vars pourraient etre des constr,
+ cela permet de retarder les lift: utile ?? *)
+
+(* relocation of a value; used when a value stored in a context is expanded
+ * in a larger context. e.g. [%k (S.t)](k+1) --> [^k]t (t is shifted of k)
+ *)
+let rec shift_value n = function
+ | VAL (k,v) -> VAL ((k+n),v)
+ | LAM (x,a,b,s) -> LAM (x,a,b,subs_shft (n,s))
+ | FIXP (fix,s,args) ->
+ FIXP (fix,subs_shft (n,s), List.map (shift_value n) args)
+ | COFIXP (cofix,s,args) ->
+ COFIXP (cofix,subs_shft (n,s), List.map (shift_value n) args)
+ | CONSTR (c,args) ->
+ CONSTR (c, List.map (shift_value n) args)
+
+
+(* Contracts a fixpoint: given a fixpoint and a bindings,
+ * returns the corresponding fixpoint body, and the bindings in which
+ * it should be evaluated: its first variables are the fixpoint bodies
+ * (S, (fix Fi {F0 := T0 .. Fn-1 := Tn-1}))
+ * -> (S. [S]F0 . [S]F1 ... . [S]Fn-1, Ti)
+ *)
+let contract_fixp env ((reci,i),(_,_,bds as bodies)) =
+ let make_body j = FIXP(((reci,j),bodies), env, []) in
+ let n = Array.length bds in
+ let rec subst_bodies_from_i i subs =
+ if i=n then subs
+ else subst_bodies_from_i (i+1) (subs_cons (make_body i, subs))
+ in
+ subst_bodies_from_i 0 env, bds.(i)
+
+let contract_cofixp env (i,(_,_,bds as bodies)) =
+ let make_body j = COFIXP((j,bodies), env, []) in
+ let n = Array.length bds in
+ let rec subst_bodies_from_i i subs =
+ if i=n then subs
+ else subst_bodies_from_i (i+1) (subs_cons (make_body i, subs))
+ in
+ subst_bodies_from_i 0 env, bds.(i)
+
+let make_constr_ref n = function
+ | FarRelKey p -> mkRel (n+p)
+ | VarKey id -> mkVar id
+ | ConstKey cst -> mkConst cst
+
+
+(* type of terms with a hole. This hole can appear only under App or Case.
+ * TOP means the term is considered without context
+ * APP(l,stk) means the term is applied to l, and then we have the context st
+ * this corresponds to the application stack of the KAM.
+ * The members of l are values: we evaluate arguments before the function.
+ * CASE(t,br,pat,S,stk) means the term is in a case (which is himself in stk
+ * t is the type of the case and br are the branches, all of them under
+ * the subs S, pat is information on the patterns of the Case
+ * (Weak reduction: we propagate the sub only when the selected branch
+ * is determined)
+ *
+ * Important remark: the APPs should be collapsed:
+ * (APP (l,(APP ...))) forbidden
+ *)
+
+type cbv_stack =
+ | TOP
+ | APP of cbv_value list * cbv_stack
+ | CASE of constr * constr array * case_info * cbv_value subs * cbv_stack
+
+(* Adds an application list. Collapse APPs! *)
+let stack_app appl stack =
+ match (appl, stack) with
+ | ([], _) -> stack
+ | (_, APP(args,stk)) -> APP(appl@args,stk)
+ | _ -> APP(appl, stack)
+
+
+open RedFlags
+
+let red_set_ref flags = function
+ | FarRelKey _ -> red_set flags fDELTA
+ | VarKey id -> red_set flags (fVAR id)
+ | ConstKey sp -> red_set flags (fCONST sp)
+
+(* Transfer application lists from a value to the stack
+ * useful because fixpoints may be totally applied in several times
+ *)
+let strip_appl head stack =
+ match head with
+ | FIXP (fix,env,app) -> (FIXP(fix,env,[]), stack_app app stack)
+ | COFIXP (cofix,env,app) -> (COFIXP(cofix,env,[]), stack_app app stack)
+ | CONSTR (c,app) -> (CONSTR(c,[]), stack_app app stack)
+ | _ -> (head, stack)
+
+
+(* Tests if fixpoint reduction is possible. A reduction function is given as
+ argument *)
+let rec check_app_constr = function
+ | ([], _) -> false
+ | ((CONSTR _)::_, 0) -> true
+ | (_::l, n) -> check_app_constr (l,(pred n))
+
+let fixp_reducible flgs ((reci,i),_) stk =
+ if red_set flgs fIOTA then
+ match stk with (* !!! for Acc_rec: reci.(i) = -2 *)
+ | APP(appl,_) -> reci.(i) >=0 & check_app_constr (appl, reci.(i))
+ | _ -> false
+ else
+ false
+
+let cofixp_reducible flgs _ stk =
+ if red_set flgs fIOTA then
+ match stk with
+ | (CASE _ | APP(_,CASE _)) -> true
+ | _ -> false
+ else
+ false
+
+(* The main recursive functions
+ *
+ * Go under applications and cases (pushed in the stack), expand head
+ * constants or substitued de Bruijn, and try to make appear a
+ * constructor, a lambda or a fixp in the head. If not, it is a value
+ * and is completely computed here. The head redexes are NOT reduced:
+ * the function returns the pair of a cbv_value and its stack. *
+ * Invariant: if the result of norm_head is CONSTR or (CO)FIXP, it last
+ * argument is []. Because we must put all the applied terms in the
+ * stack. *)
+
+let rec norm_head info env t stack =
+ (* no reduction under binders *)
+ match kind_of_term t with
+ (* stack grows (remove casts) *)
+ | App (head,args) -> (* Applied terms are normalized immediately;
+ they could be computed when getting out of the stack *)
+ let nargs = Array.map (cbv_stack_term info TOP env) args in
+ norm_head info env head (stack_app (Array.to_list nargs) stack)
+ | Case (ci,p,c,v) -> norm_head info env c (CASE(p,v,ci,env,stack))
+ | Cast (ct,_) -> norm_head info env ct stack
+
+ (* constants, axioms
+ * the first pattern is CRUCIAL, n=0 happens very often:
+ * when reducing closed terms, n is always 0 *)
+ | Rel i ->
+ (match expand_rel i env with
+ | Inl (0,v) -> strip_appl v stack
+ | Inl (n,v) -> strip_appl (shift_value n v) stack
+ | Inr (n,None) -> (VAL(0, mkRel n), stack)
+ | Inr (n,Some p) -> norm_head_ref (n-p) info env stack (FarRelKey p))
+
+ | Var id -> norm_head_ref 0 info env stack (VarKey id)
+
+ | Const sp -> norm_head_ref 0 info env stack (ConstKey sp)
+
+ | LetIn (x, b, t, c) ->
+ (* zeta means letin are contracted; delta without zeta means we *)
+ (* allow bindings but leave let's in place *)
+ let zeta = red_set (info_flags info) fZETA in
+ let env' =
+ if zeta
+ (* New rule: for Cbv, Delta does not apply to locally bound variables
+ or red_set (info_flags info) fDELTA
+ *)
+ then
+ subs_cons (cbv_stack_term info TOP env b,env)
+ else
+ subs_lift env in
+ if zeta then
+ norm_head info env' c stack
+ else
+ let normt =
+ mkLetIn (x, cbv_norm_term info env b,
+ cbv_norm_term info env t,
+ cbv_norm_term info env' c) in
+ (VAL(0,normt), stack) (* Considérer une coupure commutative ? *)
+
+ (* non-neutral cases *)
+ | Lambda (x,a,b) -> (LAM(x,a,b,env), stack)
+ | Fix fix -> (FIXP(fix,env,[]), stack)
+ | CoFix cofix -> (COFIXP(cofix,env,[]), stack)
+ | Construct c -> (CONSTR(c, []), stack)
+
+ (* neutral cases *)
+ | (Sort _ | Meta _ | Ind _|Evar _) -> (VAL(0, t), stack)
+ | Prod (x,t,c) ->
+ (VAL(0, mkProd (x, cbv_norm_term info env t,
+ cbv_norm_term info (subs_lift env) c)),
+ stack)
+
+and norm_head_ref k info env stack normt =
+ if red_set_ref (info_flags info) normt then
+ match ref_value_cache info normt with
+ | Some body -> strip_appl (shift_value k body) stack
+ | None -> (VAL(0,make_constr_ref k normt), stack)
+ else (VAL(0,make_constr_ref k normt), stack)
+
+(* cbv_stack_term performs weak reduction on constr t under the subs
+ * env, with context stack, i.e. ([env]t stack). First computes weak
+ * head normal form of t and checks if a redex appears with the stack.
+ * If so, recursive call to reach the real head normal form. If not,
+ * we build a value.
+ *)
+and cbv_stack_term info stack env t =
+ match norm_head info env t stack with
+ (* a lambda meets an application -> BETA *)
+ | (LAM (x,a,b,env), APP (arg::args, stk))
+ when red_set (info_flags info) fBETA ->
+ let subs = subs_cons (arg,env) in
+ cbv_stack_term info (stack_app args stk) subs b
+
+ (* a Fix applied enough -> IOTA *)
+ | (FIXP(fix,env,_), stk)
+ when fixp_reducible (info_flags info) fix stk ->
+ let (envf,redfix) = contract_fixp env fix in
+ cbv_stack_term info stk envf redfix
+
+ (* constructor guard satisfied or Cofix in a Case -> IOTA *)
+ | (COFIXP(cofix,env,_), stk)
+ when cofixp_reducible (info_flags info) cofix stk->
+ let (envf,redfix) = contract_cofixp env cofix in
+ cbv_stack_term info stk envf redfix
+
+ (* constructor in a Case -> IOTA *)
+ | (CONSTR((sp,n),_), APP(args,CASE(_,br,ci,env,stk)))
+ when red_set (info_flags info) fIOTA ->
+ let real_args = list_skipn ci.ci_npar args in
+ cbv_stack_term info (stack_app real_args stk) env br.(n-1)
+
+ (* constructor of arity 0 in a Case -> IOTA *)
+ | (CONSTR((_,n),_), CASE(_,br,_,env,stk))
+ when red_set (info_flags info) fIOTA ->
+ cbv_stack_term info stk env br.(n-1)
+
+ (* may be reduced later by application *)
+ | (head, TOP) -> head
+ | (FIXP(fix,env,_), APP(appl,TOP)) -> FIXP(fix,env,appl)
+ | (COFIXP(cofix,env,_), APP(appl,TOP)) -> COFIXP(cofix,env,appl)
+ | (CONSTR(c,_), APP(appl,TOP)) -> CONSTR(c,appl)
+
+ (* definitely a value *)
+ | (head,stk) -> VAL(0,apply_stack info (cbv_norm_value info head) stk)
+
+
+(* When we are sure t will never produce a redex with its stack, we
+ * normalize (even under binders) the applied terms and we build the
+ * final term
+ *)
+and apply_stack info t = function
+ | TOP -> t
+ | APP (args,st) ->
+ apply_stack info (applistc t (List.map (cbv_norm_value info) args)) st
+ | CASE (ty,br,ci,env,st) ->
+ apply_stack info
+ (mkCase (ci, cbv_norm_term info env ty, t,
+ Array.map (cbv_norm_term info env) br))
+ st
+
+
+(* performs the reduction on a constr, and returns a constr *)
+and cbv_norm_term info env t =
+ (* reduction under binders *)
+ cbv_norm_value info (cbv_stack_term info TOP env t)
+
+(* reduction of a cbv_value to a constr *)
+and cbv_norm_value info = function (* reduction under binders *)
+ | VAL (n,v) -> lift n v
+ | LAM (x,a,b,env) ->
+ mkLambda (x, cbv_norm_term info env a,
+ cbv_norm_term info (subs_lift env) b)
+ | FIXP ((lij,(names,lty,bds)),env,args) ->
+ applistc
+ (mkFix (lij,
+ (names,
+ Array.map (cbv_norm_term info env) lty,
+ Array.map (cbv_norm_term info
+ (subs_liftn (Array.length lty) env)) bds)))
+ (List.map (cbv_norm_value info) args)
+ | COFIXP ((j,(names,lty,bds)),env,args) ->
+ applistc
+ (mkCoFix (j,
+ (names,Array.map (cbv_norm_term info env) lty,
+ Array.map (cbv_norm_term info
+ (subs_liftn (Array.length lty) env)) bds)))
+ (List.map (cbv_norm_value info) args)
+ | CONSTR (c,args) ->
+ applistc
+ (mkConstruct c)
+ (List.map (cbv_norm_value info) args)
+
+(* with profiling *)
+let cbv_norm infos constr =
+ with_stats (lazy (cbv_norm_term infos (ESID 0) constr))
+
+
+type cbv_infos = cbv_value infos
+
+(* constant bodies are normalized at the first expansion *)
+let create_cbv_infos flgs env =
+ create
+ (fun old_info c -> cbv_stack_term old_info TOP (ESID 0) c)
+ flgs
+ env
diff --git a/pretyping/cbv.mli b/pretyping/cbv.mli
new file mode 100644
index 00000000..bf8e03b3
--- /dev/null
+++ b/pretyping/cbv.mli
@@ -0,0 +1,55 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: cbv.mli,v 1.6.14.1 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Environ
+open Closure
+open Esubst
+(*i*)
+
+(************************************************************************)
+(*s Call-by-value reduction *)
+
+(* Entry point for cbv normalization of a constr *)
+type cbv_infos
+
+val create_cbv_infos : RedFlags.reds -> env -> cbv_infos
+val cbv_norm : cbv_infos -> constr -> constr
+
+(************************************************************************)
+(*i This is for cbv debug *)
+type cbv_value =
+ | VAL of int * constr
+ | LAM of name * constr * constr * cbv_value subs
+ | FIXP of fixpoint * cbv_value subs * cbv_value list
+ | COFIXP of cofixpoint * cbv_value subs * cbv_value list
+ | CONSTR of constructor * cbv_value list
+
+val shift_value : int -> cbv_value -> cbv_value
+
+type cbv_stack =
+ | TOP
+ | APP of cbv_value list * cbv_stack
+ | CASE of constr * constr array * case_info * cbv_value subs * cbv_stack
+
+val stack_app : cbv_value list -> cbv_stack -> cbv_stack
+val strip_appl : cbv_value -> cbv_stack -> cbv_value * cbv_stack
+
+(* recursive functions... *)
+val cbv_stack_term : cbv_infos ->
+ cbv_stack -> cbv_value subs -> constr -> cbv_value
+val cbv_norm_term : cbv_infos -> cbv_value subs -> constr -> constr
+val norm_head : cbv_infos ->
+ cbv_value subs -> constr -> cbv_stack -> cbv_value * cbv_stack
+val apply_stack : cbv_infos -> constr -> cbv_stack -> constr
+val cbv_norm_value : cbv_infos -> cbv_value -> constr
+(* End of cbv debug section i*)
diff --git a/pretyping/classops.ml b/pretyping/classops.ml
new file mode 100755
index 00000000..2d8fb951
--- /dev/null
+++ b/pretyping/classops.ml
@@ -0,0 +1,397 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: classops.ml,v 1.48.2.1 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Util
+open Pp
+open Options
+open Names
+open Libnames
+open Nametab
+open Environ
+open Libobject
+open Library
+open Term
+open Termops
+open Rawterm
+open Decl_kinds
+
+(* usage qque peu general: utilise aussi dans record *)
+
+(* A class is a type constructor, its type is an arity whose number of
+ arguments is cl_param (0 for CL_SORT and CL_FUN) *)
+
+type cl_typ =
+ | CL_SORT
+ | CL_FUN
+ | CL_SECVAR of variable
+ | CL_CONST of constant
+ | CL_IND of inductive
+
+type cl_info_typ = {
+ cl_strength : strength;
+ cl_param : int
+}
+
+type coe_typ = global_reference
+
+type coe_info_typ = {
+ coe_value : unsafe_judgment;
+ coe_strength : strength;
+ coe_is_identity : bool;
+ coe_param : int }
+
+type cl_index = int
+
+type coe_index = coe_info_typ
+
+type inheritance_path = coe_index list
+
+(* table des classes, des coercions et graphe d'heritage *)
+
+module Bijint = struct
+ type ('a,'b) t = { v : ('a * 'b) array; s : int; inv : ('a,int) Gmap.t }
+ let empty = { v = [||]; s = 0; inv = Gmap.empty }
+ let mem y b = Gmap.mem y b.inv
+ let map x b = if 0 <= x & x < b.s then b.v.(x) else raise Not_found
+ let revmap y b = let n = Gmap.find y b.inv in (n, snd (b.v.(n)))
+ let add x y b =
+ let v =
+ if b.s = Array.length b.v then
+ (let v = Array.make (b.s + 8) (x,y) in Array.blit b.v 0 v 0 b.s; v)
+ else b.v in
+ v.(b.s) <- (x,y); { v = v; s = b.s+1; inv = Gmap.add x b.s b.inv }
+ let replace n x y b =
+ let v = Array.copy b.v in v.(n) <- (x,y); { b with v = v }
+ let dom b = Gmap.dom b.inv
+end
+
+let class_tab =
+ ref (Bijint.empty : (cl_typ, cl_info_typ) Bijint.t)
+
+let coercion_tab =
+ ref (Gmap.empty : (coe_typ, coe_info_typ) Gmap.t)
+
+let inheritance_graph =
+ ref (Gmap.empty : (cl_index * cl_index, inheritance_path) Gmap.t)
+
+let freeze () = (!class_tab, !coercion_tab, !inheritance_graph)
+
+let unfreeze (fcl,fco,fig) =
+ class_tab:=fcl;
+ coercion_tab:=fco;
+ inheritance_graph:=fig
+
+(* ajout de nouveaux "objets" *)
+
+let add_new_class cl s =
+ try
+ let n,s' = Bijint.revmap cl !class_tab in
+ if s.cl_strength = Global & s'.cl_strength <> Global then
+ class_tab := Bijint.replace n cl s !class_tab
+ with Not_found ->
+ class_tab := Bijint.add cl s !class_tab
+
+let add_new_coercion coe s =
+ coercion_tab := Gmap.add coe s !coercion_tab
+
+let add_new_path x y =
+ inheritance_graph := Gmap.add x y !inheritance_graph
+
+let init () =
+ class_tab:= Bijint.empty;
+ add_new_class CL_FUN { cl_param = 0; cl_strength = Global };
+ add_new_class CL_SORT { cl_param = 0; cl_strength = Global };
+ coercion_tab:= Gmap.empty;
+ inheritance_graph:= Gmap.empty
+
+let _ = init()
+
+(* class_info : cl_typ -> int * cl_info_typ *)
+
+let class_info cl = Bijint.revmap cl !class_tab
+
+let class_exists cl = Bijint.mem cl !class_tab
+
+(* class_info_from_index : int -> cl_typ * cl_info_typ *)
+
+let class_info_from_index i = Bijint.map i !class_tab
+
+(* coercion_info : coe_typ -> coe_info_typ *)
+
+let coercion_info coe = Gmap.find coe !coercion_tab
+
+let coercion_exists coe = Gmap.mem coe !coercion_tab
+
+let coercion_params coe_info = coe_info.coe_param
+
+let lookup_path_between (s,t) =
+ Gmap.find (s,t) !inheritance_graph
+
+let lookup_path_to_fun_from s =
+ lookup_path_between (s,fst(class_info CL_FUN))
+
+let lookup_path_to_sort_from s =
+ lookup_path_between (s,fst(class_info CL_SORT))
+
+let lookup_pattern_path_between (s,t) =
+ let l = Gmap.find (s,t) !inheritance_graph in
+ List.map
+ (fun coe ->
+ let c, _ =
+ Reductionops.whd_betadeltaiota_stack (Global.env()) Evd.empty
+ coe.coe_value.uj_val
+ in
+ match kind_of_term c with
+ | Construct sp -> (sp, coe.coe_param)
+ | _ -> raise Not_found) l
+
+
+let subst_cl_typ subst ct = match ct with
+ CL_SORT
+ | CL_FUN
+ | CL_SECVAR _ -> ct
+ | CL_CONST kn ->
+ let kn' = subst_kn subst kn in
+ if kn' == kn then ct else
+ CL_CONST kn'
+ | CL_IND (kn,i) ->
+ let kn' = subst_kn subst kn in
+ if kn' == kn then ct else
+ CL_IND (kn',i)
+
+let subst_coe_typ = subst_global
+
+let subst_coe_info subst info =
+ let jud = info.coe_value in
+ let val' = subst_mps subst (j_val jud) in
+ let type' = subst_mps subst (j_type jud) in
+ if val' == j_val jud && type' == j_type jud then info else
+ {info with coe_value = make_judge val' type'}
+
+(* library, summary *)
+
+(*val inClass : (cl_typ * cl_info_typ) -> Libobject.object = <fun>
+ val outClass : Libobject.object -> (cl_typ * cl_info_typ) = <fun> *)
+
+let cache_class (_,(x,y)) = add_new_class x y
+
+let subst_class (_,subst,(ct,ci as obj)) =
+ let ct' = subst_cl_typ subst ct in
+ if ct' == ct then obj else
+ (ct',ci)
+
+let (inClass,outClass) =
+ declare_object {(default_object "CLASS") with
+ load_function = (fun _ o -> cache_class o);
+ cache_function = cache_class;
+ subst_function = subst_class;
+ classify_function = (fun (_,x) -> Substitute x);
+ export_function = (function x -> Some x) }
+
+let declare_class (cl,stre,p) =
+ Lib.add_anonymous_leaf (inClass ((cl,{ cl_strength = stre; cl_param = p })))
+
+let _ =
+ Summary.declare_summary "inh_graph"
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init;
+ Summary.survive_module = false;
+ Summary.survive_section = false }
+
+(* classe d'un terme *)
+
+(* find_class_type : constr -> cl_typ * int *)
+
+let find_class_type t =
+ let t', args = decompose_app (Reductionops.whd_betaiotazeta t) in
+ match kind_of_term t' with
+ | Var id -> CL_SECVAR id, args
+ | Const sp -> CL_CONST sp, args
+ | Ind ind_sp -> CL_IND ind_sp, args
+ | Prod (_,_,_) -> CL_FUN, []
+ | Sort _ -> CL_SORT, []
+ | _ -> raise Not_found
+
+(* class_of : Term.constr -> int *)
+
+let class_of env sigma t =
+ let (t, n1, i, args) =
+ try
+ let (cl,args) = find_class_type t in
+ let (i, { cl_param = n1 } ) = class_info cl in
+ (t, n1, i, args)
+ with Not_found ->
+ let t = Tacred.hnf_constr env sigma t in
+ let (cl, args) = find_class_type t in
+ let (i, { cl_param = n1 } ) = class_info cl in
+ (t, n1, i, args)
+ in
+ if List.length args = n1 then t, i else raise Not_found
+
+let inductive_class_of ind = fst (class_info (CL_IND ind))
+
+let class_args_of c = snd (decompose_app c)
+
+let string_of_class = function
+ | CL_FUN -> if !Options.v7 then "FUNCLASS" else "Funclass"
+ | CL_SORT -> if !Options.v7 then "SORTCLASS" else "Sortclass"
+ | CL_CONST sp ->
+ string_of_qualid (shortest_qualid_of_global Idset.empty (ConstRef sp))
+ | CL_IND sp ->
+ string_of_qualid (shortest_qualid_of_global Idset.empty (IndRef sp))
+ | CL_SECVAR sp ->
+ string_of_qualid (shortest_qualid_of_global Idset.empty (VarRef sp))
+
+let pr_class x = str (string_of_class x)
+
+(* coercion_value : coe_index -> unsafe_judgment * bool *)
+
+let coercion_value { coe_value = j; coe_is_identity = b } = (j,b)
+
+(* pretty-print functions are now in Pretty *)
+(* rajouter une coercion dans le graphe *)
+
+let path_printer = ref (fun _ -> str "<a class path>"
+ : (int * int) * inheritance_path -> std_ppcmds)
+
+let install_path_printer f = path_printer := f
+
+let print_path x = !path_printer x
+
+let message_ambig l =
+ (str"Ambiguous paths:" ++ spc () ++
+ prlist_with_sep pr_fnl (fun ijp -> print_path ijp) l)
+
+(* add_coercion_in_graph : coe_index * cl_index * cl_index -> unit
+ coercion,source,target *)
+
+let different_class_params i j =
+ (snd (class_info_from_index i)).cl_param > 0
+
+let add_coercion_in_graph (ic,source,target) =
+ let old_inheritance_graph = !inheritance_graph in
+ let ambig_paths =
+ (ref [] : ((cl_index * cl_index) * inheritance_path) list ref) in
+ let try_add_new_path (i,j as ij) p =
+ try
+ if i=j then begin
+ if different_class_params i j then begin
+ let _ = lookup_path_between ij in
+ ambig_paths := (ij,p)::!ambig_paths
+ end
+ end else begin
+ let _ = lookup_path_between (i,j) in
+ ambig_paths := (ij,p)::!ambig_paths
+ end;
+ false
+ with Not_found -> begin
+ add_new_path ij p;
+ true
+ end
+ in
+ let try_add_new_path1 ij p =
+ let _ = try_add_new_path ij p in ()
+ in
+ if try_add_new_path (source,target) [ic] then begin
+ Gmap.iter
+ (fun (s,t) p ->
+ if s<>t then begin
+ if t = source then begin
+ try_add_new_path1 (s,target) (p@[ic]);
+ Gmap.iter
+ (fun (u,v) q ->
+ if u<>v & (u = target) & (p <> q) then
+ try_add_new_path1 (s,v) (p@[ic]@q))
+ old_inheritance_graph
+ end;
+ if s = target then try_add_new_path1 (source,t) (ic::p)
+ end)
+ old_inheritance_graph
+ end;
+ if (!ambig_paths <> []) && is_verbose () then
+ ppnl (message_ambig !ambig_paths)
+
+type coercion = coe_typ * coe_info_typ * cl_typ * cl_typ
+
+let cache_coercion (_,(coe,xf,cls,clt)) =
+ let is,_ = class_info cls in
+ let it,_ = class_info clt in
+ add_new_coercion coe xf;
+ add_coercion_in_graph (xf,is,it)
+
+let subst_coercion (_,subst,(coe,xf,cls,clt as obj)) =
+ let coe' = subst_coe_typ subst coe in
+ let xf' = subst_coe_info subst xf in
+ let cls' = subst_cl_typ subst cls in
+ let clt' = subst_cl_typ subst clt in
+ if coe' == coe && xf' == xf && cls' == cls & clt' == clt then obj else
+ (coe',xf',cls',clt')
+
+
+(* val inCoercion : coercion -> Libobject.object
+ val outCoercion : Libobject.object -> coercion *)
+
+let (inCoercion,outCoercion) =
+ declare_object {(default_object "COERCION") with
+ load_function = (fun _ o -> cache_coercion o);
+ cache_function = cache_coercion;
+ subst_function = subst_coercion;
+ classify_function = (fun (_,x) -> Substitute x);
+ export_function = (function x -> Some x) }
+
+let declare_coercion coef v stre ~isid ~src:cls ~target:clt ~params:ps =
+ Lib.add_anonymous_leaf
+ (inCoercion
+ (coef,
+ { coe_value = v;
+ coe_strength = stre;
+ coe_is_identity = isid;
+ coe_param = ps },
+ cls, clt))
+
+let coercion_strength v = v.coe_strength
+let coercion_identity v = v.coe_is_identity
+
+(* For printing purpose *)
+let get_coercion_value v = v.coe_value.uj_val
+
+let classes () = Bijint.dom !class_tab
+let coercions () = Gmap.rng !coercion_tab
+let inheritance_graph () = Gmap.to_list !inheritance_graph
+
+let coercion_of_qualid qid =
+ let ref = Nametab.global qid in
+ if not (coercion_exists ref) then
+ errorlabstrm "try_add_coercion"
+ (Nametab.pr_global_env Idset.empty ref ++ str" is not a coercion");
+ ref
+
+module CoercionPrinting =
+ struct
+ type t = coe_typ
+ let encode = coercion_of_qualid
+ let subst = subst_coe_typ
+ let printer x = pr_global_env Idset.empty x
+ let key = Goptions.SecondaryTable ("Printing","Coercion")
+ let title = "Explicitly printed coercions: "
+ let member_message x b =
+ str "Explicit printing of coercion " ++ printer x ++
+ str (if b then " is set" else " is unset")
+ let synchronous = true
+ end
+
+module PrintingCoercion = Goptions.MakeRefTable(CoercionPrinting)
+
+let hide_coercion coe =
+ if not (PrintingCoercion.active coe) then
+ let coe_info = coercion_info coe in
+ Some coe_info.coe_param
+ else None
diff --git a/pretyping/classops.mli b/pretyping/classops.mli
new file mode 100644
index 00000000..f846a9e5
--- /dev/null
+++ b/pretyping/classops.mli
@@ -0,0 +1,116 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: classops.mli,v 1.30.2.1 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Decl_kinds
+open Term
+open Evd
+open Environ
+open Nametab
+(*i*)
+
+(*s This is the type of class kinds *)
+type cl_typ =
+ | CL_SORT
+ | CL_FUN
+ | CL_SECVAR of variable
+ | CL_CONST of constant
+ | CL_IND of inductive
+
+val subst_cl_typ : substitution -> cl_typ -> cl_typ
+
+(* This is the type of infos for declared classes *)
+type cl_info_typ = {
+ cl_strength : strength;
+ cl_param : int }
+
+(* This is the type of coercion kinds *)
+type coe_typ = Libnames.global_reference
+
+(* This is the type of infos for declared coercions *)
+type coe_info_typ
+
+(* [cl_index] is the type of class keys *)
+type cl_index
+
+(* [coe_index] is the type of coercion keys *)
+type coe_index
+
+(* This is the type of paths from a class to another *)
+type inheritance_path = coe_index list
+
+(*s [declare_class] adds a class to the set of declared classes *)
+val declare_class : cl_typ * strength * int -> unit
+
+(*s Access to classes infos *)
+val class_info : cl_typ -> (cl_index * cl_info_typ)
+val class_exists : cl_typ -> bool
+val class_info_from_index : cl_index -> cl_typ * cl_info_typ
+
+(* [find_class_type c] returns the head reference of c and its
+ arguments *)
+val find_class_type : constr -> cl_typ * constr list
+
+(* raises [Not_found] if not convertible to a class *)
+val class_of : env -> evar_map -> constr -> constr * cl_index
+
+(* raises [Not_found] if not mapped to a class *)
+val inductive_class_of : inductive -> cl_index
+
+val class_args_of : constr -> constr list
+
+(*s [declare_coercion] adds a coercion in the graph of coercion paths *)
+val declare_coercion :
+ coe_typ -> unsafe_judgment -> strength -> isid:bool ->
+ src:cl_typ -> target:cl_typ -> params:int -> unit
+
+(*s Access to coercions infos *)
+val coercion_exists : coe_typ -> bool
+
+val coercion_value : coe_index -> (unsafe_judgment * bool)
+
+(*s Lookup functions for coercion paths *)
+val lookup_path_between : cl_index * cl_index -> inheritance_path
+val lookup_path_to_fun_from : cl_index -> inheritance_path
+val lookup_path_to_sort_from : cl_index -> inheritance_path
+val lookup_pattern_path_between :
+ cl_index * cl_index -> (constructor * int) list
+
+(*i Pour le discharge *)
+type coercion = coe_typ * coe_info_typ * cl_typ * cl_typ
+
+open Libobject
+val inClass : (cl_typ * cl_info_typ) -> Libobject.obj
+val outClass : Libobject.obj -> (cl_typ * cl_info_typ)
+val inCoercion : coercion -> Libobject.obj
+val outCoercion : Libobject.obj -> coercion
+val coercion_strength : coe_info_typ -> strength
+val coercion_identity : coe_info_typ -> bool
+val coercion_params : coe_info_typ -> int
+(*i*)
+
+(*i Crade *)
+open Pp
+val install_path_printer :
+ ((cl_index * cl_index) * inheritance_path -> std_ppcmds) -> unit
+(*i*)
+
+(*s This is for printing purpose *)
+val string_of_class : cl_typ -> string
+val pr_class : cl_typ -> std_ppcmds
+val get_coercion_value : coe_index -> constr
+val inheritance_graph : unit -> ((cl_index * cl_index) * inheritance_path) list
+val classes : unit -> cl_typ list
+val coercions : unit -> coe_index list
+
+(* [hide_coercion] returns the number of params to skip if the coercion must
+ be hidden, [None] otherwise; it raises [Not_found] if not a coercion *)
+val hide_coercion : coe_typ -> int option
diff --git a/pretyping/coercion.ml b/pretyping/coercion.ml
new file mode 100644
index 00000000..f214388f
--- /dev/null
+++ b/pretyping/coercion.ml
@@ -0,0 +1,211 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+(* $Id: coercion.ml,v 1.38.6.1 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Util
+open Names
+open Term
+open Reductionops
+open Environ
+open Typeops
+open Pretype_errors
+open Classops
+open Recordops
+open Evarutil
+open Evarconv
+open Retyping
+
+(* Typing operations dealing with coercions *)
+
+let class_of1 env sigma t = class_of env sigma (nf_evar sigma t)
+
+(* Here, funj is a coercion therefore already typed in global context *)
+let apply_coercion_args env argl funj =
+ let rec apply_rec acc typ = function
+ | [] -> { uj_val = applist (j_val funj,argl);
+ uj_type = typ }
+ | h::restl ->
+ (* On devrait pouvoir s'arranger pour qu'on n'ait pas à faire hnf_constr *)
+ match kind_of_term (whd_betadeltaiota env Evd.empty typ) with
+ | Prod (_,c1,c2) ->
+ (* Typage garanti par l'appel à app_coercion*)
+ apply_rec (h::acc) (subst1 h c2) restl
+ | _ -> anomaly "apply_coercion_args"
+ in
+ apply_rec [] funj.uj_type argl
+
+exception NoCoercion
+
+(* appliquer le chemin de coercions de patterns p *)
+
+let apply_pattern_coercion loc pat p =
+ List.fold_left
+ (fun pat (co,n) ->
+ let f i = if i<n then Rawterm.PatVar (loc, Anonymous) else pat in
+ Rawterm.PatCstr (loc, co, list_tabulate f (n+1), Anonymous))
+ pat p
+
+(* raise Not_found if no coercion found *)
+let inh_pattern_coerce_to loc pat ind1 ind2 =
+ let i1 = inductive_class_of ind1 in
+ let i2 = inductive_class_of ind2 in
+ let p = lookup_pattern_path_between (i1,i2) in
+ apply_pattern_coercion loc pat p
+
+(* appliquer le chemin de coercions p à hj *)
+
+let apply_coercion env p hj typ_cl =
+ if !compter then begin
+ nbpathc := !nbpathc +1;
+ nbcoer := !nbcoer + (List.length p)
+ end;
+ try
+ fst (List.fold_left
+ (fun (ja,typ_cl) i ->
+ let fv,isid = coercion_value i in
+ let argl = (class_args_of typ_cl)@[ja.uj_val] in
+ let jres = apply_coercion_args env argl fv in
+ (if isid then
+ { uj_val = ja.uj_val; uj_type = jres.uj_type }
+ else
+ jres),
+ jres.uj_type)
+ (hj,typ_cl) p)
+ with _ -> anomaly "apply_coercion"
+
+let inh_app_fun env isevars j =
+ let t = whd_betadeltaiota env (evars_of isevars) j.uj_type in
+ match kind_of_term t with
+ | Prod (_,_,_) -> j
+ | Evar ev when not (is_defined_evar isevars ev) ->
+ let t = define_evar_as_arrow isevars ev in
+ { uj_val = j.uj_val; uj_type = t }
+ | _ ->
+ (try
+ let t,i1 = class_of1 env (evars_of isevars) j.uj_type in
+ let p = lookup_path_to_fun_from i1 in
+ apply_coercion env p j t
+ with Not_found -> j)
+
+let inh_tosort_force env isevars j =
+ try
+ let t,i1 = class_of1 env (evars_of isevars) j.uj_type in
+ let p = lookup_path_to_sort_from i1 in
+ apply_coercion env p j t
+ with Not_found ->
+ j
+
+let inh_coerce_to_sort env isevars j =
+ let typ = whd_betadeltaiota env (evars_of isevars) j.uj_type in
+ match kind_of_term typ with
+ | Sort s -> { utj_val = j.uj_val; utj_type = s }
+ | Evar ev when not (is_defined_evar isevars ev) ->
+ let s = define_evar_as_sort isevars ev in
+ { utj_val = j.uj_val; utj_type = s }
+ | _ ->
+ let j1 = inh_tosort_force env isevars j in
+ type_judgment env (j_nf_evar (evars_of isevars) j1)
+
+let inh_coerce_to_fail env isevars c1 hj =
+ let hj' =
+ try
+ let t1,i1 = class_of1 env (evars_of isevars) c1 in
+ let t2,i2 = class_of1 env (evars_of isevars) hj.uj_type in
+ let p = lookup_path_between (i2,i1) in
+ apply_coercion env p hj t2
+ with Not_found -> raise NoCoercion
+ in
+ if the_conv_x_leq env isevars hj'.uj_type c1 then
+ hj'
+ else
+ raise NoCoercion
+
+let rec inh_conv_coerce_to_fail env isevars hj c1 =
+ let {uj_val = v; uj_type = t} = hj in
+ if the_conv_x_leq env isevars t c1 then hj
+ else
+ try
+ inh_coerce_to_fail env isevars c1 hj
+ with NoCoercion -> (* try ... with _ -> ... is BAD *)
+ (match kind_of_term (whd_betadeltaiota env (evars_of isevars) t),
+ kind_of_term (whd_betadeltaiota env (evars_of isevars) c1) with
+ | Prod (_,t1,t2), Prod (name,u1,u2) ->
+ let v' = whd_betadeltaiota env (evars_of isevars) v in
+ if (match kind_of_term v' with
+ | Lambda (_,v1,v2) ->
+ the_conv_x env isevars v1 u1 (* leq v1 u1? *)
+ | _ -> false)
+ then
+ let (x,v1,v2) = destLambda v' in
+ let env1 = push_rel (x,None,v1) env in
+ let h2 = inh_conv_coerce_to_fail env1 isevars
+ {uj_val = v2; uj_type = t2 } u2 in
+ { uj_val = mkLambda (x, v1, h2.uj_val);
+ uj_type = mkProd (x, v1, h2.uj_type) }
+ else
+ (* Mismatch on t1 and u1 or not a lambda: we eta-expand *)
+ (* we look for a coercion c:u1->t1 s.t. [name:u1](v' (c x)) *)
+ (* has type (name:u1)u2 (with v' recursively obtained) *)
+ let name = (match name with
+ | Anonymous -> Name (id_of_string "x")
+ | _ -> name) in
+ let env1 = push_rel (name,None,u1) env in
+ let h1 =
+ inh_conv_coerce_to_fail env1 isevars
+ {uj_val = mkRel 1; uj_type = (lift 1 u1) }
+ (lift 1 t1) in
+ let h2 = inh_conv_coerce_to_fail env1 isevars
+ { uj_val = mkApp (lift 1 v, [|h1.uj_val|]);
+ uj_type = subst1 h1.uj_val t2 }
+ u2
+ in
+ { uj_val = mkLambda (name, u1, h2.uj_val);
+ uj_type = mkProd (name, u1, h2.uj_type) }
+ | _ -> raise NoCoercion)
+
+(* Look for cj' obtained from cj by inserting coercions, s.t. cj'.typ = t *)
+let inh_conv_coerce_to loc env isevars cj t =
+ let cj' =
+ try
+ inh_conv_coerce_to_fail env isevars cj t
+ with NoCoercion ->
+ let sigma = evars_of isevars in
+ error_actual_type_loc loc env sigma cj t
+ in
+ { uj_val = cj'.uj_val; uj_type = t }
+
+(* [inh_apply_rel_list loc env isevars args f tycon] tries to type [(f
+ args)] of type [tycon] (if any) by inserting coercions in front of
+ each arg$_i$, if necessary *)
+
+let inh_apply_rel_list apploc env isevars argjl (funloc,funj) tycon =
+ let rec apply_rec env n resj = function
+ | [] -> resj
+ | (loc,hj)::restjl ->
+ let sigma = evars_of isevars in
+ let resj = inh_app_fun env isevars resj in
+ let ntyp = whd_betadeltaiota env sigma resj.uj_type in
+ match kind_of_term ntyp with
+ | Prod (na,c1,c2) ->
+ let hj' =
+ try
+ inh_conv_coerce_to_fail env isevars hj c1
+ with NoCoercion ->
+ error_cant_apply_bad_type_loc apploc env sigma
+ (1,c1,hj.uj_type) resj (List.map snd restjl) in
+ let newresj =
+ { uj_val = applist (j_val resj, [j_val hj']);
+ uj_type = subst1 hj'.uj_val c2 } in
+ apply_rec (push_rel (na,None,c1) env) (n+1) newresj restjl
+ | _ ->
+ error_cant_apply_not_functional_loc
+ (join_loc funloc loc) env sigma resj
+ (List.map snd restjl)
+ in
+ apply_rec env 1 funj argjl
+
diff --git a/pretyping/coercion.mli b/pretyping/coercion.mli
new file mode 100644
index 00000000..658844eb
--- /dev/null
+++ b/pretyping/coercion.mli
@@ -0,0 +1,46 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: coercion.mli,v 1.20.14.2 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Util
+open Evd
+open Names
+open Term
+open Sign
+open Environ
+open Evarutil
+open Rawterm
+(*i*)
+
+(*s Coercions. *)
+
+(* [inh_app_fun env isevars j] coerces [j] to a function; i.e. it
+ inserts a coercion into [j], if needed, in such a way it gets as
+ type a product; it returns [j] if no coercion is applicable *)
+val inh_app_fun :
+ env -> evar_defs -> unsafe_judgment -> unsafe_judgment
+
+(* [inh_coerce_to_sort env isevars j] coerces [j] to a type; i.e. it
+ inserts a coercion into [j], if needed, in such a way it gets as
+ type a sort; it fails if no coercion is applicable *)
+val inh_coerce_to_sort :
+ env -> evar_defs -> unsafe_judgment -> unsafe_type_judgment
+
+(* [inh_conv_coerce_to loc env isevars j t] coerces [j] to an object of type
+ [t]; i.e. it inserts a coercion into [j], if needed, in such a way [t] and
+ [j.uj_type] are convertible; it fails if no coercion is applicable *)
+val inh_conv_coerce_to : loc ->
+ env -> evar_defs -> unsafe_judgment -> constr -> unsafe_judgment
+
+(* [inh_pattern_coerce_to loc env isevars pat ind1 ind2] coerces the Cases
+ pattern [pat] typed in [ind1] into a pattern typed in [ind2];
+ raises [Not_found] if no coercion found *)
+val inh_pattern_coerce_to :
+ loc -> cases_pattern -> inductive -> inductive -> cases_pattern
diff --git a/pretyping/detyping.ml b/pretyping/detyping.ml
new file mode 100644
index 00000000..41f63ace
--- /dev/null
+++ b/pretyping/detyping.ml
@@ -0,0 +1,492 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: detyping.ml,v 1.75.2.4 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Pp
+open Util
+open Univ
+open Names
+open Term
+open Declarations
+open Inductive
+open Inductiveops
+open Environ
+open Sign
+open Rawterm
+open Nameops
+open Termops
+open Libnames
+open Nametab
+
+(****************************************************************************)
+(* Tools for printing of Cases *)
+
+let encode_inductive qid =
+ let indsp = global_inductive qid in
+ let constr_lengths = mis_constr_nargs indsp in
+ (indsp,constr_lengths)
+
+(* Parameterization of the translation from constr to ast *)
+
+(* Tables for Cases printing under a "if" form, a "let" form, *)
+
+let has_two_constructors lc =
+ Array.length lc = 2 (* & lc.(0) = 0 & lc.(1) = 0 *)
+
+let isomorphic_to_tuple lc = (Array.length lc = 1)
+
+let encode_bool r =
+ let (_,lc as x) = encode_inductive r in
+ if not (has_two_constructors lc) then
+ user_err_loc (loc_of_reference r,"encode_if",
+ str "This type has not exactly two constructors");
+ x
+
+let encode_tuple r =
+ let (_,lc as x) = encode_inductive r in
+ if not (isomorphic_to_tuple lc) then
+ user_err_loc (loc_of_reference r,"encode_tuple",
+ str "This type cannot be seen as a tuple type");
+ x
+
+module PrintingCasesMake =
+ functor (Test : sig
+ val encode : reference -> inductive * int array
+ val member_message : std_ppcmds -> bool -> std_ppcmds
+ val field : string
+ val title : string
+ end) ->
+ struct
+ type t = inductive * int array
+ let encode = Test.encode
+ let subst subst ((kn,i), ints as obj) =
+ let kn' = subst_kn subst kn in
+ if kn' == kn then obj else
+ (kn',i), ints
+ let printer (ind,_) = pr_global_env Idset.empty (IndRef ind)
+ let key = Goptions.SecondaryTable ("Printing",Test.field)
+ let title = Test.title
+ let member_message x = Test.member_message (printer x)
+ let synchronous = true
+ end
+
+module PrintingCasesIf =
+ PrintingCasesMake (struct
+ let encode = encode_bool
+ let field = "If"
+ let title = "Types leading to pretty-printing of Cases using a `if' form: "
+ let member_message s b =
+ str "Cases on elements of " ++ s ++
+ str
+ (if b then " are printed using a `if' form"
+ else " are not printed using a `if' form")
+ end)
+
+module PrintingCasesLet =
+ PrintingCasesMake (struct
+ let encode = encode_tuple
+ let field = "Let"
+ let title =
+ "Types leading to a pretty-printing of Cases using a `let' form:"
+ let member_message s b =
+ str "Cases on elements of " ++ s ++
+ str
+ (if b then " are printed using a `let' form"
+ else " are not printed using a `let' form")
+ end)
+
+module PrintingIf = Goptions.MakeRefTable(PrintingCasesIf)
+module PrintingLet = Goptions.MakeRefTable(PrintingCasesLet)
+
+let force_let ci =
+ let indsp = ci.ci_ind in
+ let lc = mis_constr_nargs indsp in PrintingLet.active (indsp,lc)
+let force_if ci =
+ let indsp = ci.ci_ind in
+ let lc = mis_constr_nargs indsp in PrintingIf.active (indsp,lc)
+
+(* Options for printing or not wildcard and synthetisable types *)
+
+open Goptions
+
+let wildcard_value = ref true
+let force_wildcard () = !wildcard_value
+
+let _ = declare_bool_option
+ { optsync = true;
+ optname = "forced wildcard";
+ optkey = SecondaryTable ("Printing","Wildcard");
+ optread = force_wildcard;
+ optwrite = (:=) wildcard_value }
+
+let synth_type_value = ref true
+let synthetize_type () = !synth_type_value
+
+let _ = declare_bool_option
+ { optsync = true;
+ optname = "synthesizability";
+ optkey = SecondaryTable ("Printing","Synth");
+ optread = synthetize_type;
+ optwrite = (:=) synth_type_value }
+
+(* Auxiliary function for MutCase printing *)
+(* [computable] tries to tell if the predicate typing the result is inferable*)
+
+let computable p k =
+ (* We first remove as many lambda as the arity, then we look
+ if it remains a lambda for a dependent elimination. This function
+ works for normal eta-expanded term. For non eta-expanded or
+ non-normal terms, it may affirm the pred is synthetisable
+ because of an undetected ultimate dependent variable in the second
+ clause, or else, it may affirms the pred non synthetisable
+ because of a non normal term in the fourth clause.
+ A solution could be to store, in the MutCase, the eta-expanded
+ normal form of pred to decide if it depends on its variables
+
+ Lorsque le prédicat est dépendant de manière certaine, on
+ ne déclare pas le prédicat synthétisable (même si la
+ variable dépendante ne l'est pas effectivement) parce que
+ sinon on perd la réciprocité de la synthèse (qui, lui,
+ engendrera un prédicat non dépendant) *)
+
+ (nb_lam p = k+1)
+ &&
+ let _,ccl = decompose_lam p in
+ noccur_between 1 (k+1) ccl
+
+
+let lookup_name_as_renamed env t s =
+ let rec lookup avoid env_names n c = match kind_of_term c with
+ | Prod (name,_,c') ->
+ (match concrete_name true avoid env_names name c' with
+ | (Name id,avoid') ->
+ if id=s then (Some n)
+ else lookup avoid' (add_name (Name id) env_names) (n+1) c'
+ | (Anonymous,avoid') -> lookup avoid' env_names (n+1) (pop c'))
+ | LetIn (name,_,_,c') ->
+ (match concrete_name true avoid env_names name c' with
+ | (Name id,avoid') ->
+ if id=s then (Some n)
+ else lookup avoid' (add_name (Name id) env_names) (n+1) c'
+ | (Anonymous,avoid') -> lookup avoid' env_names (n+1) (pop c'))
+ | Cast (c,_) -> lookup avoid env_names n c
+ | _ -> None
+ in lookup (ids_of_named_context (named_context env)) empty_names_context 1 t
+
+let lookup_index_as_renamed env t n =
+ let rec lookup n d c = match kind_of_term c with
+ | Prod (name,_,c') ->
+ (match concrete_name true [] empty_names_context name c' with
+ (Name _,_) -> lookup n (d+1) c'
+ | (Anonymous,_) -> if n=1 then Some d else lookup (n-1) (d+1) c')
+ | LetIn (name,_,_,c') ->
+ (match concrete_name true [] empty_names_context name c' with
+ | (Name _,_) -> lookup n (d+1) c'
+ | (Anonymous,_) -> if n=1 then Some d else lookup (n-1) (d+1) c')
+ | Cast (c,_) -> lookup n d c
+ | _ -> None
+ in lookup n 1 t
+
+let is_nondep_branch c n =
+ try
+ let _,ccl = decompose_lam_n_assum n c in
+ noccur_between 1 n ccl
+ with _ -> (* Not eta-expanded or not reduced *)
+ false
+
+let extract_nondep_branches test c b n =
+ let rec strip n r = if n=0 then r else
+ match r with
+ | RLambda (_,_,_,t) -> strip (n-1) t
+ | RLetIn (_,_,_,t) -> strip (n-1) t
+ | _ -> assert false in
+ if test c n then Some (strip n b) else None
+
+let detype_case computable detype detype_eqn testdep
+ tenv avoid indsp st p k c bl =
+ let synth_type = synthetize_type () in
+ let tomatch = detype c in
+
+ (* Find constructors arity *)
+ let (mib,mip) = Inductive.lookup_mind_specif tenv indsp in
+ let get_consnarg j =
+ let typi = mis_nf_constructor_type (indsp,mib,mip) (j+1) in
+ let _,t = decompose_prod_n_assum (List.length mip.mind_params_ctxt) typi in
+ List.rev (fst (decompose_prod_assum t)) in
+ let consnargs = Array.init (Array.length mip.mind_consnames) get_consnarg in
+ let consnargsl = Array.map List.length consnargs in
+ let alias, aliastyp, newpred, pred =
+ if (not !Options.raw_print) & synth_type & computable & bl <> [||] then
+ Anonymous, None, None, None
+ else
+ let p = option_app detype p in
+ match p with
+ | None -> Anonymous, None, None, None
+ | Some p ->
+ let decompose_lam k c =
+ let rec lamdec_rec l avoid k c =
+ if k = 0 then List.rev l,c else match c with
+ | RLambda (_,x,t,c) ->
+ lamdec_rec (x::l) (name_cons x avoid) (k-1) c
+ | c ->
+ let x = next_ident_away (id_of_string "x") avoid in
+ lamdec_rec ((Name x)::l) (x::avoid) (k-1)
+ (let a = RVar (dummy_loc,x) in
+ match c with
+ | RApp (loc,p,l) -> RApp (loc,p,l@[a])
+ | _ -> (RApp (dummy_loc,c,[a])))
+ in
+ lamdec_rec [] [] k c in
+ let nl,typ = decompose_lam k p in
+ let n,typ = match typ with
+ | RLambda (_,x,t,c) -> x, c
+ | _ -> Anonymous, typ in
+ let aliastyp =
+ if List.for_all ((=) Anonymous) nl then None
+ else
+ let pars = list_tabulate (fun _ -> Anonymous) mip.mind_nparams
+ in Some (dummy_loc,indsp,pars@nl) in
+ n, aliastyp, Some typ, Some p
+ in
+ let constructs = Array.init (Array.length bl) (fun i -> (indsp,i+1)) in
+ let eqnv = array_map3 detype_eqn constructs consnargsl bl in
+ let eqnl = Array.to_list eqnv in
+ let tag =
+ try
+ if !Options.raw_print then
+ RegularStyle
+ else if PrintingLet.active (indsp,consnargsl) then
+ LetStyle
+ else if PrintingIf.active (indsp,consnargsl) then
+ IfStyle
+ else
+ st
+ with Not_found -> st
+ in
+ if tag = RegularStyle then
+ RCases (dummy_loc,(pred,ref newpred),[tomatch,ref (alias,aliastyp)],eqnl)
+ else
+ let bl' = Array.map detype bl in
+ if not !Options.v7 && tag = LetStyle && aliastyp = None then
+ let rec decomp_lam_force n avoid l p =
+ if n = 0 then (List.rev l,p) else
+ match p with
+ | RLambda (_,na,_,c) ->
+ decomp_lam_force (n-1) (name_cons na avoid) (na::l) c
+ | RLetIn (_,na,_,c) ->
+ decomp_lam_force (n-1) (name_cons na avoid) (na::l) c
+ | _ ->
+ let x = Nameops.next_ident_away (id_of_string "x") avoid in
+ decomp_lam_force (n-1) (x::avoid) (Name x :: l)
+ (* eta-expansion *)
+ (let a = RVar (dummy_loc,x) in
+ match p with
+ | RApp (loc,p,l) -> RApp (loc,p,l@[a])
+ | _ -> (RApp (dummy_loc,p,[a]))) in
+ let (nal,d) = decomp_lam_force consnargsl.(0) avoid [] bl'.(0) in
+ RLetTuple (dummy_loc,nal,(alias,newpred),tomatch,d)
+ else
+ let nondepbrs =
+ array_map3 (extract_nondep_branches testdep) bl bl' consnargsl in
+ if not !Options.v7 && tag = IfStyle && aliastyp = None
+ && array_for_all ((<>) None) nondepbrs then
+ RIf (dummy_loc,tomatch,(alias,newpred),
+ out_some nondepbrs.(0),out_some nondepbrs.(1))
+ else if !Options.v7 then
+ let rec remove_type avoid args c =
+ match c,args with
+ | RLambda (loc,na,t,c), _::args ->
+ let h = RHole (dummy_loc,BinderType na) in
+ RLambda (loc,na,h,remove_type avoid args c)
+ | RLetIn (loc,na,b,c), _::args ->
+ RLetIn (loc,na,b,remove_type avoid args c)
+ | c, (na,None,t)::args ->
+ let id = next_name_away_with_default "x" na avoid in
+ let h = RHole (dummy_loc,BinderType na) in
+ let c = remove_type (id::avoid) args
+ (RApp (dummy_loc,c,[RVar (dummy_loc,id)])) in
+ RLambda (dummy_loc,Name id,h,c)
+ | c, (na,Some b,t)::args ->
+ let h = RHole (dummy_loc,BinderType na) in
+ let avoid = name_fold (fun x l -> x::l) na avoid in
+ RLetIn (dummy_loc,na,h,remove_type avoid args c)
+ | c, [] -> c in
+ let bl' = array_map2 (remove_type avoid) consnargs bl' in
+ ROrderedCase (dummy_loc,tag,pred,tomatch,bl',ref None)
+ else
+ RCases(dummy_loc,(pred,ref newpred),[tomatch,ref (alias,aliastyp)],eqnl)
+
+
+let rec detype tenv avoid env t =
+ match kind_of_term (collapse_appl t) with
+ | Rel n ->
+ (try match lookup_name_of_rel n env with
+ | Name id -> RVar (dummy_loc, id)
+ | Anonymous -> anomaly "detype: index to an anonymous variable"
+ with Not_found ->
+ let s = "_UNBOUND_REL_"^(string_of_int n)
+ in RVar (dummy_loc, id_of_string s))
+ | Meta n ->
+ (* Meta in constr are not user-parsable and are mapped to Evar *)
+ REvar (dummy_loc, n, None)
+ | Var id ->
+ (try
+ let _ = Global.lookup_named id in RRef (dummy_loc, VarRef id)
+ with _ ->
+ RVar (dummy_loc, id))
+ | Sort (Prop c) -> RSort (dummy_loc,RProp c)
+ | Sort (Type u) -> RSort (dummy_loc,RType (Some u))
+ | Cast (c1,c2) ->
+ RCast(dummy_loc,detype tenv avoid env c1,
+ detype tenv avoid env c2)
+ | Prod (na,ty,c) -> detype_binder tenv BProd avoid env na ty c
+ | Lambda (na,ty,c) -> detype_binder tenv BLambda avoid env na ty c
+ | LetIn (na,b,_,c) -> detype_binder tenv BLetIn avoid env na b c
+ | App (f,args) ->
+ RApp (dummy_loc,detype tenv avoid env f,
+ array_map_to_list (detype tenv avoid env) args)
+ | Const sp -> RRef (dummy_loc, ConstRef sp)
+ | Evar (ev,cl) ->
+ REvar (dummy_loc, ev,
+ Some (List.map (detype tenv avoid env) (Array.to_list cl)))
+ | Ind ind_sp ->
+ RRef (dummy_loc, IndRef ind_sp)
+ | Construct cstr_sp ->
+ RRef (dummy_loc, ConstructRef cstr_sp)
+ | Case (annot,p,c,bl) ->
+ let comp = computable p (annot.ci_pp_info.ind_nargs) in
+ let ind = annot.ci_ind in
+ let st = annot.ci_pp_info.style in
+ detype_case comp (detype tenv avoid env) (detype_eqn tenv avoid env)
+ is_nondep_branch
+ (snd tenv) avoid ind st (Some p) annot.ci_pp_info.ind_nargs c bl
+ | Fix (nvn,recdef) -> detype_fix tenv avoid env nvn recdef
+ | CoFix (n,recdef) -> detype_cofix tenv avoid env n recdef
+
+and detype_fix tenv avoid env (vn,_ as nvn) (names,tys,bodies) =
+ let def_avoid, def_env, lfi =
+ Array.fold_left
+ (fun (avoid, env, l) na ->
+ let id = next_name_away na avoid in
+ (id::avoid, add_name (Name id) env, id::l))
+ (avoid, env, []) names in
+ let n = Array.length tys in
+ let v = array_map3
+ (fun c t i -> share_names tenv (i+1) [] def_avoid def_env c (lift n t))
+ bodies tys vn in
+ RRec(dummy_loc,RFix nvn,Array.of_list (List.rev lfi),
+ Array.map (fun (bl,_,_) -> bl) v,
+ Array.map (fun (_,_,ty) -> ty) v,
+ Array.map (fun (_,bd,_) -> bd) v)
+
+and detype_cofix tenv avoid env n (names,tys,bodies) =
+ let def_avoid, def_env, lfi =
+ Array.fold_left
+ (fun (avoid, env, l) na ->
+ let id = next_name_away na avoid in
+ (id::avoid, add_name (Name id) env, id::l))
+ (avoid, env, []) names in
+ let ntys = Array.length tys in
+ let v = array_map2
+ (fun c t -> share_names tenv 0 [] def_avoid def_env c (lift ntys t))
+ bodies tys in
+ RRec(dummy_loc,RCoFix n,Array.of_list (List.rev lfi),
+ Array.map (fun (bl,_,_) -> bl) v,
+ Array.map (fun (_,_,ty) -> ty) v,
+ Array.map (fun (_,bd,_) -> bd) v)
+
+and share_names tenv n l avoid env c t =
+ if !Options.v7 && n=0 then
+ let c = detype tenv avoid env c in
+ let t = detype tenv avoid env t in
+ (List.rev l,c,t)
+ else
+ match kind_of_term c, kind_of_term t with
+ (* factorize even when not necessary to have better presentation *)
+ | Lambda (na,t,c), Prod (na',t',c') ->
+ let na = match (na,na') with
+ Name _, _ -> na
+ | _, Name _ -> na'
+ | _ -> na in
+ let t = detype tenv avoid env t in
+ let id = next_name_away na avoid in
+ let avoid = id::avoid and env = add_name (Name id) env in
+ share_names tenv (n-1) ((Name id,None,t)::l) avoid env c c'
+ (* May occur for fix built interactively *)
+ | LetIn (na,b,t',c), _ when n > 0 ->
+ let t' = detype tenv avoid env t' in
+ let b = detype tenv avoid env b in
+ let id = next_name_away na avoid in
+ let avoid = id::avoid and env = add_name (Name id) env in
+ share_names tenv n ((Name id,Some b,t')::l) avoid env c t
+ (* Only if built with the f/n notation or w/o let-expansion in types *)
+ | _, LetIn (_,b,_,t) when n > 0 ->
+ share_names tenv n l avoid env c (subst1 b t)
+ (* If it is an open proof: we cheat and eta-expand *)
+ | _, Prod (na',t',c') when n > 0 ->
+ let t' = detype tenv avoid env t' in
+ let id = next_name_away na' avoid in
+ let avoid = id::avoid and env = add_name (Name id) env in
+ let appc = mkApp (lift 1 c,[|mkRel 1|]) in
+ share_names tenv (n-1) ((Name id,None,t')::l) avoid env appc c'
+ (* If built with the f/n notation: we renounce to share names *)
+ | _ ->
+ if n>0 then warning "Detyping.detype: cannot factorize fix enough";
+ let c = detype tenv avoid env c in
+ let t = detype tenv avoid env t in
+ (List.rev l,c,t)
+
+and detype_eqn tenv avoid env constr construct_nargs branch =
+ let make_pat x avoid env b ids =
+ if force_wildcard () & noccurn 1 b then
+ PatVar (dummy_loc,Anonymous),avoid,(add_name Anonymous env),ids
+ else
+ let id = next_name_away_with_default "x" x avoid in
+ PatVar (dummy_loc,Name id),id::avoid,(add_name (Name id) env),id::ids
+ in
+ let rec buildrec ids patlist avoid env n b =
+ if n=0 then
+ (dummy_loc, ids,
+ [PatCstr(dummy_loc, constr, List.rev patlist,Anonymous)],
+ detype tenv avoid env b)
+ else
+ match kind_of_term b with
+ | Lambda (x,_,b) ->
+ let pat,new_avoid,new_env,new_ids = make_pat x avoid env b ids in
+ buildrec new_ids (pat::patlist) new_avoid new_env (n-1) b
+
+ | LetIn (x,_,_,b) ->
+ let pat,new_avoid,new_env,new_ids = make_pat x avoid env b ids in
+ buildrec new_ids (pat::patlist) new_avoid new_env (n-1) b
+
+ | Cast (c,_) -> (* Oui, il y a parfois des cast *)
+ buildrec ids patlist avoid env n c
+
+ | _ -> (* eta-expansion : n'arrivera plus lorsque tous les
+ termes seront construits à partir de la syntaxe Cases *)
+ (* nommage de la nouvelle variable *)
+ let new_b = applist (lift 1 b, [mkRel 1]) in
+ let pat,new_avoid,new_env,new_ids =
+ make_pat Anonymous avoid env new_b ids in
+ buildrec new_ids (pat::patlist) new_avoid new_env (n-1) new_b
+
+ in
+ buildrec [] [] avoid env construct_nargs branch
+
+and detype_binder tenv bk avoid env na ty c =
+ let na',avoid' =
+ if bk = BLetIn then
+ concrete_let_name (fst tenv) avoid env na c
+ else
+ concrete_name (fst tenv) avoid env na c in
+ let r = detype tenv avoid' (add_name na' env) c in
+ match bk with
+ | BProd -> RProd (dummy_loc, na',detype tenv [] env ty, r)
+ | BLambda -> RLambda (dummy_loc, na',detype tenv [] env ty, r)
+ | BLetIn -> RLetIn (dummy_loc, na',detype tenv [] env ty, r)
diff --git a/pretyping/detyping.mli b/pretyping/detyping.mli
new file mode 100644
index 00000000..c2a70928
--- /dev/null
+++ b/pretyping/detyping.mli
@@ -0,0 +1,42 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: detyping.mli,v 1.13.2.2 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Util
+open Names
+open Term
+open Sign
+open Environ
+open Rawterm
+open Termops
+(*i*)
+
+(* [detype env avoid nenv c] turns [c], typed in [env], into a rawconstr. *)
+(* De Bruijn indexes are turned to bound names, avoiding names in [avoid] *)
+
+val detype : bool * env -> identifier list -> names_context -> constr ->
+ rawconstr
+
+val detype_case :
+ bool -> ('a -> rawconstr) ->
+ (constructor -> int -> 'a -> loc * identifier list * cases_pattern list *
+ rawconstr) -> ('a -> int -> bool) ->
+ env -> identifier list -> inductive -> case_style ->
+ 'a option -> int -> 'a -> 'a array -> rawconstr
+
+(* look for the index of a named var or a nondep var as it is renamed *)
+val lookup_name_as_renamed : env -> constr -> identifier -> int option
+val lookup_index_as_renamed : env -> constr -> int -> int option
+
+
+val force_wildcard : unit -> bool
+val synthetize_type : unit -> bool
+val force_if : case_info -> bool
+val force_let : case_info -> bool
diff --git a/pretyping/doc.tex b/pretyping/doc.tex
new file mode 100644
index 00000000..d92a027e
--- /dev/null
+++ b/pretyping/doc.tex
@@ -0,0 +1,14 @@
+
+\newpage
+\section*{Pre-typing}
+
+\ocwsection \label{pretyping}
+
+\bigskip
+\begin{center}\epsfig{file=pretyping.dep.ps,width=\linewidth}\end{center}
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
diff --git a/pretyping/evarconv.ml b/pretyping/evarconv.ml
new file mode 100644
index 00000000..6f396b43
--- /dev/null
+++ b/pretyping/evarconv.ml
@@ -0,0 +1,397 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: evarconv.ml,v 1.44.6.1 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Util
+open Names
+open Term
+open Reductionops
+open Closure
+open Instantiate
+open Environ
+open Typing
+open Classops
+open Recordops
+open Evarutil
+open Libnames
+
+type flex_kind_of_term =
+ | Rigid of constr
+ | MaybeFlexible of constr
+ | Flexible of existential
+
+let flex_kind_of_term c l =
+ match kind_of_term c with
+ | Const _ -> MaybeFlexible c
+ | Rel n -> MaybeFlexible c
+ | Var id -> MaybeFlexible c
+ | Lambda _ when l<>[] -> MaybeFlexible c
+ | LetIn _ -> MaybeFlexible c
+ | Evar ev -> Flexible ev
+ | _ -> Rigid c
+
+let eval_flexible_term env c =
+ match kind_of_term c with
+ | Const c -> constant_opt_value env c
+ | Rel n -> let (_,v,_) = lookup_rel n env in option_app (lift n) v
+ | Var id -> let (_,v,_) = lookup_named id env in v
+ | LetIn (_,b,_,c) -> Some (subst1 b c)
+ | Lambda _ -> Some c
+ | _ -> assert false
+(*
+let rec apprec_nobeta env sigma s =
+ let (t,stack as s) = whd_state s in
+ match kind_of_term (fst s) with
+ | Case (ci,p,d,lf) ->
+ let (cr,crargs) = whd_betadeltaiota_stack env sigma d in
+ let rslt = mkCase (ci, p, applist (cr,crargs), lf) in
+ if reducible_mind_case cr then
+ apprec_nobeta env sigma (rslt, stack)
+ else
+ s
+ | Fix fix ->
+ (match reduce_fix (whd_betadeltaiota_state env sigma) fix stack with
+ | Reduced s -> apprec_nobeta env sigma s
+ | NotReducible -> s)
+ | _ -> s
+
+let evar_apprec_nobeta env isevars stack c =
+ let rec aux s =
+ let (t,stack as s') = apprec_nobeta env (evars_of isevars) s in
+ match kind_of_term t with
+ | Evar (n,_ as ev) when Evd.is_defined (evars_of isevars) n ->
+ aux (existential_value (evars_of isevars) ev, stack)
+ | _ -> (t, list_of_stack stack)
+ in aux (c, append_stack (Array.of_list stack) empty_stack)
+*)
+
+let evar_apprec env isevars stack c =
+ let sigma = evars_of isevars in
+ let rec aux s =
+ let (t,stack as s') = Reductionops.apprec env sigma s in
+ match kind_of_term t with
+ | Evar (n,_ as ev) when Evd.is_defined sigma n ->
+ aux (existential_value sigma ev, stack)
+ | _ -> (t, list_of_stack stack)
+ in aux (c, append_stack (Array.of_list stack) empty_stack)
+
+let apprec_nohdbeta env isevars c =
+ let (t,stack as s) = Reductionops.whd_stack c in
+ match kind_of_term t with
+ | (Case _ | Fix _) -> evar_apprec env isevars [] c
+ | _ -> s
+
+(* [check_conv_record (t1,l1) (t2,l2)] tries to decompose the problem
+ (t1 l1) = (t2 l2) into a problem
+
+ l1 = params1@c1::extra_args1
+ l2 = us2@extra_args2
+ (t1 params1 c1) = (proji params (c xs))
+ (t2 us2) = (cstr us)
+ extra_args1 = extra_args2
+
+ by finding a record R and an object c := [xs:bs](Build_R a1..am v1..vn)
+ with vi = (cstr us), for which we know that the i-th projection proji
+ satisfies
+
+ (proji params c) = (cstr us)
+
+ Rem: such objects, usable for conversion, are defined in the objdef
+ table; practically, it amounts to "canonically" equip t2 into a
+ object c in structure R (since, if c1 were not an evar, the
+ projection would have been reduced) *)
+
+let check_conv_record (t1,l1) (t2,l2) =
+ try
+ let proji = reference_of_constr t1 in
+ let cstr = reference_of_constr t2 in
+ let { o_DEF = c; o_TABS = bs; o_TPARAMS = params; o_TCOMPS = us } =
+ objdef_info (proji, cstr) in
+ let params1, c1, extra_args1 =
+ match list_chop (List.length params) l1 with
+ | params1, c1::extra_args1 -> params1, c1, extra_args1
+ | _ -> assert false in
+ let us2,extra_args2 = list_chop (List.length us) l2 in
+ c,bs,(params,params1),(us,us2),(extra_args1,extra_args2),c1
+ with _ ->
+ raise Not_found
+
+
+(* Precondition: one of the terms of the pb is an uninstanciated evar,
+ * possibly applied to arguments. *)
+
+let rec evar_conv_x env isevars pbty term1 term2 =
+ let sigma = evars_of isevars in
+ let term1 = whd_castappevar sigma term1 in
+ let term2 = whd_castappevar sigma term2 in
+(*
+ if eq_constr term1 term2 then
+ true
+ else
+*)
+ (* Maybe convertible but since reducing can erase evars which [evar_apprec]*)
+ (* could have found, we do it only if the terms are free of evar *)
+ (not (has_undefined_isevars isevars term1) &
+ not (has_undefined_isevars isevars term2) &
+ is_fconv pbty env (evars_of isevars) term1 term2)
+ or
+ if ise_undefined isevars term1 then
+ solve_simple_eqn evar_conv_x env isevars (pbty,destEvar term1,term2)
+ else if ise_undefined isevars term2 then
+ solve_simple_eqn evar_conv_x env isevars (pbty,destEvar term2,term1)
+ else
+ let (t1,l1) = apprec_nohdbeta env isevars term1 in
+ let (t2,l2) = apprec_nohdbeta env isevars term2 in
+ if (head_is_embedded_evar isevars t1 & not(is_eliminator t2))
+ or (head_is_embedded_evar isevars t2 & not(is_eliminator t1))
+ then
+ (add_conv_pb isevars (pbty,applist(t1,l1),applist(t2,l2)); true)
+ else
+ evar_eqappr_x env isevars pbty (t1,l1) (t2,l2)
+
+and evar_eqappr_x env isevars pbty (term1,l1 as appr1) (term2,l2 as appr2) =
+ (* Evar must be undefined since we have whd_ised *)
+ match (flex_kind_of_term term1 l1, flex_kind_of_term term2 l2) with
+ | Flexible (sp1,al1 as ev1), Flexible (sp2,al2 as ev2) ->
+ let f1 () =
+ if List.length l1 > List.length l2 then
+ let (deb1,rest1) = list_chop (List.length l1-List.length l2) l1 in
+ solve_simple_eqn evar_conv_x env isevars
+ (pbty,ev2,applist(term1,deb1))
+ & list_for_all2eq (evar_conv_x env isevars CONV) rest1 l2
+ else
+ let (deb2,rest2) = list_chop (List.length l2-List.length l1) l2 in
+ solve_simple_eqn evar_conv_x env isevars
+ (pbty,ev1,applist(term2,deb2))
+ & list_for_all2eq (evar_conv_x env isevars CONV) l1 rest2
+ and f2 () =
+ (sp1 = sp2)
+ & (array_for_all2 (evar_conv_x env isevars CONV) al1 al2)
+ & (list_for_all2eq (evar_conv_x env isevars CONV) l1 l2)
+ in
+ ise_try isevars [f1; f2]
+
+ | Flexible ev1, MaybeFlexible flex2 ->
+ let f1 () =
+ (List.length l1 <= List.length l2) &
+ let (deb2,rest2) = list_chop (List.length l2-List.length l1) l2 in
+ (* First compare extra args for better failure message *)
+ list_for_all2eq (evar_conv_x env isevars CONV) l1 rest2 &
+ evar_conv_x env isevars pbty term1 (applist(term2,deb2))
+ and f4 () =
+ match eval_flexible_term env flex2 with
+ | Some v2 ->
+ evar_eqappr_x env isevars pbty
+ appr1 (evar_apprec env isevars l2 v2)
+ | None -> false
+ in
+ ise_try isevars [f1; f4]
+
+ | MaybeFlexible flex1, Flexible ev2 ->
+ let f1 () =
+ (List.length l2 <= List.length l1) &
+ let (deb1,rest1) = list_chop (List.length l1-List.length l2) l1 in
+ (* First compare extra args for better failure message *)
+ list_for_all2eq (evar_conv_x env isevars CONV) rest1 l2 &
+ evar_conv_x env isevars pbty (applist(term1,deb1)) term2
+ and f4 () =
+ match eval_flexible_term env flex1 with
+ | Some v1 ->
+ evar_eqappr_x env isevars pbty
+ (evar_apprec env isevars l1 v1) appr2
+ | None -> false
+ in
+ ise_try isevars [f1; f4]
+
+ | MaybeFlexible flex1, MaybeFlexible flex2 ->
+ let f2 () =
+ (flex1 = flex2)
+ & (List.length l1 = List.length l2)
+ & (list_for_all2eq (evar_conv_x env isevars CONV) l1 l2)
+ and f3 () =
+ (try conv_record env isevars
+ (try check_conv_record appr1 appr2
+ with Not_found -> check_conv_record appr2 appr1)
+ with _ -> false)
+ and f4 () =
+ (* heuristic: unfold second argument first, exception made
+ if the first argument is a beta-redex (expand a constant
+ only if necessary) *)
+ let val2 =
+ match kind_of_term flex1 with
+ Lambda _ -> None
+ | _ -> eval_flexible_term env flex2 in
+ match val2 with
+ | Some v2 ->
+ evar_eqappr_x env isevars pbty
+ appr1 (evar_apprec env isevars l2 v2)
+ | None ->
+ match eval_flexible_term env flex1 with
+ | Some v1 ->
+ evar_eqappr_x env isevars pbty
+ (evar_apprec env isevars l1 v1) appr2
+ | None -> false
+ in
+ ise_try isevars [f2; f3; f4]
+
+ | Flexible ev1, Rigid _ ->
+ (List.length l1 <= List.length l2) &
+ let (deb2,rest2) = list_chop (List.length l2-List.length l1) l2 in
+ (* First compare extra args for better failure message *)
+ list_for_all2eq (evar_conv_x env isevars CONV) l1 rest2 &
+ solve_simple_eqn evar_conv_x env isevars
+ (pbty,ev1,applist(term2,deb2))
+
+ | Rigid _, Flexible ev2 ->
+ (List.length l2 <= List.length l1) &
+ let (deb1,rest1) = list_chop (List.length l1-List.length l2) l1 in
+ (* First compare extra args for better failure message *)
+ list_for_all2eq (evar_conv_x env isevars CONV) rest1 l2 &
+ solve_simple_eqn evar_conv_x env isevars
+ (pbty,ev2,applist(term1,deb1))
+
+
+ | MaybeFlexible flex1, Rigid _ ->
+ let f3 () =
+ (try conv_record env isevars (check_conv_record appr1 appr2)
+ with _ -> false)
+ and f4 () =
+ match eval_flexible_term env flex1 with
+ | Some v1 ->
+ evar_eqappr_x env isevars pbty
+ (evar_apprec env isevars l1 v1) appr2
+ | None -> false
+ in
+ ise_try isevars [f3; f4]
+
+ | Rigid _ , MaybeFlexible flex2 ->
+ let f3 () =
+ (try (conv_record env isevars (check_conv_record appr2 appr1))
+ with _ -> false)
+ and f4 () =
+ match eval_flexible_term env flex2 with
+ | Some v2 ->
+ evar_eqappr_x env isevars pbty
+ appr1 (evar_apprec env isevars l2 v2)
+ | None -> false
+ in
+ ise_try isevars [f3; f4]
+
+ | Rigid c1, Rigid c2 -> match kind_of_term c1, kind_of_term c2 with
+
+ | Cast (c1,_), _ -> evar_eqappr_x env isevars pbty (c1,l1) appr2
+
+ | _, Cast (c2,_) -> evar_eqappr_x env isevars pbty appr1 (c2,l2)
+
+ | Sort s1, Sort s2 when l1=[] & l2=[] -> base_sort_cmp pbty s1 s2
+
+ | Lambda (na,c1,c'1), Lambda (_,c2,c'2) when l1=[] & l2=[] ->
+ evar_conv_x env isevars CONV c1 c2
+ &
+ (let c = nf_evar (evars_of isevars) c1 in
+ evar_conv_x (push_rel (na,None,c) env) isevars CONV c'1 c'2)
+
+ | LetIn (na,b1,t1,c'1), LetIn (_,b2,_,c'2) ->
+ let f1 () =
+ evar_conv_x env isevars CONV b1 b2
+ &
+ (let b = nf_evar (evars_of isevars) b1 in
+ let t = nf_evar (evars_of isevars) t1 in
+ evar_conv_x (push_rel (na,Some b,t) env) isevars pbty c'1 c'2)
+ & (List.length l1 = List.length l2)
+ & (List.for_all2 (evar_conv_x env isevars CONV) l1 l2)
+ and f2 () =
+ let appr1 = evar_apprec env isevars l1 (subst1 b1 c'1)
+ and appr2 = evar_apprec env isevars l2 (subst1 b2 c'2)
+ in evar_eqappr_x env isevars pbty appr1 appr2
+ in
+ ise_try isevars [f1; f2]
+
+ | LetIn (_,b1,_,c'1), _ ->(* On fait commuter les args avec le Let *)
+ let appr1 = evar_apprec env isevars l1 (subst1 b1 c'1)
+ in evar_eqappr_x env isevars pbty appr1 appr2
+
+ | _, LetIn (_,b2,_,c'2) ->
+ let appr2 = evar_apprec env isevars l2 (subst1 b2 c'2)
+ in evar_eqappr_x env isevars pbty appr1 appr2
+
+ | Prod (n,c1,c'1), Prod (_,c2,c'2) when l1=[] & l2=[] ->
+ evar_conv_x env isevars CONV c1 c2
+ &
+ (let c = nf_evar (evars_of isevars) c1 in
+ evar_conv_x (push_rel (n,None,c) env) isevars pbty c'1 c'2)
+
+ | Ind sp1, Ind sp2 ->
+ sp1=sp2
+ & list_for_all2eq (evar_conv_x env isevars CONV) l1 l2
+
+ | Construct sp1, Construct sp2 ->
+ sp1=sp2
+ & list_for_all2eq (evar_conv_x env isevars CONV) l1 l2
+
+ | Case (_,p1,c1,cl1), Case (_,p2,c2,cl2) ->
+ evar_conv_x env isevars CONV p1 p2
+ & evar_conv_x env isevars CONV c1 c2
+ & (array_for_all2 (evar_conv_x env isevars CONV) cl1 cl2)
+ & (list_for_all2eq (evar_conv_x env isevars CONV) l1 l2)
+
+ | Fix (li1,(_,tys1,bds1 as recdef1)), Fix (li2,(_,tys2,bds2)) ->
+ li1=li2
+ & (array_for_all2 (evar_conv_x env isevars CONV) tys1 tys2)
+ & (array_for_all2
+ (evar_conv_x (push_rec_types recdef1 env) isevars CONV)
+ bds1 bds2)
+ & (list_for_all2eq (evar_conv_x env isevars CONV) l1 l2)
+
+ | CoFix (i1,(_,tys1,bds1 as recdef1)), CoFix (i2,(_,tys2,bds2)) ->
+ i1=i2
+ & (array_for_all2 (evar_conv_x env isevars CONV) tys1 tys2)
+ & (array_for_all2
+ (evar_conv_x (push_rec_types recdef1 env) isevars CONV)
+ bds1 bds2)
+ & (list_for_all2eq (evar_conv_x env isevars CONV) l1 l2)
+
+ | (Meta _ | Lambda _), _ -> false
+ | _, (Meta _ | Lambda _) -> false
+
+ | (Ind _ | Construct _ | Sort _ | Prod _), _ -> false
+ | _, (Ind _ | Construct _ | Sort _ | Prod _) -> false
+
+ | (App _ | Case _ | Fix _ | CoFix _),
+ (App _ | Case _ | Fix _ | CoFix _) -> false
+
+ | (Rel _ | Var _ | Const _ | Evar _), _ -> assert false
+ | _, (Rel _ | Var _ | Const _ | Evar _) -> assert false
+
+and conv_record env isevars (c,bs,(params,params1),(us,us2),(ts,ts1),c1) =
+ let ks =
+ List.fold_left
+ (fun ks b ->
+ let dloc = (dummy_loc,Rawterm.InternalHole) in
+ (new_isevar isevars env dloc (substl ks b)) :: ks)
+ [] bs
+ in
+ if (list_for_all2eq
+ (fun u1 u -> evar_conv_x env isevars CONV u1 (substl ks u))
+ us2 us)
+ &
+ (list_for_all2eq
+ (fun x1 x -> evar_conv_x env isevars CONV x1 (substl ks x))
+ params1 params)
+ & (list_for_all2eq (evar_conv_x env isevars CONV) ts ts1)
+ & (evar_conv_x env isevars CONV c1 (applist (c,(List.rev ks))))
+ then
+ (*TR*) (if !compter then (nbstruc:=!nbstruc+1;
+ nbimplstruc:=!nbimplstruc+(List.length ks);true)
+ else true)
+ else false
+
+let the_conv_x env isevars t1 t2 = evar_conv_x env isevars CONV t1 t2
+let the_conv_x_leq env isevars t1 t2 = evar_conv_x env isevars CUMUL t1 t2
+
diff --git a/pretyping/evarconv.mli b/pretyping/evarconv.mli
new file mode 100644
index 00000000..8785d855
--- /dev/null
+++ b/pretyping/evarconv.mli
@@ -0,0 +1,28 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: evarconv.mli,v 1.11.14.1 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Term
+open Sign
+open Environ
+open Reductionops
+open Evarutil
+(*i*)
+
+val the_conv_x : env -> evar_defs -> constr -> constr -> bool
+
+val the_conv_x_leq : env -> evar_defs -> constr -> constr -> bool
+
+(*i For debugging *)
+val evar_conv_x : env -> evar_defs -> conv_pb -> constr -> constr -> bool
+val evar_eqappr_x :
+ env -> evar_defs ->
+ conv_pb -> constr * constr list -> constr * constr list -> bool
+(*i*)
diff --git a/pretyping/evarutil.ml b/pretyping/evarutil.ml
new file mode 100644
index 00000000..441070fe
--- /dev/null
+++ b/pretyping/evarutil.ml
@@ -0,0 +1,579 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: evarutil.ml,v 1.64.2.3 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Util
+open Pp
+open Names
+open Nameops
+open Univ
+open Term
+open Termops
+open Sign
+open Environ
+open Evd
+open Instantiate
+open Reductionops
+open Indrec
+open Pretype_errors
+
+
+let rec filter_unique = function
+ | [] -> []
+ | x::l ->
+ if List.mem x l then filter_unique (List.filter (fun y -> x<>y) l)
+ else x::filter_unique l
+
+(*
+let distinct_id_list =
+ let rec drec fresh = function
+ [] -> List.rev fresh
+ | id::rest ->
+ let id' = next_ident_away_from id fresh in drec (id'::fresh) rest
+ in drec []
+*)
+
+(*
+let filter_sign p sign x =
+ sign_it
+ (fun id ty (v,ids,sgn) ->
+ let (disc,v') = p v (id,ty) in
+ if disc then (v', id::ids, sgn) else (v', ids, add_sign (id,ty) sgn))
+ sign
+ (x,[],nil_sign)
+*)
+
+(* Expanding existential variables (pretyping.ml) *)
+(* 1- whd_ise fails if an existential is undefined *)
+
+exception Uninstantiated_evar of existential_key
+
+let rec whd_ise sigma c =
+ match kind_of_term c with
+ | Evar (ev,args) when Evd.in_dom sigma ev ->
+ if Evd.is_defined sigma ev then
+ whd_ise sigma (existential_value sigma (ev,args))
+ else raise (Uninstantiated_evar ev)
+ | _ -> c
+
+
+(* Expand evars, possibly in the head of an application *)
+let whd_castappevar_stack sigma c =
+ let rec whrec (c, l as s) =
+ match kind_of_term c with
+ | Evar (ev,args) when Evd.in_dom sigma ev & Evd.is_defined sigma ev ->
+ whrec (existential_value sigma (ev,args), l)
+ | Cast (c,_) -> whrec (c, l)
+ | App (f,args) -> whrec (f, Array.fold_right (fun a l -> a::l) args l)
+ | _ -> s
+ in
+ whrec (c, [])
+
+let whd_castappevar sigma c = applist (whd_castappevar_stack sigma c)
+
+let nf_evar = Pretype_errors.nf_evar
+let j_nf_evar = Pretype_errors.j_nf_evar
+let jl_nf_evar = Pretype_errors.jl_nf_evar
+let jv_nf_evar = Pretype_errors.jv_nf_evar
+let tj_nf_evar = Pretype_errors.tj_nf_evar
+
+(**********************)
+(* Creating new evars *)
+(**********************)
+
+let evar_env evd = Global.env_of_context evd.evar_hyps
+
+(* Generator of existential names *)
+let new_evar =
+ let evar_ctr = ref 0 in
+ fun () -> incr evar_ctr; existential_of_int !evar_ctr
+
+let make_evar_instance env =
+ fold_named_context
+ (fun env (id, b, _) l -> (*if b=None then*) mkVar id :: l (*else l*))
+ env ~init:[]
+
+(* create an untyped existential variable *)
+let new_evar_in_sign env =
+ let ev = new_evar () in
+ mkEvar (ev, Array.of_list (make_evar_instance env))
+
+(*------------------------------------*
+ * functional operations on evar sets *
+ *------------------------------------*)
+
+(* All ids of sign must be distincts! *)
+let new_isevar_sign env sigma typ instance =
+ let sign = named_context env in
+ if not (list_distinct (ids_of_named_context sign)) then
+ error "new_isevar_sign: two vars have the same name";
+ let newev = new_evar() in
+ let info = { evar_concl = typ; evar_hyps = sign;
+ evar_body = Evar_empty } in
+ (Evd.add sigma newev info, mkEvar (newev,Array.of_list instance))
+
+(* We don't try to guess in which sort the type should be defined, since
+ any type has type Type. May cause some trouble, but not so far... *)
+let new_Type () = mkType (new_univ ())
+
+let new_Type_sort () = Type (new_univ ())
+
+let judge_of_new_Type () = Typeops.judge_of_type (new_univ ())
+(*
+let new_Type () = mkType dummy_univ
+
+let new_Type_sort () = Type dummy_univ
+
+let judge_of_new_Type () =
+ { uj_val = mkSort (Type dummy_univ);
+ uj_type = mkSort (Type dummy_univ) }
+*)
+
+(* This refreshes universes in types; works only for inferred types (i.e. for
+ types of the form (x1:A1)...(xn:An)B with B a sort or an atom in
+ head normal form) *)
+let refresh_universes t =
+ let modified = ref false in
+ let rec refresh t = match kind_of_term t with
+ | Sort (Type _) -> modified := true; new_Type ()
+ | Prod (na,u,v) -> mkProd (na,u,refresh v)
+ | _ -> t in
+ let t' = refresh t in
+ if !modified then t' else t
+
+(* Declaring any type to be in the sort Type shouldn't be harmful since
+ cumulativity now includes Prop and Set in Type. *)
+let new_type_var env sigma =
+ let instance = make_evar_instance env in
+ new_isevar_sign env sigma (new_Type ()) instance
+
+let split_evar_to_arrow sigma (ev,args) =
+ let evd = Evd.map sigma ev in
+ let evenv = evar_env evd in
+ let (sigma1,dom) = new_type_var evenv sigma in
+ let hyps = evd.evar_hyps in
+ let nvar = next_ident_away (id_of_string "x") (ids_of_named_context hyps) in
+ let newenv = push_named (nvar, None, dom) evenv in
+ let (sigma2,rng) = new_type_var newenv sigma1 in
+ let x = named_hd newenv dom Anonymous in
+ let prod = mkProd (x, dom, subst_var nvar rng) in
+ let sigma3 = Evd.define sigma2 ev prod in
+ let evdom = fst (destEvar dom), args in
+ let evrng =
+ fst (destEvar rng), array_cons (mkRel 1) (Array.map (lift 1) args) in
+ let prod' = mkProd (x, mkEvar evdom, mkEvar evrng) in
+ (sigma3,prod', evdom, evrng)
+
+(* Redefines an evar with a smaller context (i.e. it may depend on less
+ * variables) such that c becomes closed.
+ * Example: in [x:?1; y:(list ?2)] <?3>x=y /\ x=(nil bool)
+ * ?3 <-- ?1 no pb: env of ?3 is larger than ?1's
+ * ?1 <-- (list ?2) pb: ?2 may depend on x, but not ?1.
+ * What we do is that ?2 is defined by a new evar ?4 whose context will be
+ * a prefix of ?2's env, included in ?1's env. *)
+
+let do_restrict_hyps sigma ev args =
+ let args = Array.to_list args in
+ let evd = Evd.map sigma ev in
+ let env = evar_env evd in
+ let hyps = evd.evar_hyps in
+ let (_,(rsign,ncargs)) =
+ List.fold_left
+ (fun (sign,(rs,na)) a ->
+ (List.tl sign,
+ if not(closed0 a) then
+ (rs,na)
+ else
+ (add_named_decl (List.hd sign) rs, a::na)))
+ (hyps,([],[])) args
+ in
+ let sign' = List.rev rsign in
+ let env' = reset_with_named_context sign' env in
+ let instance = make_evar_instance env' in
+ let (sigma',nc) = new_isevar_sign env' sigma evd.evar_concl instance in
+ let nc = refresh_universes nc in (* needed only if nc is an inferred type *)
+ let sigma'' = Evd.define sigma' ev nc in
+ (sigma'', nc)
+
+
+
+
+(*------------------------------------*
+ * operations on the evar constraints *
+ *------------------------------------*)
+
+type evar_constraint = conv_pb * constr * constr
+type evar_defs =
+ { mutable evars : Evd.evar_map;
+ mutable conv_pbs : evar_constraint list;
+ mutable history : (existential_key * (loc * Rawterm.hole_kind)) list }
+
+let create_evar_defs evd = { evars=evd; conv_pbs=[]; history=[] }
+let evars_of d = d.evars
+let evars_reset_evd evd d = d.evars <- evd
+let add_conv_pb d pb = d.conv_pbs <- pb::d.conv_pbs
+let evar_source ev d =
+ try List.assoc ev d.history
+ with Failure _ -> (dummy_loc, Rawterm.InternalHole)
+
+(* ise_try [f1;...;fn] tries fi() for i=1..n, restoring the evar constraints
+ * when fi returns false or an exception. Returns true if one of the fi
+ * returns true, and false if every fi return false (in the latter case,
+ * the evar constraints are restored).
+ *)
+let ise_try isevars l =
+ let u = isevars.evars in
+ let rec test = function
+ [] -> isevars.evars <- u; false
+ | f::l ->
+ (try f() with reraise -> isevars.evars <- u; raise reraise)
+ or (isevars.evars <- u; test l)
+ in test l
+
+
+
+(* say if the section path sp corresponds to an existential *)
+let ise_in_dom isevars sp = Evd.in_dom isevars.evars sp
+
+(* map the given section path to the enamed_declaration *)
+let ise_map isevars sp = Evd.map isevars.evars sp
+
+(* define the existential of section path sp as the constr body *)
+let ise_define isevars sp body =
+ let body = refresh_universes body in (* needed only if an inferred type *)
+ isevars.evars <- Evd.define isevars.evars sp body
+
+let is_defined_evar isevars (n,_) = Evd.is_defined isevars.evars n
+
+(* Does k corresponds to an (un)defined existential ? *)
+let ise_undefined isevars c = match kind_of_term c with
+ | Evar ev -> not (is_defined_evar isevars ev)
+ | _ -> false
+
+let need_restriction isevars args = not (array_for_all closed0 args)
+
+
+(* We try to instanciate the evar assuming the body won't depend
+ * on arguments that are not Rels or Vars, or appearing several times.
+ *)
+(* Note: error_not_clean should not be an error: it simply means that the
+ * conversion test that lead to the faulty call to [real_clean] should return
+ * false. The problem is that we won't get the right error message.
+ *)
+
+let real_clean env isevars ev args rhs =
+ let subst = List.map (fun (x,y) -> (y,mkVar x)) (filter_unique args) in
+ let rec subs k t =
+ match kind_of_term t with
+ | Rel i ->
+ if i<=k then t
+ else (try List.assoc (mkRel (i-k)) subst with Not_found -> t)
+ | Evar (ev,args) ->
+ let args' = Array.map (subs k) args in
+ if need_restriction isevars args' then
+ if Evd.is_defined isevars.evars ev then
+ subs k (existential_value isevars.evars (ev,args'))
+ else begin
+ let (sigma,rc) = do_restrict_hyps isevars.evars ev args' in
+ isevars.evars <- sigma;
+ isevars.history <-
+ (fst (destEvar rc),evar_source ev isevars)::isevars.history;
+ rc
+ end
+ else
+ mkEvar (ev,args')
+ | Var _ -> (try List.assoc t subst with Not_found -> t)
+ | _ -> map_constr_with_binders succ subs k t
+ in
+ let body = subs 0 rhs in
+ if not (closed0 body)
+ then error_not_clean env isevars.evars ev body (evar_source ev isevars);
+ body
+
+let make_evar_instance_with_rel env =
+ let n = rel_context_length (rel_context env) in
+ let vars =
+ fold_named_context
+ (fun env (id,b,_) l -> (* if b=None then *) mkVar id :: l (*else l*))
+ env ~init:[] in
+ snd (fold_rel_context
+ (fun env (_,b,_) (i,l) ->
+ (i-1, (*if b=None then *) mkRel i :: l (*else l*)))
+ env ~init:(n,vars))
+
+let make_subst env args =
+ snd (fold_named_context
+ (fun env (id,b,c) (args,l as g) ->
+ match b, args with
+ | (* None *) _ , a::rest -> (rest, (id,a)::l)
+(* | Some _, _ -> g*)
+ | _ -> anomaly "Instance does not match its signature")
+ env ~init:(List.rev args,[]))
+
+(* [new_isevar] declares a new existential in an env env with type typ *)
+(* Converting the env into the sign of the evar to define *)
+
+let push_rel_context_to_named_context env =
+ let sign0 = named_context env in
+ let (subst,_,sign) =
+ Sign.fold_rel_context
+ (fun (na,c,t) (subst,avoid,sign) ->
+ let na = if na = Anonymous then Name(id_of_string"_") else na in
+ let id = next_name_away na avoid in
+ ((mkVar id)::subst,
+ id::avoid,
+ add_named_decl (id,option_app (substl subst) c,
+ type_app (substl subst) t)
+ sign))
+ (rel_context env) ~init:([],ids_of_named_context sign0,sign0)
+ in (subst, reset_with_named_context sign env)
+
+let new_isevar isevars env src typ =
+ let subst,env' = push_rel_context_to_named_context env in
+ let typ' = substl subst typ in
+ let instance = make_evar_instance_with_rel env in
+ let (sigma',evar) = new_isevar_sign env' isevars.evars typ' instance in
+ isevars.evars <- sigma';
+ isevars.history <- (fst (destEvar evar),src)::isevars.history;
+ evar
+
+(* [evar_define] solves the problem lhs = rhs when lhs is an uninstantiated
+ * evar, i.e. tries to find the body ?sp for lhs=mkEvar (sp,args)
+ * ?sp [ sp.hyps \ args ] unifies to rhs
+ * ?sp must be a closed term, not referring to itself.
+ * Not so trivial because some terms of args may be terms that are not
+ * variables. In this case, the non-var-or-Rels arguments are replaced
+ * by <implicit>. [clean_rhs] will ignore this part of the subtitution.
+ * This leads to incompleteness (we don't deal with pbs that require
+ * inference of dependent types), but it seems sensible.
+ *
+ * If after cleaning, some free vars still occur, the function [restrict_hyps]
+ * tries to narrow the env of the evars that depend on Rels.
+ *
+ * If after that free Rels still occur it means that the instantiation
+ * cannot be done, as in [x:?1; y:nat; z:(le y y)] x=z
+ * ?1 would be instantiated by (le y y) but y is not in the scope of ?1
+ *)
+
+let evar_define env isevars (ev,argsv) rhs =
+ if occur_evar ev rhs
+ then error_occur_check env (evars_of isevars) ev rhs;
+ let args = Array.to_list argsv in
+ let evd = ise_map isevars ev in
+ (* the bindings to invert *)
+ let worklist = make_subst (evar_env evd) args in
+ let body = real_clean env isevars ev worklist rhs in
+ ise_define isevars ev body;
+ [ev]
+
+(*-------------------*)
+(* Auxiliary functions for the conversion algorithms modulo evars
+ *)
+
+let has_undefined_isevars isevars t =
+ try let _ = local_strong (whd_ise isevars.evars) t in false
+ with Uninstantiated_evar _ -> true
+
+let head_is_evar isevars =
+ let rec hrec k = match kind_of_term k with
+ | Evar (n,_) -> not (Evd.is_defined isevars.evars n)
+ | App (f,_) -> hrec f
+ | Cast (c,_) -> hrec c
+ | _ -> false
+ in
+ hrec
+
+let rec is_eliminator c = match kind_of_term c with
+ | App _ -> true
+ | Case _ -> true
+ | Cast (c,_) -> is_eliminator c
+ | _ -> false
+
+let head_is_embedded_evar isevars c =
+ (head_is_evar isevars c) & (is_eliminator c)
+
+let head_evar =
+ let rec hrec c = match kind_of_term c with
+ | Evar (ev,_) -> ev
+ | Case (_,_,c,_) -> hrec c
+ | App (c,_) -> hrec c
+ | Cast (c,_) -> hrec c
+ | _ -> failwith "headconstant"
+ in
+ hrec
+
+(* This code (i.e. solve_pb, etc.) takes a unification
+ * problem, and tries to solve it. If it solves it, then it removes
+ * all the conversion problems, and re-runs conversion on each one, in
+ * the hopes that the new solution will aid in solving them.
+ *
+ * The kinds of problems it knows how to solve are those in which
+ * the usable arguments of an existential var are all themselves
+ * universal variables.
+ * The solution to this problem is to do renaming for the Var's,
+ * to make them match up with the Var's which are found in the
+ * hyps of the existential, to do a "pop" for each Rel which is
+ * not an argument of the existential, and a subst1 for each which
+ * is, again, with the corresponding variable. This is done by
+ * evar_define
+ *
+ * Thus, we take the arguments of the existential which we are about
+ * to assign, and zip them with the identifiers in the hypotheses.
+ * Then, we process all the Var's in the arguments, and sort the
+ * Rel's into ascending order. Then, we just march up, doing
+ * subst1's and pop's.
+ *
+ * NOTE: We can do this more efficiently for the relative arguments,
+ * by building a long substituend by hand, but this is a pain in the
+ * ass.
+ *)
+
+let status_changed lev (pbty,t1,t2) =
+ try
+ List.mem (head_evar t1) lev or List.mem (head_evar t2) lev
+ with Failure _ ->
+ try List.mem (head_evar t2) lev with Failure _ -> false
+
+let get_changed_pb isevars lev =
+ let (pbs,pbs1) =
+ List.fold_left
+ (fun (pbs,pbs1) pb ->
+ if status_changed lev pb then
+ (pb::pbs,pbs1)
+ else
+ (pbs,pb::pbs1))
+ ([],[])
+ isevars.conv_pbs
+ in
+ isevars.conv_pbs <- pbs1;
+ pbs
+
+(* Solve pbs (?i x1..xn) = (?i y1..yn) which arises often in fixpoint
+ * definitions. We try to unify the xi with the yi pairwise. The pairs
+ * that don't unify are discarded (i.e. ?i is redefined so that it does not
+ * depend on these args). *)
+
+let solve_refl conv_algo env isevars ev argsv1 argsv2 =
+ if argsv1 = argsv2 then [] else
+ let evd = Evd.map isevars.evars ev in
+ let hyps = evd.evar_hyps in
+ let (_,rsign) =
+ array_fold_left2
+ (fun (sgn,rsgn) a1 a2 ->
+ if conv_algo env isevars CONV a1 a2 then
+ (List.tl sgn, add_named_decl (List.hd sgn) rsgn)
+ else
+ (List.tl sgn, rsgn))
+ (hyps,[]) argsv1 argsv2
+ in
+ let nsign = List.rev rsign in
+ let nargs = (Array.of_list (List.map mkVar (ids_of_named_context nsign))) in
+ let newev = new_evar () in
+ let info = { evar_concl = evd.evar_concl; evar_hyps = nsign;
+ evar_body = Evar_empty } in
+ isevars.evars <-
+ Evd.define (Evd.add isevars.evars newev info) ev (mkEvar (newev,nargs));
+ isevars.history <- (newev,evar_source ev isevars)::isevars.history;
+ [ev]
+
+
+(* Tries to solve problem t1 = t2.
+ * Precondition: t1 is an uninstanciated evar
+ * Returns an optional list of evars that were instantiated, or None
+ * if the problem couldn't be solved. *)
+
+(* Rq: uncomplete algorithm if pbty = CONV_X_LEQ ! *)
+let solve_simple_eqn conv_algo env isevars (pbty,(n1,args1 as ev1),t2) =
+ let t2 = nf_evar isevars.evars t2 in
+ let lsp = match kind_of_term t2 with
+ | Evar (n2,args2 as ev2)
+ when not (Evd.is_defined isevars.evars n2) ->
+ if n1 = n2 then
+ solve_refl conv_algo env isevars n1 args1 args2
+ else
+ if Array.length args1 < Array.length args2 then
+ evar_define env isevars ev2 (mkEvar ev1)
+ else
+ evar_define env isevars ev1 t2
+ | _ ->
+ evar_define env isevars ev1 t2 in
+ let pbs = get_changed_pb isevars lsp in
+ List.for_all (fun (pbty,t1,t2) -> conv_algo env isevars pbty t1 t2) pbs
+
+(* Operations on value/type constraints *)
+
+type type_constraint = constr option
+type val_constraint = constr option
+
+(* Old comment...
+ * Basically, we have the following kind of constraints (in increasing
+ * strength order):
+ * (false,(None,None)) -> no constraint at all
+ * (true,(None,None)) -> we must build a judgement which _TYPE is a kind
+ * (_,(None,Some ty)) -> we must build a judgement which _TYPE is ty
+ * (_,(Some v,_)) -> we must build a judgement which _VAL is v
+ * Maybe a concrete datatype would be easier to understand.
+ * We differentiate (true,(None,None)) from (_,(None,Some Type))
+ * because otherwise Case(s) would be misled, as in
+ * (n:nat) Case n of bool [_]nat end would infer the predicate Type instead
+ * of Set.
+ *)
+
+(* The empty type constraint *)
+let empty_tycon = None
+
+(* Builds a type constraint *)
+let mk_tycon ty = Some ty
+
+(* Constrains the value of a type *)
+let empty_valcon = None
+
+(* Builds a value constraint *)
+let mk_valcon c = Some c
+
+(* Refining an evar to a product or a sort *)
+
+let refine_evar_as_arrow isevars ev =
+ let (sigma,prod,evdom,evrng) = split_evar_to_arrow isevars.evars ev in
+ evars_reset_evd sigma isevars;
+ let hst = evar_source (fst ev) isevars in
+ isevars.history <- (fst evrng,hst)::(fst evdom, hst)::isevars.history;
+ (prod,evdom,evrng)
+
+let define_evar_as_arrow isevars ev =
+ let (prod,_,_) = refine_evar_as_arrow isevars ev in
+ prod
+
+let define_evar_as_sort isevars (ev,args) =
+ let s = new_Type () in
+ let sigma' = Evd.define isevars.evars ev s in
+ evars_reset_evd sigma' isevars;
+ destSort s
+
+
+(* Propagation of constraints through application and abstraction:
+ Given a type constraint on a functional term, returns the type
+ constraint on its domain and codomain. If the input constraint is
+ an evar instantiate it with the product of 2 new evars. *)
+
+let split_tycon loc env isevars = function
+ | None -> Anonymous,None,None
+ | Some c ->
+ let sigma = evars_of isevars in
+ let t = whd_betadeltaiota env sigma c in
+ match kind_of_term t with
+ | Prod (na,dom,rng) -> na, Some dom, Some rng
+ | Evar (n,_ as ev) when not (Evd.is_defined isevars.evars n) ->
+ let (_,evdom,evrng) = refine_evar_as_arrow isevars ev in
+ Anonymous, Some (mkEvar evdom), Some (mkEvar evrng)
+ | _ -> error_not_product_loc loc env sigma c
+
+let valcon_of_tycon x = x
+
+let lift_tycon = option_app (lift 1)
diff --git a/pretyping/evarutil.mli b/pretyping/evarutil.mli
new file mode 100644
index 00000000..011d2a92
--- /dev/null
+++ b/pretyping/evarutil.mli
@@ -0,0 +1,97 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: evarutil.mli,v 1.33.2.2 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Util
+open Names
+open Rawterm
+open Term
+open Sign
+open Evd
+open Environ
+open Reductionops
+(*i*)
+
+(*s This modules provides useful functions for unification modulo evars *)
+
+(* [whd_ise] raise [Uninstantiated_evar] if an evar remains uninstantiated; *)
+(* *[whd_evar]* and *[nf_evar]* leave uninstantiated evar as is *)
+
+val nf_evar : evar_map -> constr -> constr
+val j_nf_evar : evar_map -> unsafe_judgment -> unsafe_judgment
+val jl_nf_evar :
+ evar_map -> unsafe_judgment list -> unsafe_judgment list
+val jv_nf_evar :
+ evar_map -> unsafe_judgment array -> unsafe_judgment array
+val tj_nf_evar :
+ evar_map -> unsafe_type_judgment -> unsafe_type_judgment
+
+(* Replacing all evars *)
+exception Uninstantiated_evar of existential_key
+val whd_ise : evar_map -> constr -> constr
+val whd_castappevar : evar_map -> constr -> constr
+
+(* Creating new existential variables *)
+val new_evar : unit -> evar
+val new_evar_in_sign : env -> constr
+
+val evar_env : evar_info -> env
+
+type evar_defs
+val evars_of : evar_defs -> evar_map
+val create_evar_defs : evar_map -> evar_defs
+val evars_reset_evd : evar_map -> evar_defs -> unit
+val evar_source : existential_key -> evar_defs -> loc * hole_kind
+
+type evar_constraint = conv_pb * constr * constr
+val add_conv_pb : evar_defs -> evar_constraint -> unit
+
+val is_defined_evar : evar_defs -> existential -> bool
+val ise_try : evar_defs -> (unit -> bool) list -> bool
+val ise_undefined : evar_defs -> constr -> bool
+val has_undefined_isevars : evar_defs -> constr -> bool
+
+val new_isevar_sign :
+ Environ.env -> Evd.evar_map -> Term.constr -> Term.constr list ->
+ Evd.evar_map * Term.constr
+
+val new_isevar : evar_defs -> env -> loc * hole_kind -> constr -> constr
+
+val is_eliminator : constr -> bool
+val head_is_embedded_evar : evar_defs -> constr -> bool
+val solve_simple_eqn :
+ (env -> evar_defs -> conv_pb -> constr -> constr -> bool)
+ -> env -> evar_defs -> conv_pb * existential * constr -> bool
+
+val define_evar_as_arrow : evar_defs -> existential -> types
+val define_evar_as_sort : evar_defs -> existential -> sorts
+
+(* Value/Type constraints *)
+
+val new_Type_sort : unit -> sorts
+val new_Type : unit -> constr
+val judge_of_new_Type : unit -> unsafe_judgment
+val refresh_universes : types -> types
+
+type type_constraint = constr option
+type val_constraint = constr option
+
+val empty_tycon : type_constraint
+val mk_tycon : constr -> type_constraint
+val empty_valcon : val_constraint
+val mk_valcon : constr -> val_constraint
+
+val split_tycon :
+ loc -> env -> evar_defs -> type_constraint ->
+ name * type_constraint * type_constraint
+
+val valcon_of_tycon : type_constraint -> val_constraint
+
+val lift_tycon : type_constraint -> type_constraint
diff --git a/pretyping/evd.ml b/pretyping/evd.ml
new file mode 100644
index 00000000..7a3e7c02
--- /dev/null
+++ b/pretyping/evd.ml
@@ -0,0 +1,74 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: evd.ml,v 1.3.2.1 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Util
+open Names
+open Term
+open Sign
+
+(* The type of mappings for existential variables *)
+
+type evar = existential_key
+
+type evar_body =
+ | Evar_empty
+ | Evar_defined of constr
+
+type evar_info = {
+ evar_concl : constr;
+ evar_hyps : named_context;
+ evar_body : evar_body}
+
+module Evarmap = Intmap
+
+type evar_map = evar_info Evarmap.t
+
+let empty = Evarmap.empty
+
+let to_list evc = Evarmap.fold (fun ev x acc -> (ev,x)::acc) evc []
+let dom evc = Evarmap.fold (fun ev _ acc -> ev::acc) evc []
+let map evc k = Evarmap.find k evc
+let rmv evc k = Evarmap.remove k evc
+let remap evc k i = Evarmap.add k i evc
+let in_dom evc k = Evarmap.mem k evc
+
+let add evd ev newinfo = Evarmap.add ev newinfo evd
+
+let define evd ev body =
+ let oldinfo = map evd ev in
+ let newinfo =
+ { evar_concl = oldinfo.evar_concl;
+ evar_hyps = oldinfo.evar_hyps;
+ evar_body = Evar_defined body}
+ in
+ match oldinfo.evar_body with
+ | Evar_empty -> Evarmap.add ev newinfo evd
+ | _ -> anomaly "cannot define an isevar twice"
+
+(* The list of non-instantiated existential declarations *)
+
+let non_instantiated sigma =
+ let listev = to_list sigma in
+ List.fold_left
+ (fun l ((ev,evd) as d) ->
+ if evd.evar_body = Evar_empty then (d::l) else l)
+ [] listev
+
+let is_evar sigma ev = in_dom sigma ev
+
+let is_defined sigma ev =
+ let info = map sigma ev in
+ not (info.evar_body = Evar_empty)
+
+let evar_body ev = ev.evar_body
+
+let string_of_existential ev = "?" ^ string_of_int ev
+
+let existential_of_int ev = ev
diff --git a/pretyping/evd.mli b/pretyping/evd.mli
new file mode 100644
index 00000000..f66667aa
--- /dev/null
+++ b/pretyping/evd.mli
@@ -0,0 +1,57 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: evd.mli,v 1.3.2.1 2004/07/16 19:30:44 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Sign
+(*i*)
+
+(* The type of mappings for existential variables.
+ The keys are integers and the associated information is a record
+ containing the type of the evar ([evar_concl]), the context under which
+ it was introduced ([evar_hyps]) and its definition ([evar_body]).
+ [evar_info] is used to add any other kind of information. *)
+
+type evar = existential_key
+
+type evar_body =
+ | Evar_empty
+ | Evar_defined of constr
+
+type evar_info = {
+ evar_concl : constr;
+ evar_hyps : named_context;
+ evar_body : evar_body}
+
+type evar_map
+
+val empty : evar_map
+
+val add : evar_map -> evar -> evar_info -> evar_map
+
+val dom : evar_map -> evar list
+val map : evar_map -> evar -> evar_info
+val rmv : evar_map -> evar -> evar_map
+val remap : evar_map -> evar -> evar_info -> evar_map
+val in_dom : evar_map -> evar -> bool
+val to_list : evar_map -> (evar * evar_info) list
+
+val define : evar_map -> evar -> constr -> evar_map
+
+val non_instantiated : evar_map -> (evar * evar_info) list
+val is_evar : evar_map -> evar -> bool
+
+val is_defined : evar_map -> evar -> bool
+
+val evar_body : evar_info -> evar_body
+
+val string_of_existential : evar -> string
+val existential_of_int : int -> evar
diff --git a/pretyping/indrec.ml b/pretyping/indrec.ml
new file mode 100644
index 00000000..0b9283ae
--- /dev/null
+++ b/pretyping/indrec.ml
@@ -0,0 +1,553 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: indrec.ml,v 1.20.2.3 2004/07/16 19:30:44 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Libnames
+open Nameops
+open Term
+open Termops
+open Declarations
+open Entries
+open Inductive
+open Inductiveops
+open Instantiate
+open Environ
+open Reductionops
+open Typeops
+open Type_errors
+open Indtypes (* pour les erreurs *)
+open Safe_typing
+open Nametab
+
+let make_prod_dep dep env = if dep then prod_name env else mkProd
+let mkLambda_string s t c = mkLambda (Name (id_of_string s), t, c)
+
+(*******************************************)
+(* Building curryfied elimination *)
+(*******************************************)
+
+(**********************************************************************)
+(* Building case analysis schemes *)
+(* Nouvelle version, plus concise mais plus coûteuse à cause de
+ lift_constructor et lift_inductive_family qui ne se contentent pas de
+ lifter les paramètres globaux *)
+
+let mis_make_case_com depopt env sigma (ind,mib,mip) kind =
+ let lnamespar = mip.mind_params_ctxt in
+ let dep = match depopt with
+ | None -> mip.mind_sort <> (Prop Null)
+ | Some d -> d
+ in
+ if not (List.exists ((=) kind) mip.mind_kelim) then
+ raise
+ (InductiveError
+ (NotAllowedCaseAnalysis
+ (dep,(new_sort_in_family kind),ind)));
+
+ let nbargsprod = mip.mind_nrealargs + 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 indf = make_ind_family(ind, extended_rel_list 0 lnamespar) in
+ let constrs = get_constructors env indf in
+
+ let rec add_branch env k =
+ if k = Array.length mip.mind_consnames then
+ let nbprod = k+1 in
+ let indf = make_ind_family(ind,extended_rel_list nbprod lnamespar) in
+ let lnamesar,_ = get_arity env indf in
+ let ci = make_default_case_info env RegularStyle ind in
+ let depind = build_dependent_inductive env indf in
+ let deparsign = (Anonymous,None,depind)::lnamesar in
+ let p =
+ it_mkLambda_or_LetIn_name env'
+ (appvect
+ (mkRel ((if dep then nbargsprod else mip.mind_nrealargs) + nbprod),
+ if dep then extended_rel_vect 0 deparsign
+ else extended_rel_vect 0 lnamesar))
+ (if dep then deparsign else lnamesar) in
+ it_mkLambda_or_LetIn_name env'
+ (mkCase (ci, lift nbargsprod p,
+ mkRel 1,
+ rel_vect nbargsprod k))
+ deparsign
+ else
+ let cs = lift_constructor (k+1) constrs.(k) in
+ let t = build_branch_type env dep (mkRel (k+1)) cs in
+ mkLambda_string "f" t
+ (add_branch (push_rel (Anonymous, None, t) env) (k+1))
+ in
+ let typP = make_arity env' dep indf (new_sort_in_family kind) in
+ it_mkLambda_or_LetIn_name env
+ (mkLambda_string "P" typP
+ (add_branch (push_rel (Anonymous,None,typP) env') 0)) lnamespar
+
+(* check if the type depends recursively on one of the inductive scheme *)
+
+(**********************************************************************)
+(* Building the recursive elimination *)
+
+(*
+ * 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_betadeltaiota_nolet_stack env sigma p in
+ match kind_of_term p' with
+ | Prod (n,t,c) ->
+ let d = (n,None,t) in
+ make_prod env (n,t,prec (push_rel d env) (i+1) (d::sign) c)
+ | LetIn (n,b,t,c) ->
+ let d = (n,Some 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),extended_rel_list 0 sign)|]
+ else
+ base
+ | _ -> assert false
+ in
+ prec env 0 []
+ in
+ let rec process_constr env i c recargs nhyps li =
+ if nhyps > 0 then match kind_of_term 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 _ ->
+ Options.if_verbose warning "Ignoring recursive call";
+ (None,rest)
+ | _ -> (None, rest))
+ in
+ (match optionpos with
+ | None ->
+ make_prod env
+ (n,t,
+ process_constr (push_rel (n,None,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 (n,None,t) env in
+ let t_0 = process_pos env' dep' nP (lift 1 t) in
+ make_prod_dep (dep or dep') env
+ (n,t,
+ mkArrow t_0
+ (process_constr
+ (push_rel (Anonymous,None,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 (n,Some b,t) env)
+ (i+1) c_0 recargs (nhyps-1) li)
+ | _ -> assert false
+ else
+ if dep then
+ let realargs = List.map (fun k -> mkRel (i-k)) (List.rev li) in
+ let params = List.map (lift i) vargs in
+ let co = applist (mkConstruct 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 (nparams,fvect,decF) f cstr recargs =
+ let process_pos env fk =
+ let rec prec env i hyps p =
+ let p',largs = whd_betadeltaiota_nolet_stack env sigma p in
+ match kind_of_term p' with
+ | Prod (n,t,c) ->
+ let d = (n,None,t) in
+ lambda_name env (n,t,prec (push_rel d env) (i+1) (d::hyps) c)
+ | LetIn (n,b,t,c) ->
+ let d = (n,Some b,t) in
+ mkLetIn (n,b,t,prec (push_rel d env) (i+1) (d::hyps) c)
+ | Ind _ ->
+ let realargs = list_skipn nparams largs
+ and arg = appvect (mkRel (i+1),extended_rel_vect 0 hyps) in
+ applist(lift i fk,realargs@[arg])
+ | _ -> assert false
+ in
+ prec env 0 []
+ in
+ (* ici, cstrprods est la liste des produits du constructeur instantié *)
+ let rec process_constr env i f = function
+ | (n,None,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 ->
+ lambda_name env
+ (n,t,process_constr (push_rel d env) (i+1)
+ (whd_beta (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
+ lambda_name env
+ (n,t,process_constr env' (i+1)
+ (whd_beta (applist (lift 1 f, [(mkRel 1); arg])))
+ (cprest,rest)))
+ | (n,Some 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 "process_constr"
+
+ in
+ process_constr env 0 f (List.rev cstr.cs_args, recargs)
+
+(* Main function *)
+let mis_make_indrec env sigma listdepkind (ind,mib,mip) =
+ let nparams = mip.mind_nparams in
+ let lnamespar = mip.mind_params_ctxt in
+ let nrec = List.length listdepkind in
+ let depPvec =
+ Array.create mib.mind_ntypes (None : (bool * constr) option) in
+ let _ =
+ let rec
+ assign k = function
+ | [] -> ()
+ | (indi,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
+ let make_one_rec p =
+ let makefix nbconstruct =
+ let rec mrec i ln ltyp ldef = function
+ | (indi,mibi,mipi,dep,_)::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 = extended_rel_list (nrec+nbconstruct) lnamespar in
+ let indf = make_ind_family(indi,args) in
+ let lnames,_ = get_arity env indf in
+
+ let nar = mipi.mind_nrealargs in
+ let dect = nar+nrec+nbconstruct in
+
+ let branches =
+ (* 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' = extended_rel_list (dect+nrec+1) lnamespar in
+ let indf' = make_ind_family(indi,args') in
+ let constrs = get_constructors env indf' in
+ let vecfi = rel_vect (dect+1-i-nctyi) nctyi in
+ array_map3
+ (make_rec_branch_arg env sigma (nparams,depPvec,nar+1))
+ vecfi constrs (dest_subterms recargsvec.(tyi)) in
+ let j = (match depPvec.(tyi) with
+ | Some (_,c) when isRel c -> destRel c
+ | _ -> assert false) in
+ let deftyi =
+ let ci = make_default_case_info env RegularStyle indi in
+ let indf' = lift_inductive_family nrec indf in
+ let depind = build_dependent_inductive env indf' in
+ let lnames' = Termops.lift_rel_context nrec lnames in
+ let p =
+ let arsign =
+ if dep then (Anonymous,None,depind)::lnames' else lnames' in
+ it_mkLambda_or_LetIn_name env
+ (appvect
+ (mkRel ((if dep then 1 else 0) + dect + j),
+ extended_rel_vect 0 arsign)) arsign
+ in
+ it_mkLambda_or_LetIn_name env
+ (lambda_create env
+ (depind,mkCase (ci, lift (nar+1) p, mkRel 1, branches)))
+ lnames'
+ in
+ let typtyi =
+ let ind = build_dependent_inductive env indf in
+ it_mkProd_or_LetIn_name env
+ (prod_create env
+ (ind,
+ (if dep then
+ let ext_lnames = (Anonymous,None,ind)::lnames in
+ let args = extended_rel_list 0 ext_lnames in
+ applist (mkRel (nbconstruct+nar+j+1), args)
+ else
+ let args = extended_rel_list 1 lnames in
+ applist (mkRel (nbconstruct+nar+j+1), args))))
+ lnames
+ in
+ mrec (i+nctyi) (nar::ln) (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 names = Array.create nrec (Name(id_of_string "F")) in
+ mkFix ((fixn,p),(names,fixtyi,fixdef))
+ in
+ mrec 0 [] [] []
+ in
+ let rec make_branch env i = function
+ | (indi,mibi,mipi,dep,_)::rest ->
+ let tyi = snd indi in
+ let nconstr = Array.length mipi.mind_consnames in
+ let rec onerec env j =
+ if j = nconstr then
+ make_branch env (i+j) rest
+ else
+ let recarg = (dest_subterms recargsvec.(tyi)).(j) in
+ let vargs = extended_rel_list (nrec+i+j) lnamespar in
+ let indf = (indi, vargs) in
+ let cs = get_constructor (indi,mibi,mipi,vargs) (j+1) in
+ let p_0 =
+ type_rec_branch
+ true dep env sigma (vargs,depPvec,i+j) tyi cs recarg
+ in
+ mkLambda_string "f" p_0
+ (onerec (push_rel (Anonymous,None,p_0) env) (j+1))
+ in onerec env 0
+ | [] ->
+ makefix i listdepkind
+ in
+ let rec put_arity env i = function
+ | (indi,_,_,dep,kinds)::rest ->
+ let indf = make_ind_family (indi,extended_rel_list i lnamespar) in
+ let typP = make_arity env dep indf (new_sort_in_family kinds) in
+ mkLambda_string "P" typP
+ (put_arity (push_rel (Anonymous,None,typP) env) (i+1) rest)
+ | [] ->
+ make_branch env 0 listdepkind
+ in
+ let (indi,mibi,mipi,dep,kind) = List.nth listdepkind p in
+ let env' = push_rel_context lnamespar env in
+ if mis_is_recursive_subset
+ (List.map (fun (indi,_,_,_,_) -> snd indi) listdepkind)
+ mipi.mind_recargs
+ then
+ it_mkLambda_or_LetIn_name env (put_arity env' 0 listdepkind) lnamespar
+ else
+ mis_make_case_com (Some dep) env sigma (indi,mibi,mipi) kind
+ in
+ list_tabulate make_one_rec nrec
+
+(**********************************************************************)
+(* This builds elimination predicate for Case tactic *)
+
+let make_case_com depopt env sigma ity kind =
+ let (mib,mip) = lookup_mind_specif env ity in
+ mis_make_case_com depopt env sigma (ity,mib,mip) kind
+
+let make_case_dep env = make_case_com (Some true) env
+let make_case_nodep env = make_case_com (Some false) env
+let make_case_gen env = make_case_com None env
+
+
+(**********************************************************************)
+(* [instanciate_indrec_scheme s rec] replace the sort of the scheme
+ [rec] by [s] *)
+
+let change_sort_arity sort =
+ let rec drec a = match kind_of_term a with
+ | Cast (c,t) -> drec c
+ | Prod (n,t,c) -> mkProd (n, t, drec c)
+ | Sort _ -> mkSort sort
+ | _ -> assert false
+ in
+ drec
+
+(* [npar] is the number of expected arguments (then excluding letin's) *)
+let instanciate_indrec_scheme sort =
+ let rec drec npar elim =
+ match kind_of_term elim with
+ | Lambda (n,t,c) ->
+ if npar = 0 then
+ mkLambda (n, change_sort_arity sort t, c)
+ else
+ mkLambda (n, t, drec (npar-1) c)
+ | LetIn (n,b,t,c) -> mkLetIn (n,b,t,drec npar c)
+ | _ -> anomaly "instanciate_indrec_scheme: wrong elimination type"
+ in
+ drec
+
+(* Change the sort in the type of an inductive definition, builds the
+ corresponding eta-expanded term *)
+let instanciate_type_indrec_scheme sort npars term =
+ let rec drec np elim =
+ match kind_of_term elim with
+ | Prod (n,t,c) ->
+ if np = 0 then
+ let t' = change_sort_arity sort t in
+ 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 "instanciate_type_indrec_scheme: wrong elimination type"
+ in
+ drec npars
+
+(**********************************************************************)
+(* Interface to build complex Scheme *)
+
+let check_arities listdepkind =
+ List.iter
+ (function (indi,mibi,mipi,dep,kind) ->
+ let id = mipi.mind_typename in
+ let kelim = mipi.mind_kelim in
+ if not (List.exists ((=) kind) kelim) then
+ raise
+ (InductiveError (BadInduction (dep, id, new_sort_in_family kind))))
+ listdepkind
+
+let build_mutual_indrec env sigma = function
+ | (mind,mib,mip,dep,s)::lrecspec ->
+ let (sp,tyi) = mind in
+ let listdepkind =
+ (mind,mib,mip, dep,s)::
+ (List.map
+ (function (mind',mibi',mipi',dep',s') ->
+ let (sp',_) = mind' in
+ if sp=sp' then
+ let (mibi',mipi') = lookup_mind_specif env mind' in
+ (mind',mibi',mipi',dep',s')
+ else
+ raise (InductiveError NotMutualInScheme))
+ lrecspec)
+ in
+ let _ = check_arities listdepkind in
+ mis_make_indrec env sigma listdepkind (mind,mib,mip)
+ | _ -> anomaly "build_indrec expects a non empty list of inductive types"
+
+let build_indrec env sigma ind =
+ let (mib,mip) = lookup_mind_specif env ind in
+ let kind = family_of_sort mip.mind_sort in
+ let dep = kind <> InProp in
+ List.hd (mis_make_indrec env sigma [(ind,mib,mip,dep,kind)] (ind,mib,mip))
+
+(**********************************************************************)
+(* To handle old Case/Match syntax in Pretyping *)
+
+(*****************************************)
+(* To interpret Case and Match operators *)
+(* Expects a dependent predicate *)
+
+let type_rec_branches recursive env sigma indt p c =
+ let IndType (indf,realargs) = indt in
+ let (ind,params) = dest_ind_family indf in
+ let (mib,mip) = lookup_mind_specif env ind in
+ let recargs = mip.mind_recargs in
+ let tyi = snd ind in
+ let init_depPvec i = if i = tyi then Some(true,p) else None in
+ let depPvec = Array.init mib.mind_ntypes init_depPvec in
+ let vargs = Array.of_list params in
+ let constructors = get_constructors env indf in
+ let lft =
+ array_map2
+ (type_rec_branch recursive true env sigma (params,depPvec,0) tyi)
+ constructors (dest_subterms recargs) in
+ (lft,Reduction.beta_appvect p (Array.of_list (realargs@[c])))
+(* Non recursive case. Pb: does not deal with unification
+ let (p,ra,_) = type_case_branches env (ind,params@realargs) pj c in
+ (p,ra)
+*)
+
+(*s Eliminations. *)
+
+let elimination_suffix = function
+ | InProp -> "_ind"
+ | InSet -> "_rec"
+ | InType -> "_rect"
+
+let make_elimination_ident id s = add_suffix id (elimination_suffix s)
+
+(* Look up function for the default elimination constant *)
+
+let lookup_eliminator ind_sp s =
+ let kn,i = ind_sp in
+ let mp,dp,l = repr_kn kn in
+ let ind_id = (Global.lookup_mind kn).mind_packets.(i).mind_typename in
+ let id = add_suffix ind_id (elimination_suffix s) in
+ (* Try first to get an eliminator defined in the same section as the *)
+ (* inductive type *)
+ let ref = ConstRef (make_kn mp dp (label_of_id id)) in
+ try
+ let _ = sp_of_global ref in
+ constr_of_reference ref
+ with Not_found ->
+ (* Then try to get a user-defined eliminator in some other places *)
+ (* using short name (e.g. for "eq_rec") *)
+ try constr_of_reference (Nametab.locate (make_short_qualid id))
+ with Not_found ->
+ errorlabstrm "default_elim"
+ (str "Cannot find the elimination combinator " ++
+ pr_id id ++ spc () ++
+ str "The elimination of the inductive definition " ++
+ pr_id id ++ spc () ++ str "on sort " ++
+ spc () ++ print_sort_family s ++
+ str " is probably not allowed")
+
+
+(* let env = Global.env() in
+ let path = sp_of_global None (IndRef ind_sp) in
+ let dir, base = repr_path path in
+ let id = add_suffix base (elimination_suffix s) in
+ (* Try first to get an eliminator defined in the same section as the *)
+ (* inductive type *)
+ try construct_absolute_reference (Names.make_path dir id)
+ with Not_found ->
+ (* Then try to get a user-defined eliminator in some other places *)
+ (* using short name (e.g. for "eq_rec") *)
+ try constr_of_reference (Nametab.locate (make_short_qualid id))
+ with Not_found ->
+ errorlabstrm "default_elim"
+ (str "Cannot find the elimination combinator " ++
+ pr_id id ++ spc () ++
+ str "The elimination of the inductive definition " ++
+ pr_id base ++ spc () ++ str "on sort " ++
+ spc () ++ print_sort_family s ++
+ str " is probably not allowed")
+*)
diff --git a/pretyping/indrec.mli b/pretyping/indrec.mli
new file mode 100644
index 00000000..f6f76706
--- /dev/null
+++ b/pretyping/indrec.mli
@@ -0,0 +1,56 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: indrec.mli,v 1.6.2.1 2004/07/16 19:30:45 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Declarations
+open Inductiveops
+open Environ
+open Evd
+(*i*)
+
+(* Eliminations. *)
+
+(* These functions build elimination predicate for Case tactic *)
+
+val make_case_dep : env -> evar_map -> inductive -> sorts_family -> constr
+val make_case_nodep : env -> evar_map -> inductive -> sorts_family -> constr
+val make_case_gen : env -> evar_map -> inductive -> sorts_family -> constr
+
+(* This builds an elimination scheme associated (using the own arity
+ of the inductive) *)
+
+val build_indrec : env -> evar_map -> inductive -> constr
+val instanciate_indrec_scheme : sorts -> int -> constr -> constr
+val instanciate_type_indrec_scheme : sorts -> int -> constr -> types ->
+ constr * types
+
+(* This builds complex [Scheme] *)
+
+val build_mutual_indrec :
+ env -> evar_map ->
+ (inductive * mutual_inductive_body * one_inductive_body
+ * bool * sorts_family) list
+ -> constr list
+
+(* These are for old Case/Match typing *)
+
+val type_rec_branches : bool -> env -> evar_map -> inductive_type
+ -> constr -> constr -> constr array * constr
+val make_rec_branch_arg :
+ env -> evar_map ->
+ int * ('b * constr) option array * int ->
+ constr -> constructor_summary -> wf_paths list -> constr
+
+(* *)
+val lookup_eliminator : inductive -> sorts_family -> constr
+val elimination_suffix : sorts_family -> string
+val make_elimination_ident : identifier -> sorts_family -> identifier
diff --git a/pretyping/inductiveops.ml b/pretyping/inductiveops.ml
new file mode 100644
index 00000000..24a8fbc7
--- /dev/null
+++ b/pretyping/inductiveops.ml
@@ -0,0 +1,352 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: inductiveops.ml,v 1.14.2.1 2004/07/16 19:30:45 herbelin Exp $ *)
+
+open Util
+open Names
+open Univ
+open Term
+open Termops
+open Sign
+open Declarations
+open Environ
+open Reductionops
+
+(* [inductive_family] = [inductive_instance] applied to global parameters *)
+type inductive_family = inductive * constr list
+
+let make_ind_family (mis, params) = (mis,params)
+let dest_ind_family (mis,params) = (mis,params)
+
+let map_ind_family f (mis,params) = (mis, List.map f params)
+
+let liftn_inductive_family n d = map_ind_family (liftn n d)
+let lift_inductive_family n = liftn_inductive_family n 1
+
+let substnl_ind_family l n = map_ind_family (substnl l n)
+
+
+type inductive_type = IndType of inductive_family * constr list
+
+let make_ind_type (indf, realargs) = IndType (indf,realargs)
+let dest_ind_type (IndType (indf,realargs)) = (indf,realargs)
+
+let map_inductive_type f (IndType (indf, realargs)) =
+ IndType (map_ind_family f indf, List.map f realargs)
+
+let liftn_inductive_type n d = map_inductive_type (liftn n d)
+let lift_inductive_type n = liftn_inductive_type n 1
+
+let substnl_ind_type l n = map_inductive_type (substnl l n)
+
+let mkAppliedInd (IndType ((ind,params), realargs)) =
+ applist (mkInd ind,params@realargs)
+
+
+(* Does not consider imbricated or mutually recursive types *)
+let mis_is_recursive_subset listind rarg =
+ let rec one_is_rec rvec =
+ List.exists
+ (fun ra ->
+ match dest_recarg ra with
+ | Mrec i -> List.mem i listind
+ | _ -> false) rvec
+ in
+ array_exists one_is_rec (dest_subterms rarg)
+
+let mis_is_recursive (ind,mib,mip) =
+ mis_is_recursive_subset (interval 0 (mib.mind_ntypes-1))
+ mip.mind_recargs
+
+let mis_nf_constructor_type (ind,mib,mip) j =
+ let specif = mip.mind_nf_lc
+ and ntypes = mib.mind_ntypes
+ and nconstr = Array.length mip.mind_consnames in
+ let make_Ik k = mkInd ((fst ind),ntypes-k-1) in
+ if j > nconstr then error "Not enough constructors in the type";
+ substl (list_tabulate make_Ik ntypes) specif.(j-1)
+
+(* Arity of constructors excluding parameters and local defs *)
+let mis_constr_nargs indsp =
+ let (mib,mip) = Global.lookup_inductive indsp in
+ let recargs = dest_subterms mip.mind_recargs in
+ Array.map List.length recargs
+
+let mis_constr_nargs_env env (kn,i) =
+ let mib = Environ.lookup_mind kn env in
+ let mip = mib.mind_packets.(i) in
+ let recargs = dest_subterms mip.mind_recargs in
+ Array.map List.length recargs
+
+let mis_constructor_nargs_env env ((kn,i),j) =
+ let mib = Environ.lookup_mind kn env in
+ let mip = mib.mind_packets.(i) in
+ recarg_length mip.mind_recargs j + mip.mind_nparams
+
+(* Annotation for cases *)
+let make_case_info env ind style pats_source =
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let print_info =
+ { ind_nargs = mip.mind_nrealargs;
+ style = style;
+ source = pats_source } in
+ { ci_ind = ind;
+ ci_npar = mip.mind_nparams;
+ ci_pp_info = print_info }
+
+let make_default_case_info env style ind =
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ make_case_info env ind style
+ (Array.map (fun _ -> RegularPat) mip.mind_consnames)
+
+(*s Useful functions *)
+
+type constructor_summary = {
+ cs_cstr : constructor;
+ cs_params : constr list;
+ cs_nargs : int;
+ cs_args : rel_context;
+ cs_concl_realargs : constr array
+}
+
+let lift_constructor n cs = {
+ cs_cstr = cs.cs_cstr;
+ cs_params = List.map (lift n) cs.cs_params;
+ cs_nargs = cs.cs_nargs;
+ cs_args = lift_rel_context n cs.cs_args;
+ cs_concl_realargs = Array.map (liftn n (cs.cs_nargs+1)) cs.cs_concl_realargs
+}
+
+let instantiate_params t args sign =
+ let rec inst s t = function
+ | ((_,None,_)::ctxt,a::args) ->
+ (match kind_of_term t with
+ | Prod(_,_,t) -> inst (a::s) t (ctxt,args)
+ | _ -> anomaly"instantiate_params: type, ctxt and args mismatch")
+ | ((_,(Some b),_)::ctxt,args) ->
+ (match kind_of_term t with
+ | LetIn(_,_,_,t) -> inst ((substl s b)::s) t (ctxt,args)
+ | _ -> anomaly"instantiate_params: type, ctxt and args mismatch")
+ | [], [] -> substl s t
+ | _ -> anomaly"instantiate_params: type, ctxt and args mismatch"
+ in inst [] t (List.rev sign,args)
+
+let get_constructor (ind,mib,mip,params) j =
+ assert (j <= Array.length mip.mind_consnames);
+ let typi = mis_nf_constructor_type (ind,mib,mip) j in
+ let typi = instantiate_params typi params mip.mind_params_ctxt in
+ let (args,ccl) = decompose_prod_assum typi in
+ let (_,allargs) = decompose_app ccl in
+ let vargs = list_skipn mip.mind_nparams allargs in
+ { cs_cstr = ith_constructor_of_inductive ind j;
+ cs_params = params;
+ cs_nargs = rel_context_length args;
+ cs_args = args;
+ cs_concl_realargs = Array.of_list vargs }
+
+let get_constructors env (ind,params) =
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ Array.init (Array.length mip.mind_consnames)
+ (fun j -> get_constructor (ind,mib,mip,params) (j+1))
+
+let rec instantiate args c = match kind_of_term c, args with
+ | Prod (_,_,c), a::args -> instantiate args (subst1 a c)
+ | LetIn (_,b,_,c), args -> instantiate args (subst1 b c)
+ | _, [] -> c
+ | _ -> anomaly "too short arity"
+
+let get_arity env (ind,params) =
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let arity = mip.mind_nf_arity in
+ destArity (instantiate params arity)
+
+(* Functions to build standard types related to inductive *)
+let build_dependent_constructor cs =
+ applist
+ (mkConstruct cs.cs_cstr,
+ (List.map (lift cs.cs_nargs) cs.cs_params)
+ @(extended_rel_list 0 cs.cs_args))
+
+let build_dependent_inductive env ((ind, params) as indf) =
+ let arsign,_ = get_arity env indf in
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let nrealargs = mip.mind_nrealargs in
+ applist
+ (mkInd ind,
+ (List.map (lift nrealargs) params)@(extended_rel_list 0 arsign))
+
+(* builds the arity of an elimination predicate in sort [s] *)
+
+let make_arity_signature env dep indf =
+ let (arsign,_) = get_arity env indf in
+ if dep then
+ (* We need names everywhere *)
+ name_context env
+ ((Anonymous,None,build_dependent_inductive env indf)::arsign)
+ (* Costly: would be better to name one for all at definition time *)
+ else
+ (* No need to enforce names *)
+ arsign
+
+let make_arity env dep indf s = mkArity (make_arity_signature env dep indf, s)
+
+(* [p] is the predicate and [cs] a constructor summary *)
+let build_branch_type env dep p cs =
+ let base = appvect (lift cs.cs_nargs p, cs.cs_concl_realargs) in
+ if dep then
+ it_mkProd_or_LetIn_name env
+ (applist (base,[build_dependent_constructor cs]))
+ cs.cs_args
+ else
+ it_mkProd_or_LetIn base cs.cs_args
+
+(**************************************************)
+
+let extract_mrectype t =
+ let (t, l) = decompose_app t in
+ match kind_of_term t with
+ | Ind ind -> (ind, l)
+ | _ -> raise Not_found
+
+let find_mrectype env sigma c =
+ let (t, l) = decompose_app (whd_betadeltaiota env sigma c) in
+ match kind_of_term t with
+ | Ind ind -> (ind, l)
+ | _ -> raise Not_found
+
+let find_rectype env sigma c =
+ let (t, l) = decompose_app (whd_betadeltaiota env sigma c) in
+ match kind_of_term t with
+ | Ind ind ->
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let (par,rargs) = list_chop mip.mind_nparams l in
+ IndType((ind, par),rargs)
+ | _ -> raise Not_found
+
+let find_inductive env sigma c =
+ let (t, l) = decompose_app (whd_betadeltaiota env sigma c) in
+ match kind_of_term t with
+ | Ind ind
+ when (fst (Inductive.lookup_mind_specif env ind)).mind_finite ->
+ (ind, l)
+ | _ -> raise Not_found
+
+let find_coinductive env sigma c =
+ let (t, l) = decompose_app (whd_betadeltaiota env sigma c) in
+ match kind_of_term t with
+ | Ind ind
+ when not (fst (Inductive.lookup_mind_specif env ind)).mind_finite ->
+ (ind, l)
+ | _ -> raise Not_found
+
+
+(***********************************************)
+(* find appropriate names for pattern variables. Useful in the
+ Case tactic. *)
+
+let is_dep_predicate env kelim pred nodep_ar =
+ let rec srec env pval pt nodep_ar =
+ let pt' = whd_betadeltaiota env Evd.empty pt in
+ let pv' = whd_betadeltaiota env Evd.empty pval in
+ match kind_of_term pv', kind_of_term pt', kind_of_term nodep_ar with
+ | Lambda (na,t,b), Prod (_,_,a), Prod (_,_,a') ->
+ srec (push_rel_assum (na,t) env) b a a'
+ | _, Prod (na,t,a), Prod (_,_,a') ->
+ srec (push_rel_assum (na,t) env) (lift 1 pv') a a'
+ | Lambda (_,_,b), Prod (_,_,_), _ -> (*dependent (mkRel 1) b*) true
+ | _, Prod (_,_,_), _ -> true
+ | _ -> false in
+ srec env pred.uj_val pred.uj_type nodep_ar
+
+let is_dependent_elimination_predicate env pred indf =
+ let (ind,params) = indf in
+ let (_,mip) = Inductive.lookup_mind_specif env ind in
+ let kelim = mip.mind_kelim in
+ let arsign,s = get_arity env indf in
+ let glob_t = it_mkProd_or_LetIn (mkSort s) arsign in
+ is_dep_predicate env kelim pred glob_t
+
+let is_dep_arity env kelim predty nodep_ar =
+ let rec srec pt nodep_ar =
+ let pt' = whd_betadeltaiota env Evd.empty pt in
+ match kind_of_term pt', kind_of_term nodep_ar with
+ | Prod (_,a1,a2), Prod (_,a1',a2') -> srec a2 a2'
+ | Prod (_,a1,a2), _ -> true
+ | _ -> false in
+ srec predty nodep_ar
+
+let is_dependent_elimination env predty indf =
+ let (ind,params) = indf in
+ let (_,mip) = Inductive.lookup_mind_specif env ind in
+ let kelim = mip.mind_kelim in
+ let arsign,s = get_arity env indf in
+ let glob_t = it_mkProd_or_LetIn (mkSort s) arsign in
+ is_dep_arity env kelim predty glob_t
+
+let set_names env n brty =
+ let (ctxt,cl) = decompose_prod_n_assum n brty in
+ it_mkProd_or_LetIn_name env cl ctxt
+
+let set_pattern_names env ind brv =
+ let (_,mip) = Inductive.lookup_mind_specif env ind in
+ let arities =
+ Array.map
+ (fun c ->
+ rel_context_length (fst (decompose_prod_assum c)) -
+ mip.mind_nparams)
+ mip.mind_nf_lc in
+ array_map2 (set_names env) arities brv
+
+
+let type_case_branches_with_names env indspec pj c =
+ let (ind,args) = indspec in
+ let (lbrty,conclty,_) = Inductive.type_case_branches env indspec pj c in
+ let (mib,mip) = Inductive.lookup_mind_specif env ind in
+ let params = list_firstn mip.mind_nparams args in
+ if is_dependent_elimination_predicate env pj (ind,params) then
+ (set_pattern_names env ind lbrty, conclty)
+ else (lbrty, conclty)
+
+(* Type of Case predicates *)
+let arity_of_case_predicate env (ind,params) dep k =
+ let arsign,_ = get_arity env (ind,params) in
+ let mind = build_dependent_inductive env (ind,params) in
+ let concl = if dep then mkArrow mind (mkSort k) else mkSort k in
+ it_mkProd_or_LetIn concl arsign
+
+(***********************************************)
+(* Guard condition *)
+
+(* A function which checks that a term well typed verifies both
+ syntactic conditions *)
+
+let control_only_guard env =
+ let rec control_rec c = match kind_of_term c with
+ | Rel _ | Var _ -> ()
+ | Sort _ | Meta _ -> ()
+ | Ind _ -> ()
+ | Construct _ -> ()
+ | Const _ -> ()
+ | CoFix (_,(_,tys,bds) as cofix) ->
+ Inductive.check_cofix env cofix;
+ Array.iter control_rec tys;
+ Array.iter control_rec bds;
+ | Fix (_,(_,tys,bds) as fix) ->
+ Inductive.check_fix env fix;
+ Array.iter control_rec tys;
+ Array.iter control_rec bds;
+ | Case(_,p,c,b) ->control_rec p;control_rec c;Array.iter control_rec b
+ | Evar (_,cl) -> Array.iter control_rec cl
+ | App (_,cl) -> Array.iter control_rec cl
+ | Cast (c1,c2) -> control_rec c1; control_rec c2
+ | Prod (_,c1,c2) -> control_rec c1; control_rec c2
+ | Lambda (_,c1,c2) -> control_rec c1; control_rec c2
+ | LetIn (_,c1,c2,c3) -> control_rec c1; control_rec c2; control_rec c3
+ in
+ control_rec
diff --git a/pretyping/inductiveops.mli b/pretyping/inductiveops.mli
new file mode 100644
index 00000000..a8dcef29
--- /dev/null
+++ b/pretyping/inductiveops.mli
@@ -0,0 +1,93 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: inductiveops.mli,v 1.10.2.1 2004/07/16 19:30:45 herbelin Exp $ *)
+
+open Names
+open Term
+open Declarations
+open Environ
+open Evd
+
+(* An inductive type with its parameters *)
+type inductive_family
+val make_ind_family : inductive * constr list -> inductive_family
+val dest_ind_family : inductive_family -> inductive * constr list
+val map_ind_family : (constr -> constr) -> inductive_family -> inductive_family
+val liftn_inductive_family : int -> int -> inductive_family -> inductive_family
+val lift_inductive_family : int -> inductive_family -> inductive_family
+val substnl_ind_family :
+ constr list -> int -> inductive_family -> inductive_family
+
+(* An inductive type with its parameters and real arguments *)
+type inductive_type = IndType of inductive_family * constr list
+val make_ind_type : inductive_family * constr list -> inductive_type
+val dest_ind_type : inductive_type -> inductive_family * constr list
+val map_inductive_type : (constr -> constr) -> inductive_type -> inductive_type
+val liftn_inductive_type : int -> int -> inductive_type -> inductive_type
+val lift_inductive_type : int -> inductive_type -> inductive_type
+val substnl_ind_type :
+ constr list -> int -> inductive_type -> inductive_type
+
+val mkAppliedInd : inductive_type -> constr
+val mis_is_recursive_subset : int list -> wf_paths -> bool
+val mis_is_recursive :
+ inductive * mutual_inductive_body * one_inductive_body -> bool
+val mis_nf_constructor_type :
+ inductive * mutual_inductive_body * one_inductive_body -> int -> constr
+val mis_constr_nargs : inductive -> int array
+
+val mis_constr_nargs_env : env -> inductive -> int array
+
+val mis_constructor_nargs_env : env -> constructor -> int
+
+type constructor_summary = {
+ cs_cstr : constructor;
+ cs_params : constr list;
+ cs_nargs : int;
+ cs_args : Sign.rel_context;
+ cs_concl_realargs : constr array;
+}
+val lift_constructor : int -> constructor_summary -> constructor_summary
+val get_constructor :
+ inductive * mutual_inductive_body * one_inductive_body * constr list ->
+ int -> constructor_summary
+val get_arity : env -> inductive_family -> Sign.arity
+val get_constructors : env -> inductive_family -> constructor_summary array
+val build_dependent_constructor : constructor_summary -> constr
+val build_dependent_inductive : env -> inductive_family -> constr
+val make_arity_signature :
+ env -> bool -> inductive_family -> Sign.rel_context
+val make_arity : env -> bool -> inductive_family -> sorts -> types
+val build_branch_type : env -> bool -> constr -> constructor_summary -> types
+
+(* Raise Not_found if not given an valid inductive type *)
+val extract_mrectype : constr -> inductive * constr list
+val find_mrectype : env -> evar_map -> constr -> inductive * constr list
+val find_rectype : env -> evar_map -> constr -> inductive_type
+val find_inductive : env -> evar_map -> constr -> inductive * constr list
+val find_coinductive : env -> evar_map -> constr -> inductive * constr list
+
+(********************)
+(* Determines if a case predicate type corresponds to dependent elimination *)
+val is_dependent_elimination :
+ env -> types -> inductive_family -> bool
+
+(* Builds the case predicate arity (dependent or not) *)
+val arity_of_case_predicate :
+ env -> inductive_family -> bool -> sorts -> types
+
+val type_case_branches_with_names :
+ env -> inductive * constr list -> unsafe_judgment -> constr ->
+ types array * types
+val make_case_info :
+ env -> inductive -> case_style -> pattern_source array -> case_info
+val make_default_case_info : env -> case_style -> inductive -> case_info
+
+(********************)
+val control_only_guard : env -> types -> unit
diff --git a/pretyping/instantiate.ml b/pretyping/instantiate.ml
new file mode 100644
index 00000000..702cdfea
--- /dev/null
+++ b/pretyping/instantiate.ml
@@ -0,0 +1,68 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: instantiate.ml,v 1.3.2.1 2004/07/16 19:30:45 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Term
+open Sign
+open Evd
+open Declarations
+open Environ
+
+let is_id_inst inst =
+ let is_id (id,c) = match kind_of_term c with
+ | Var id' -> id = id'
+ | _ -> false
+ in
+ List.for_all is_id inst
+
+(* Vérifier que les instances des let-in sont compatibles ?? *)
+let instantiate_sign_including_let sign args =
+ let rec instrec = function
+ | ((id,b,_) :: sign, c::args) -> (id,c) :: (instrec (sign,args))
+ | ([],[]) -> []
+ | ([],_) | (_,[]) ->
+ anomaly "Signature and its instance do not match"
+ in
+ instrec (sign,args)
+
+let instantiate_evar sign c args =
+ let inst = instantiate_sign_including_let sign args in
+ if is_id_inst inst then
+ c
+ else
+ replace_vars inst c
+
+(* Existentials. *)
+
+let existential_type sigma (n,args) =
+ let info =
+ try Evd.map sigma n
+ with Not_found ->
+ anomaly ("Evar "^(string_of_existential n)^" was not declared") in
+ let hyps = info.evar_hyps in
+ instantiate_evar hyps info.evar_concl (Array.to_list args)
+
+exception NotInstantiatedEvar
+
+let existential_value sigma (n,args) =
+ let info = Evd.map sigma n in
+ let hyps = info.evar_hyps in
+ match evar_body info with
+ | Evar_defined c ->
+ instantiate_evar hyps c (Array.to_list args)
+ | Evar_empty ->
+ raise NotInstantiatedEvar
+
+let existential_opt_value sigma ev =
+ try Some (existential_value sigma ev)
+ with NotInstantiatedEvar -> None
+
diff --git a/pretyping/instantiate.mli b/pretyping/instantiate.mli
new file mode 100644
index 00000000..44c4d579
--- /dev/null
+++ b/pretyping/instantiate.mli
@@ -0,0 +1,25 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: instantiate.mli,v 1.2.14.1 2004/07/16 19:30:45 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Evd
+open Sign
+open Environ
+(*i*)
+
+(*s [existential_value sigma ev] raises [NotInstantiatedEvar] if [ev] has
+no body and [Not_found] if it does not exist in [sigma] *)
+
+exception NotInstantiatedEvar
+val existential_value : evar_map -> existential -> constr
+val existential_type : evar_map -> existential -> types
+val existential_opt_value : evar_map -> existential -> constr option
diff --git a/pretyping/matching.ml b/pretyping/matching.ml
new file mode 100644
index 00000000..bdab3b5b
--- /dev/null
+++ b/pretyping/matching.ml
@@ -0,0 +1,254 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: matching.ml,v 1.3.2.1 2004/07/16 19:30:45 herbelin Exp $ *)
+
+(*i*)
+open Util
+open Names
+open Libnames
+open Nameops
+open Termops
+open Reductionops
+open Term
+open Rawterm
+open Environ
+open Pattern
+(*i*)
+
+(* Given a term with second-order variables in it,
+ represented by Meta's, and possibly applied using [SOAPP] to
+ terms, this function will perform second-order, binding-preserving,
+ matching, in the case where the pattern is a pattern in the sense
+ of Dale Miller.
+
+ ALGORITHM:
+
+ Given a pattern, we decompose it, flattening Cast's and apply's,
+ recursing on all operators, and pushing the name of the binder each
+ time we descend a binder.
+
+ When we reach a first-order variable, we ask that the corresponding
+ term's free-rels all be higher than the depth of the current stack.
+
+ When we reach a second-order application, we ask that the
+ intersection of the free-rels of the term and the current stack be
+ contained in the arguments of the application, and in that case, we
+ construct a LAMBDA with the names on the stack.
+
+ *)
+
+exception PatternMatchingFailure
+
+let constrain (n,m) sigma =
+ if List.mem_assoc n sigma then
+ if eq_constr m (List.assoc n sigma) then sigma
+ else raise PatternMatchingFailure
+ else
+ (n,m)::sigma
+
+let build_lambda toabstract stk (m : constr) =
+ let rec buildrec m p_0 p_1 = match p_0,p_1 with
+ | (_, []) -> m
+ | (n, (na,t)::tl) ->
+ if List.mem n toabstract then
+ buildrec (mkLambda (na,t,m)) (n+1) tl
+ else
+ buildrec (lift (-1) m) (n+1) tl
+ in
+ buildrec m 1 stk
+
+let memb_metavars m n =
+ match (m,n) with
+ | (None, _) -> true
+ | (Some mvs, n) -> List.mem n mvs
+
+let eq_context ctxt1 ctxt2 = array_for_all2 eq_constr ctxt1 ctxt2
+
+let matches_core convert allow_partial_app pat c =
+ let rec sorec stk sigma p t =
+ let cT = strip_outer_cast t in
+ match p,kind_of_term cT with
+ | PSoApp (n,args),m ->
+ let relargs =
+ List.map
+ (function
+ | PRel n -> n
+ | _ -> error "Only bound indices are currently allowed in second order pattern matching")
+ args in
+ let frels = Intset.elements (free_rels cT) in
+ if list_subset frels relargs then
+ constrain (n,build_lambda relargs stk cT) sigma
+ else
+ raise PatternMatchingFailure
+
+ | PMeta (Some n), m ->
+ let depth = List.length stk in
+ let frels = Intset.elements (free_rels cT) in
+ if List.for_all (fun i -> i > depth) frels then
+ constrain (n,lift (-depth) cT) sigma
+ else
+ raise PatternMatchingFailure
+
+ | PMeta None, m -> sigma
+
+ | PRef (VarRef v1), Var v2 when v1 = v2 -> sigma
+
+ | PVar v1, Var v2 when v1 = v2 -> sigma
+
+ | PRef ref, _ when constr_of_reference ref = cT -> sigma
+
+ | PRel n1, Rel n2 when n1 = n2 -> sigma
+
+ | PSort (RProp c1), Sort (Prop c2) when c1 = c2 -> sigma
+
+ | PSort (RType _), Sort (Type _) -> sigma
+
+ | PApp (PMeta (Some n),args1), App (c2,args2) when allow_partial_app ->
+ let p = Array.length args2 - Array.length args1 in
+ if p>=0 then
+ let args21, args22 = array_chop p args2 in
+ let sigma =
+ let depth = List.length stk in
+ let c = mkApp(c2,args21) in
+ let frels = Intset.elements (free_rels c) in
+ if List.for_all (fun i -> i > depth) frels then
+ constrain (n,lift (-depth) c) sigma
+ else
+ raise PatternMatchingFailure in
+ array_fold_left2 (sorec stk) sigma args1 args22
+ else raise PatternMatchingFailure
+
+ | PApp (c1,arg1), App (c2,arg2) ->
+ (try array_fold_left2 (sorec stk) (sorec stk sigma c1 c2) arg1 arg2
+ with Invalid_argument _ -> raise PatternMatchingFailure)
+
+ | PProd (na1,c1,d1), Prod(na2,c2,d2) ->
+ sorec ((na2,c2)::stk) (sorec stk sigma c1 c2) d1 d2
+
+ | PLambda (na1,c1,d1), Lambda(na2,c2,d2) ->
+ sorec ((na2,c2)::stk) (sorec stk sigma c1 c2) d1 d2
+
+ | PLetIn (na1,c1,d1), LetIn(na2,c2,t2,d2) ->
+ sorec ((na2,t2)::stk) (sorec stk sigma c1 c2) d1 d2
+
+ | PRef (ConstRef _ as ref), _ when convert <> None ->
+ let (env,evars) = out_some convert in
+ let c = constr_of_reference ref in
+ if is_conv env evars c cT then sigma
+ else raise PatternMatchingFailure
+
+ | PCase (_,_,a1,br1), Case (_,_,a2,br2) ->
+ (* On ne teste pas le prédicat *)
+ if (Array.length br1) = (Array.length br2) then
+ array_fold_left2 (sorec stk) (sorec stk sigma a1 a2) br1 br2
+ else
+ raise PatternMatchingFailure
+ (* À faire *)
+ | PFix f0, Fix f1 when f0 = f1 -> sigma
+ | PCoFix c0, CoFix c1 when c0 = c1 -> sigma
+ | _ -> raise PatternMatchingFailure
+
+ in
+ Sort.list (fun (a,_) (b,_) -> a<b) (sorec [] [] pat c)
+
+let matches = matches_core None false
+
+let pmatches = matches_core None true
+
+(* To skip to the next occurrence *)
+exception NextOccurrence of int
+
+(* Tells if it is an authorized occurrence and if the instance is closed *)
+let authorized_occ nocc mres =
+ if not (List.for_all (fun (_,c) -> closed0 c) (fst mres)) then
+ raise PatternMatchingFailure;
+ if nocc = 0 then mres
+ else raise (NextOccurrence nocc)
+
+let special_meta = (-1)
+
+(* Tries to match a subterm of [c] with [pat] *)
+let rec sub_match nocc pat c =
+ match kind_of_term c with
+ | Cast (c1,c2) ->
+ (try authorized_occ nocc ((matches pat c), mkMeta special_meta) with
+ | PatternMatchingFailure ->
+ let (lm,lc) = try_sub_match nocc pat [c1] in
+ (lm,mkCast (List.hd lc, c2))
+ | NextOccurrence nocc ->
+ let (lm,lc) = try_sub_match (nocc - 1) pat [c1] in
+ (lm,mkCast (List.hd lc, c2)))
+ | Lambda (x,c1,c2) ->
+ (try authorized_occ nocc ((matches pat c), mkMeta special_meta) with
+ | PatternMatchingFailure ->
+ let (lm,lc) = try_sub_match nocc pat [c1;c2] in
+ (lm,mkLambda (x,List.hd lc,List.nth lc 1))
+ | NextOccurrence nocc ->
+ let (lm,lc) = try_sub_match (nocc - 1) pat [c1;c2] in
+ (lm,mkLambda (x,List.hd lc,List.nth lc 1)))
+ | Prod (x,c1,c2) ->
+ (try authorized_occ nocc ((matches pat c), mkMeta special_meta) with
+ | PatternMatchingFailure ->
+ let (lm,lc) = try_sub_match nocc pat [c1;c2] in
+ (lm,mkProd (x,List.hd lc,List.nth lc 1))
+ | NextOccurrence nocc ->
+ let (lm,lc) = try_sub_match (nocc - 1) pat [c1;c2] in
+ (lm,mkProd (x,List.hd lc,List.nth lc 1)))
+ | LetIn (x,c1,t2,c2) ->
+ (try authorized_occ nocc ((matches pat c), mkMeta special_meta) with
+ | PatternMatchingFailure ->
+ let (lm,lc) = try_sub_match nocc pat [c1;t2;c2] in
+ (lm,mkLetIn (x,List.hd lc,List.nth lc 1,List.nth lc 2))
+ | NextOccurrence nocc ->
+ let (lm,lc) = try_sub_match (nocc - 1) pat [c1;t2;c2] in
+ (lm,mkLetIn (x,List.hd lc,List.nth lc 1,List.nth lc 2)))
+ | App (c1,lc) ->
+ (try authorized_occ nocc ((matches pat c), mkMeta special_meta) with
+ | PatternMatchingFailure ->
+ let (lm,le) = try_sub_match nocc pat (c1::(Array.to_list lc)) in
+ (lm,mkApp (List.hd le, Array.of_list (List.tl le)))
+ | NextOccurrence nocc ->
+ let (lm,le) = try_sub_match (nocc - 1) pat (c1::(Array.to_list lc)) in
+ (lm,mkApp (List.hd le, Array.of_list (List.tl le))))
+ | Case (ci,hd,c1,lc) ->
+ (try authorized_occ nocc ((matches pat c), mkMeta special_meta) with
+ | PatternMatchingFailure ->
+ let (lm,le) = try_sub_match nocc pat (c1::Array.to_list lc) in
+ (lm,mkCase (ci,hd,List.hd le,Array.of_list (List.tl le)))
+ | NextOccurrence nocc ->
+ let (lm,le) = try_sub_match (nocc - 1) pat (c1::Array.to_list lc) in
+ (lm,mkCase (ci,hd,List.hd le,Array.of_list (List.tl le))))
+ | Construct _ | Fix _ | Ind _|CoFix _ |Evar _|Const _
+ | Rel _|Meta _|Var _|Sort _ ->
+ (try authorized_occ nocc ((matches pat c),mkMeta special_meta) with
+ | PatternMatchingFailure -> raise (NextOccurrence nocc)
+ | NextOccurrence nocc -> raise (NextOccurrence (nocc - 1)))
+
+(* Tries [sub_match] for all terms in the list *)
+and try_sub_match nocc pat lc =
+ let rec try_sub_match_rec nocc pat lacc = function
+ | [] -> raise (NextOccurrence nocc)
+ | c::tl ->
+ (try
+ let (lm,ce) = sub_match nocc pat c in
+ (lm,lacc@(ce::tl))
+ with
+ | NextOccurrence nocc -> try_sub_match_rec nocc pat (lacc@[c]) tl) in
+ try_sub_match_rec nocc pat [] lc
+
+let is_matching pat n =
+ try let _ = matches pat n in true
+ with PatternMatchingFailure -> false
+
+let matches_conv env sigma = matches_core (Some (env,sigma)) false
+
+let is_matching_conv env sigma pat n =
+ try let _ = matches_conv env sigma pat n in true
+ with PatternMatchingFailure -> false
+
diff --git a/pretyping/matching.mli b/pretyping/matching.mli
new file mode 100644
index 00000000..808c46a4
--- /dev/null
+++ b/pretyping/matching.mli
@@ -0,0 +1,52 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: matching.mli,v 1.3.2.1 2004/07/16 19:30:45 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Environ
+open Pattern
+open Termops
+(*i*)
+
+(*s This modules implements pattern-matching on terms *)
+
+exception PatternMatchingFailure
+
+val special_meta : metavariable
+
+(* [matches pat c] matches [c] against [pat] and returns the resulting
+ assignment of metavariables; it raises [PatternMatchingFailure] if
+ not matchable; bindings are given in increasing order based on the
+ numbers given in the pattern *)
+val matches : constr_pattern -> constr -> patvar_map
+
+(* [is_matching pat c] just tells if [c] matches against [pat] *)
+
+val is_matching : constr_pattern -> constr -> bool
+
+(* [matches_conv env sigma] matches up to conversion in environment
+ [(env,sigma)] when constants in pattern are concerned; it raises
+ [PatternMatchingFailure] if not matchable; bindings are given in
+ increasing order based on the numbers given in the pattern *)
+
+val matches_conv :env -> Evd.evar_map -> constr_pattern -> constr -> patvar_map
+
+(* To skip to the next occurrence *)
+exception NextOccurrence of int
+
+(* Tries to match a _closed_ subterm of [c] with [pat] *)
+val sub_match : int -> constr_pattern -> constr -> patvar_map * constr
+
+(* [is_matching_conv env sigma pat c] tells if [c] matches against [pat]
+ up to conversion for constants in patterns *)
+
+val is_matching_conv :
+ env -> Evd.evar_map -> constr_pattern -> constr -> bool
diff --git a/pretyping/pattern.ml b/pretyping/pattern.ml
new file mode 100644
index 00000000..80ab1b6e
--- /dev/null
+++ b/pretyping/pattern.ml
@@ -0,0 +1,287 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: pattern.ml,v 1.24.2.1 2004/07/16 19:30:45 herbelin Exp $ *)
+
+open Util
+open Names
+open Libnames
+open Nameops
+open Term
+open Rawterm
+open Environ
+open Nametab
+open Pp
+
+(* Metavariables *)
+
+type patvar_map = (patvar * constr) list
+let patvar_of_int n =
+ let p = if !Options.v7 & not (Options.do_translate ()) then "?" else "X"
+ in
+ Names.id_of_string (p ^ string_of_int n)
+let pr_patvar = pr_id
+
+let patvar_of_int_v7 n = Names.id_of_string ("?" ^ string_of_int n)
+
+(* Patterns *)
+
+type constr_pattern =
+ | PRef of global_reference
+ | PVar of identifier
+ | PEvar of existential_key * constr_pattern array
+ | PRel of int
+ | PApp of constr_pattern * constr_pattern array
+ | PSoApp of patvar * constr_pattern list
+ | PLambda of name * constr_pattern * constr_pattern
+ | PProd of name * constr_pattern * constr_pattern
+ | PLetIn of name * constr_pattern * constr_pattern
+ | PSort of rawsort
+ | PMeta of patvar option
+ | PCase of (inductive option * case_style)
+ * constr_pattern option * constr_pattern * constr_pattern array
+ | PFix of fixpoint
+ | PCoFix of cofixpoint
+
+let rec occur_meta_pattern = function
+ | PApp (f,args) ->
+ (occur_meta_pattern f) or (array_exists occur_meta_pattern args)
+ | PLambda (na,t,c) -> (occur_meta_pattern t) or (occur_meta_pattern c)
+ | PProd (na,t,c) -> (occur_meta_pattern t) or (occur_meta_pattern c)
+ | PLetIn (na,t,c) -> (occur_meta_pattern t) or (occur_meta_pattern c)
+ | PCase(_,None,c,br) ->
+ (occur_meta_pattern c) or (array_exists occur_meta_pattern br)
+ | PCase(_,Some p,c,br) ->
+ (occur_meta_pattern p) or
+ (occur_meta_pattern c) or (array_exists occur_meta_pattern br)
+ | PMeta _ | PSoApp _ -> true
+ | PEvar _ | PVar _ | PRef _ | PRel _ | PSort _ | PFix _ | PCoFix _ -> false
+
+let rec subst_pattern subst pat = match pat with
+ | PRef ref ->
+ let ref' = subst_global subst ref in
+ if ref' == ref then pat else
+ PRef ref'
+ | PVar _
+ | PEvar _
+ | PRel _ -> pat
+ | PApp (f,args) ->
+ let f' = subst_pattern subst f in
+ let args' = array_smartmap (subst_pattern subst) args in
+ if f' == f && args' == args then pat else
+ PApp (f',args')
+ | PSoApp (i,args) ->
+ let args' = list_smartmap (subst_pattern subst) args in
+ if args' == args then pat else
+ PSoApp (i,args')
+ | PLambda (name,c1,c2) ->
+ let c1' = subst_pattern subst c1 in
+ let c2' = subst_pattern subst c2 in
+ if c1' == c1 && c2' == c2 then pat else
+ PLambda (name,c1',c2')
+ | PProd (name,c1,c2) ->
+ let c1' = subst_pattern subst c1 in
+ let c2' = subst_pattern subst c2 in
+ if c1' == c1 && c2' == c2 then pat else
+ PProd (name,c1',c2')
+ | PLetIn (name,c1,c2) ->
+ let c1' = subst_pattern subst c1 in
+ let c2' = subst_pattern subst c2 in
+ if c1' == c1 && c2' == c2 then pat else
+ PLetIn (name,c1',c2')
+ | PSort _
+ | PMeta _ -> pat
+ | PCase (cs,typ, c, branches) ->
+ let typ' = option_smartmap (subst_pattern subst) typ in
+ let c' = subst_pattern subst c in
+ let branches' = array_smartmap (subst_pattern subst) branches in
+ if typ' == typ && c' == c && branches' == branches then pat else
+ PCase(cs,typ', c', branches')
+ | PFix fixpoint ->
+ let cstr = mkFix fixpoint in
+ let fixpoint' = destFix (subst_mps subst cstr) in
+ if fixpoint' == fixpoint then pat else
+ PFix fixpoint'
+ | PCoFix cofixpoint ->
+ let cstr = mkCoFix cofixpoint in
+ let cofixpoint' = destCoFix (subst_mps subst cstr) in
+ if cofixpoint' == cofixpoint then pat else
+ PCoFix cofixpoint'
+
+type constr_label =
+ | ConstNode of constant
+ | IndNode of inductive
+ | CstrNode of constructor
+ | VarNode of identifier
+
+exception BoundPattern;;
+
+let label_of_ref = function
+ | ConstRef sp -> ConstNode sp
+ | IndRef sp -> IndNode sp
+ | ConstructRef sp -> CstrNode sp
+ | VarRef id -> VarNode id
+
+let ref_of_label = function
+ | ConstNode sp -> ConstRef sp
+ | IndNode sp -> IndRef sp
+ | CstrNode sp -> ConstructRef sp
+ | VarNode id -> VarRef id
+
+let subst_label subst cstl =
+ let ref = ref_of_label cstl in
+ let ref' = subst_global subst ref in
+ if ref' == ref then cstl else
+ label_of_ref ref'
+
+
+let rec head_pattern_bound t =
+ match t with
+ | PProd (_,_,b) -> head_pattern_bound b
+ | PLetIn (_,_,b) -> head_pattern_bound b
+ | PApp (c,args) -> head_pattern_bound c
+ | PCase (_,p,c,br) -> head_pattern_bound c
+ | PRef r -> label_of_ref r
+ | PVar id -> VarNode id
+ | PEvar _ | PRel _ | PMeta _ | PSoApp _ | PSort _ | PFix _
+ -> raise BoundPattern
+ (* Perhaps they were arguments, but we don't beta-reduce *)
+ | PLambda _ -> raise BoundPattern
+ | PCoFix _ -> anomaly "head_pattern_bound: not a type"
+
+let head_of_constr_reference c = match kind_of_term c with
+ | Const sp -> ConstNode sp
+ | Construct sp -> CstrNode sp
+ | Ind sp -> IndNode sp
+ | Var id -> VarNode id
+ | _ -> anomaly "Not a rigid reference"
+
+let rec pattern_of_constr t =
+ match kind_of_term t with
+ | Rel n -> PRel n
+ | Meta n -> PMeta (Some (id_of_string (string_of_int n)))
+ | Var id -> PVar id
+ | Sort (Prop c) -> PSort (RProp c)
+ | Sort (Type _) -> PSort (RType None)
+ | Cast (c,_) -> pattern_of_constr c
+ | LetIn (na,c,_,b) -> PLetIn (na,pattern_of_constr c,pattern_of_constr b)
+ | Prod (na,c,b) -> PProd (na,pattern_of_constr c,pattern_of_constr b)
+ | Lambda (na,c,b) -> PLambda (na,pattern_of_constr c,pattern_of_constr b)
+ | App (f,a) -> PApp (pattern_of_constr f,Array.map pattern_of_constr a)
+ | Const sp -> PRef (ConstRef sp)
+ | Ind sp -> PRef (IndRef sp)
+ | Construct sp -> PRef (ConstructRef sp)
+ | Evar (n,ctxt) -> PEvar (n,Array.map pattern_of_constr ctxt)
+ | Case (ci,p,a,br) ->
+ PCase ((Some ci.ci_ind,ci.ci_pp_info.style),
+ Some (pattern_of_constr p),pattern_of_constr a,
+ Array.map pattern_of_constr br)
+ | Fix f -> PFix f
+ | CoFix _ ->
+ error "pattern_of_constr: (co)fix currently not supported"
+
+(* To process patterns, we need a translation without typing at all. *)
+
+let rec inst lvar = function
+ | PVar id as x -> (try List.assoc id lvar with Not_found -> x)
+ | PApp (p,pl) -> PApp (inst lvar p, Array.map (inst lvar) pl)
+ | PSoApp (n,pl) -> PSoApp (n, List.map (inst lvar) pl)
+ | PLambda (n,a,b) -> PLambda (n,inst lvar a,inst lvar b)
+ | PProd (n,a,b) -> PProd (n,inst lvar a,inst lvar b)
+ | PLetIn (n,a,b) -> PLetIn (n,inst lvar a,inst lvar b)
+ | PCase (ci,po,p,pl) ->
+ PCase (ci,option_app (inst lvar) po,inst lvar p,Array.map (inst lvar) pl)
+ (* Non recursive *)
+ | (PEvar _ | PRel _ | PRef _ | PSort _ | PMeta _ as x) -> x
+ (* Bound to terms *)
+ | (PFix _ | PCoFix _ as r) ->
+ error ("Not instantiable pattern")
+
+let instantiate_pattern = inst
+
+let rec pat_of_raw metas vars = function
+ | RVar (_,id) ->
+ (try PRel (list_index (Name id) vars)
+ with Not_found -> PVar id)
+ | RPatVar (_,(false,n)) ->
+ metas := n::!metas; PMeta (Some n)
+ | RRef (_,r) ->
+ PRef r
+ (* Hack pour ne pas réécrire une interprétation complète des patterns*)
+ | RApp (_, RPatVar (_,(true,n)), cl) ->
+ PSoApp (n, List.map (pat_of_raw metas vars) cl)
+ | RApp (_,c,cl) ->
+ PApp (pat_of_raw metas vars c,
+ Array.of_list (List.map (pat_of_raw metas vars) cl))
+ | RLambda (_,na,c1,c2) ->
+ PLambda (na, pat_of_raw metas vars c1,
+ pat_of_raw metas (na::vars) c2)
+ | RProd (_,na,c1,c2) ->
+ PProd (na, pat_of_raw metas vars c1,
+ pat_of_raw metas (na::vars) c2)
+ | RLetIn (_,na,c1,c2) ->
+ PLetIn (na, pat_of_raw metas vars c1,
+ pat_of_raw metas (na::vars) c2)
+ | RSort (_,s) ->
+ PSort s
+ | RHole _ ->
+ PMeta None
+ | RCast (_,c,t) ->
+ Options.if_verbose
+ Pp.warning "Cast not taken into account in constr pattern";
+ pat_of_raw metas vars c
+ | ROrderedCase (_,st,po,c,br,_) ->
+ PCase ((None,st),option_app (pat_of_raw metas vars) po,
+ pat_of_raw metas vars c,
+ Array.map (pat_of_raw metas vars) br)
+ | RIf (_,c,(_,None),b1,b2) ->
+ PCase ((None,IfStyle),None, pat_of_raw metas vars c,
+ [|pat_of_raw metas vars b1; pat_of_raw metas vars b2|])
+ | RCases (loc,(po,_),[c,_],brs) ->
+ let sp =
+ match brs with
+ | (_,_,[PatCstr(_,(ind,_),_,_)],_)::_ -> Some ind
+ | _ -> None in
+ (* When po disappears: switch to rtn type *)
+ PCase ((sp,Term.RegularStyle),option_app (pat_of_raw metas vars) po,
+ pat_of_raw metas vars c,
+ Array.init (List.length brs)
+ (pat_of_raw_branch loc metas vars sp brs))
+ | r ->
+ let loc = loc_of_rawconstr r in
+ user_err_loc (loc,"pattern_of_rawconstr", Pp.str "Not supported pattern")
+
+and pat_of_raw_branch loc metas vars ind brs i =
+ let bri = List.filter
+ (function
+ (_,_,[PatCstr(_,c,lv,_)],_) -> snd c = i+1
+ | (loc,_,_,_) ->
+ user_err_loc (loc,"pattern_of_rawconstr",
+ Pp.str "Not supported pattern")) brs in
+ match bri with
+ [(_,_,[PatCstr(_,(indsp,_),lv,_)],br)] ->
+ if ind <> None & ind <> Some indsp then
+ user_err_loc (loc,"pattern_of_rawconstr",
+ Pp.str "All constructors must be in the same inductive type");
+ let lna =
+ List.map
+ (function PatVar(_,na) -> na
+ | PatCstr(loc,_,_,_) ->
+ user_err_loc (loc,"pattern_of_rawconstr",
+ Pp.str "Not supported pattern")) lv in
+ let vars' = List.rev lna @ vars in
+ List.fold_right (fun na b -> PLambda(na,PMeta None,b)) lna
+ (pat_of_raw metas vars' br)
+ | _ -> user_err_loc (loc,"pattern_of_rawconstr",
+ str "No unique branch for " ++ int (i+1) ++
+ str"-th constructor")
+
+let pattern_of_rawconstr c =
+ let metas = ref [] in
+ let p = pat_of_raw metas [] c in
+ (!metas,p)
diff --git a/pretyping/pattern.mli b/pretyping/pattern.mli
new file mode 100644
index 00000000..cf0d4528
--- /dev/null
+++ b/pretyping/pattern.mli
@@ -0,0 +1,91 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: pattern.mli,v 1.17.2.1 2004/07/16 19:30:45 herbelin Exp $ i*)
+
+(*i*)
+open Pp
+open Names
+open Sign
+open Term
+open Environ
+open Libnames
+open Nametab
+open Rawterm
+(*i*)
+
+(* Pattern variables *)
+
+type patvar_map = (patvar * constr) list
+val pr_patvar : patvar -> std_ppcmds
+
+(* Only for v7 parsing/printing *)
+val patvar_of_int : int -> patvar
+val patvar_of_int_v7 : int -> patvar
+
+(* Patterns *)
+
+type constr_pattern =
+ | PRef of global_reference
+ | PVar of identifier
+ | PEvar of existential_key * constr_pattern array
+ | PRel of int
+ | PApp of constr_pattern * constr_pattern array
+ | PSoApp of patvar * constr_pattern list
+ | PLambda of name * constr_pattern * constr_pattern
+ | PProd of name * constr_pattern * constr_pattern
+ | PLetIn of name * constr_pattern * constr_pattern
+ | PSort of rawsort
+ | PMeta of patvar option
+ | PCase of (inductive option * case_style)
+ * constr_pattern option * constr_pattern * constr_pattern array
+ | PFix of fixpoint
+ | PCoFix of cofixpoint
+
+val occur_meta_pattern : constr_pattern -> bool
+
+val subst_pattern : substitution -> constr_pattern -> constr_pattern
+
+type constr_label =
+ | ConstNode of constant
+ | IndNode of inductive
+ | CstrNode of constructor
+ | VarNode of identifier
+
+val label_of_ref : global_reference -> constr_label
+
+val subst_label : substitution -> constr_label -> constr_label
+
+exception BoundPattern
+
+(* [head_pattern_bound t] extracts the head variable/constant of the
+ type [t] or raises [BoundPattern] (even if a sort); it raises an anomaly
+ if [t] is an abstraction *)
+
+val head_pattern_bound : constr_pattern -> constr_label
+
+(* [head_of_constr_reference c] assumes [r] denotes a reference and
+ returns its label; raises an anomaly otherwise *)
+
+val head_of_constr_reference : Term.constr -> constr_label
+
+(* [pattern_of_constr c] translates a term [c] with metavariables into
+ a pattern; currently, no destructor (Cases, Fix, Cofix) and no
+ existential variable are allowed in [c] *)
+
+val pattern_of_constr : constr -> constr_pattern
+
+(* [pattern_of_rawconstr l c] translates a term [c] with metavariables into
+ a pattern; variables bound in [l] are replaced by the pattern to which they
+ are bound *)
+
+val pattern_of_rawconstr : rawconstr ->
+ patvar list * constr_pattern
+
+val instantiate_pattern :
+ (identifier * constr_pattern) list -> constr_pattern -> constr_pattern
diff --git a/pretyping/pretype_errors.ml b/pretyping/pretype_errors.ml
new file mode 100644
index 00000000..fee1522f
--- /dev/null
+++ b/pretyping/pretype_errors.ml
@@ -0,0 +1,164 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: pretype_errors.ml,v 1.25.2.2 2004/07/16 19:30:45 herbelin Exp $ *)
+
+open Util
+open Stdpp
+open Names
+open Sign
+open Term
+open Termops
+open Environ
+open Type_errors
+open Rawterm
+open Inductiveops
+
+type pretype_error =
+ (* Old Case *)
+ | CantFindCaseType of constr
+ (* Unification *)
+ | OccurCheck of existential_key * constr
+ | NotClean of existential_key * constr * hole_kind
+ | UnsolvableImplicit of hole_kind
+ (* Pretyping *)
+ | VarNotFound of identifier
+ | UnexpectedType of constr * constr
+ | NotProduct of constr
+
+exception PretypeError of env * pretype_error
+
+let nf_evar = Reductionops.nf_evar
+let j_nf_evar sigma j =
+ { uj_val = nf_evar sigma j.uj_val;
+ uj_type = nf_evar sigma j.uj_type }
+let jl_nf_evar sigma jl = List.map (j_nf_evar sigma) jl
+let jv_nf_evar sigma = Array.map (j_nf_evar sigma)
+let tj_nf_evar sigma {utj_val=v;utj_type=t} =
+ {utj_val=type_app (nf_evar sigma) v;utj_type=t}
+
+let env_ise sigma env =
+ let sign = named_context env in
+ let ctxt = rel_context env in
+ let env0 = reset_with_named_context sign env in
+ Sign.fold_rel_context
+ (fun (na,b,ty) e ->
+ push_rel
+ (na, option_app (nf_evar sigma) b, nf_evar sigma ty)
+ e)
+ ctxt
+ ~init:env0
+
+(* This simplify the typing context of Cases clauses *)
+(* hope it does not disturb other typing contexts *)
+let contract env lc =
+ let l = ref [] in
+ let contract_context (na,c,t) env =
+ match c with
+ | Some c' when isRel c' ->
+ l := (substl !l c') :: !l;
+ env
+ | _ ->
+ let t' = substl !l t in
+ let c' = option_app (substl !l) c in
+ let na' = named_hd env t' na in
+ l := (mkRel 1) :: List.map (lift 1) !l;
+ push_rel (na',c',t') env in
+ let env = process_rel_context contract_context env in
+ (env, List.map (substl !l) lc)
+
+let contract2 env a b = match contract env [a;b] with
+ | env, [a;b] -> env,a,b | _ -> assert false
+
+let contract3 env a b c = match contract env [a;b;c] with
+ | env, [a;b;c] -> env,a,b,c | _ -> assert false
+
+let raise_pretype_error (loc,ctx,sigma,te) =
+ Stdpp.raise_with_loc loc (PretypeError(env_ise sigma ctx,te))
+
+let raise_located_type_error (loc,ctx,sigma,te) =
+ Stdpp.raise_with_loc loc (TypeError(env_ise sigma ctx,te))
+
+
+let error_actual_type_loc loc env sigma {uj_val=c;uj_type=actty} expty =
+ let env, c, actty, expty = contract3 env c actty expty in
+ let j = j_nf_evar sigma {uj_val=c;uj_type=actty} in
+ raise_located_type_error
+ (loc, env, sigma, ActualType (j, nf_evar sigma expty))
+
+let error_cant_apply_not_functional_loc loc env sigma rator randl =
+ let ja = Array.of_list (jl_nf_evar sigma randl) in
+ raise_located_type_error
+ (loc, env, sigma,
+ CantApplyNonFunctional (j_nf_evar sigma rator, ja))
+
+let error_cant_apply_bad_type_loc loc env sigma (n,c,t) rator randl =
+ let ja = Array.of_list (jl_nf_evar sigma randl) in
+ raise_located_type_error
+ (loc, env, sigma,
+ CantApplyBadType
+ ((n,nf_evar sigma c, nf_evar sigma t),
+ j_nf_evar sigma rator, ja))
+
+let error_ill_formed_branch_loc loc env sigma c i actty expty =
+ let simp t = Reduction.nf_betaiota (nf_evar sigma t) in
+ raise_located_type_error
+ (loc, env, sigma,
+ IllFormedBranch (nf_evar sigma c,i,simp actty, simp expty))
+
+let error_number_branches_loc loc env sigma cj expn =
+ raise_located_type_error
+ (loc, env, sigma,
+ NumberBranches (j_nf_evar sigma cj, expn))
+
+let error_case_not_inductive_loc loc env sigma cj =
+ raise_located_type_error
+ (loc, env, sigma, CaseNotInductive (j_nf_evar sigma cj))
+
+let error_ill_typed_rec_body_loc loc env sigma i na jl tys =
+ raise_located_type_error
+ (loc, env, sigma,
+ IllTypedRecBody (i,na,jv_nf_evar sigma jl,
+ Array.map (nf_evar sigma) tys))
+
+(*s Implicit arguments synthesis errors. It is hard to find
+ a precise location. *)
+
+let error_occur_check env sigma ev c =
+ let c = nf_evar sigma c in
+ raise (PretypeError (env_ise sigma env, OccurCheck (ev,c)))
+
+let error_not_clean env sigma ev c (loc,k) =
+ let c = nf_evar sigma c in
+ raise_with_loc loc
+ (PretypeError (env_ise sigma env, NotClean (ev,c,k)))
+
+let error_unsolvable_implicit loc env sigma e =
+ raise_with_loc loc (PretypeError (env_ise sigma env, UnsolvableImplicit e))
+
+(*s Ml Case errors *)
+
+let error_cant_find_case_type_loc loc env sigma expr =
+ raise_pretype_error
+ (loc, env, sigma, CantFindCaseType (nf_evar sigma expr))
+
+(*s Pretyping errors *)
+
+let error_unexpected_type_loc loc env sigma actty expty =
+ let env, actty, expty = contract2 env actty expty in
+ raise_pretype_error
+ (loc, env, sigma,
+ UnexpectedType (nf_evar sigma actty, nf_evar sigma expty))
+
+let error_not_product_loc loc env sigma c =
+ raise_pretype_error (loc, env, sigma, NotProduct (nf_evar sigma c))
+
+(*s Error in conversion from AST to rawterms *)
+
+let error_var_not_found_loc loc s =
+ raise_pretype_error (loc, empty_env, Evd.empty, VarNotFound s)
diff --git a/pretyping/pretype_errors.mli b/pretyping/pretype_errors.mli
new file mode 100644
index 00000000..ebeff99d
--- /dev/null
+++ b/pretyping/pretype_errors.mli
@@ -0,0 +1,100 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: pretype_errors.mli,v 1.25.2.3 2004/07/16 19:30:45 herbelin Exp $ i*)
+
+(*i*)
+open Pp
+open Util
+open Names
+open Term
+open Sign
+open Environ
+open Rawterm
+open Inductiveops
+(*i*)
+
+(*s The type of errors raised by the pretyper *)
+
+type pretype_error =
+ (* Old Case *)
+ | CantFindCaseType of constr
+ (* Unification *)
+ | OccurCheck of existential_key * constr
+ | NotClean of existential_key * constr * hole_kind
+ | UnsolvableImplicit of hole_kind
+ (* Pretyping *)
+ | VarNotFound of identifier
+ | UnexpectedType of constr * constr
+ | NotProduct of constr
+
+exception PretypeError of env * pretype_error
+
+(* Presenting terms without solved evars *)
+val nf_evar : Evd.evar_map -> constr -> constr
+val j_nf_evar : Evd.evar_map -> unsafe_judgment -> unsafe_judgment
+val jl_nf_evar :
+ Evd.evar_map -> unsafe_judgment list -> unsafe_judgment list
+val jv_nf_evar :
+ Evd.evar_map -> unsafe_judgment array -> unsafe_judgment array
+val tj_nf_evar :
+ Evd.evar_map -> unsafe_type_judgment -> unsafe_type_judgment
+
+
+(* Raising errors *)
+val error_actual_type_loc :
+ loc -> env -> Evd.evar_map -> unsafe_judgment -> constr -> 'b
+
+val error_cant_apply_not_functional_loc :
+ loc -> env -> Evd.evar_map ->
+ unsafe_judgment -> unsafe_judgment list -> 'b
+
+val error_cant_apply_bad_type_loc :
+ loc -> env -> Evd.evar_map -> int * constr * constr ->
+ unsafe_judgment -> unsafe_judgment list -> 'b
+
+val error_case_not_inductive_loc :
+ loc -> env -> Evd.evar_map -> unsafe_judgment -> 'b
+
+val error_ill_formed_branch_loc :
+ loc -> env -> Evd.evar_map ->
+ constr -> int -> constr -> constr -> 'b
+
+val error_number_branches_loc :
+ loc -> env -> Evd.evar_map ->
+ unsafe_judgment -> int -> 'b
+
+val error_ill_typed_rec_body_loc :
+ loc -> env -> Evd.evar_map ->
+ int -> name array -> unsafe_judgment array -> types array -> 'b
+
+(*s Implicit arguments synthesis errors *)
+
+val error_occur_check : env -> Evd.evar_map -> existential_key -> constr -> 'b
+
+val error_not_clean :
+ env -> Evd.evar_map -> existential_key -> constr -> loc * hole_kind -> 'b
+
+val error_unsolvable_implicit : loc -> env -> Evd.evar_map -> hole_kind -> 'b
+
+(*s Ml Case errors *)
+
+val error_cant_find_case_type_loc :
+ loc -> env -> Evd.evar_map -> constr -> 'b
+
+(*s Pretyping errors *)
+
+val error_unexpected_type_loc :
+ loc -> env -> Evd.evar_map -> constr -> constr -> 'b
+
+val error_not_product_loc :
+ loc -> env -> Evd.evar_map -> constr -> 'b
+
+(*s Error in conversion from AST to rawterms *)
+
+val error_var_not_found_loc : loc -> identifier -> 'b
diff --git a/pretyping/pretyping.ml b/pretyping/pretyping.ml
new file mode 100644
index 00000000..36df9c8a
--- /dev/null
+++ b/pretyping/pretyping.ml
@@ -0,0 +1,1024 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: pretyping.ml,v 1.123.2.3 2004/07/16 19:30:45 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Sign
+open Evd
+open Term
+open Termops
+open Reductionops
+open Environ
+open Type_errors
+open Typeops
+open Libnames
+open Classops
+open List
+open Recordops
+open Evarutil
+open Pretype_errors
+open Rawterm
+open Evarconv
+open Coercion
+open Pattern
+open Dyn
+
+
+(************************************************************************)
+(* This concerns Cases *)
+open Declarations
+open Inductive
+open Inductiveops
+open Instantiate
+
+let lift_context n l =
+ let k = List.length l in
+ list_map_i (fun i (name,c) -> (name,liftn n (k-i) c)) 0 l
+
+let transform_rec loc env sigma (pj,c,lf) indt =
+ let p = pj.uj_val in
+ let (indf,realargs) = dest_ind_type indt in
+ let (ind,params) = dest_ind_family indf in
+ let (mib,mip) = lookup_mind_specif env ind in
+ let recargs = mip.mind_recargs in
+ let mI = mkInd ind in
+ let ci = make_default_case_info env (if Options.do_translate() then RegularStyle else MatchStyle) ind in
+ let nconstr = Array.length mip.mind_consnames in
+ if Array.length lf <> nconstr then
+ (let cj = {uj_val=c; uj_type=mkAppliedInd indt} in
+ error_number_branches_loc loc env sigma cj nconstr);
+ let tyi = snd ind in
+ if mis_is_recursive_subset [tyi] recargs then
+ let dep =
+ is_dependent_elimination env (nf_evar sigma pj.uj_type) indf in
+ let init_depFvec i = if i = tyi then Some(dep,mkRel 1) else None in
+ let depFvec = Array.init mib.mind_ntypes init_depFvec in
+ (* build now the fixpoint *)
+ let lnames,_ = get_arity env indf in
+ let nar = List.length lnames in
+ let nparams = mip.mind_nparams in
+ let constrs = get_constructors env (lift_inductive_family (nar+2) indf) in
+ let branches =
+ array_map3
+ (fun f t reca ->
+ whd_beta
+ (Indrec.make_rec_branch_arg env sigma
+ (nparams,depFvec,nar+1)
+ f t reca))
+ (Array.map (lift (nar+2)) lf) constrs (dest_subterms recargs)
+ in
+ let deffix =
+ it_mkLambda_or_LetIn_name env
+ (lambda_create env
+ (applist (mI,List.append (List.map (lift (nar+1)) params)
+ (extended_rel_list 0 lnames)),
+ mkCase (ci, lift (nar+2) p, mkRel 1, branches)))
+ (lift_rel_context 1 lnames)
+ in
+ if noccurn 1 deffix then
+ whd_beta (applist (pop deffix,realargs@[c]))
+ else
+ let ind = applist (mI,(List.append
+ (List.map (lift nar) params)
+ (extended_rel_list 0 lnames))) in
+ let typPfix =
+ it_mkProd_or_LetIn_name env
+ (prod_create env
+ (ind,
+ (if dep then
+ let ext_lnames = (Anonymous,None,ind)::lnames in
+ let args = extended_rel_list 0 ext_lnames in
+ whd_beta (applist (lift (nar+1) p, args))
+ else
+ let args = extended_rel_list 1 lnames in
+ whd_beta (applist (lift (nar+1) p, args)))))
+ lnames in
+ let fix =
+ mkFix (([|nar|],0),
+ ([|Name(id_of_string "F")|],[|typPfix|],[|deffix|])) in
+ applist (fix,realargs@[c])
+ else
+ mkCase (ci, p, c, lf)
+
+(************************************************************************)
+
+(* To embed constr in rawconstr *)
+let ((constr_in : constr -> Dyn.t),
+ (constr_out : Dyn.t -> constr)) = create "constr"
+
+let mt_evd = Evd.empty
+
+let vect_lift_type = Array.mapi (fun i t -> type_app (lift i) t)
+
+(* Utilisé pour inférer le prédicat des Cases *)
+(* Semble exagérement fort *)
+(* Faudra préférer une unification entre les types de toutes les clauses *)
+(* et autoriser des ? à rester dans le résultat de l'unification *)
+
+let evar_type_fixpoint loc env isevars lna lar vdefj =
+ let lt = Array.length vdefj in
+ if Array.length lar = lt then
+ for i = 0 to lt-1 do
+ if not (the_conv_x_leq env isevars
+ (vdefj.(i)).uj_type
+ (lift lt lar.(i))) then
+ error_ill_typed_rec_body_loc loc env (evars_of isevars)
+ i lna vdefj lar
+ done
+
+let check_branches_message loc env isevars c (explft,lft) =
+ for i = 0 to Array.length explft - 1 do
+ if not (the_conv_x_leq env isevars lft.(i) explft.(i)) then
+ let sigma = evars_of isevars in
+ error_ill_formed_branch_loc loc env sigma c i lft.(i) explft.(i)
+ done
+
+(* coerce to tycon if any *)
+let inh_conv_coerce_to_tycon loc env isevars j = function
+ | None -> j
+ | Some typ -> inh_conv_coerce_to loc env isevars j typ
+
+let push_rels vars env = List.fold_right push_rel vars env
+
+(*
+let evar_type_case isevars env ct pt lft p c =
+ let (mind,bty,rslty) = type_case_branches env (evars_of isevars) ct pt p c
+ in check_branches_message isevars env (c,ct) (bty,lft); (mind,rslty)
+*)
+
+let strip_meta id = (* For Grammar v7 compatibility *)
+ let s = string_of_id id in
+ if s.[0]='$' then id_of_string (String.sub s 1 (String.length s - 1))
+ else id
+
+let pretype_id loc env (lvar,unbndltacvars) id =
+ let id = strip_meta id in (* May happen in tactics defined by Grammar *)
+ try
+ List.assoc id lvar
+ with Not_found ->
+ try
+ let (n,typ) = lookup_rel_id id (rel_context env) in
+ { uj_val = mkRel n; uj_type = type_app (lift n) typ }
+ with Not_found ->
+ try
+ let (_,_,typ) = lookup_named id env in
+ { uj_val = mkVar id; uj_type = typ }
+ with Not_found ->
+ try (* To build a nicer ltac error message *)
+ match List.assoc id unbndltacvars with
+ | None -> user_err_loc (loc,"",
+ str (string_of_id id ^ " ist not bound to a term"))
+ | Some id0 -> Pretype_errors.error_var_not_found_loc loc id0
+ with Not_found ->
+ error_var_not_found_loc loc id
+
+(* make a dependent predicate from an undependent one *)
+
+let make_dep_of_undep env (IndType (indf,realargs)) pj =
+ let n = List.length realargs in
+ let rec decomp n p =
+ if n=0 then p else
+ match kind_of_term p with
+ | Lambda (_,_,c) -> decomp (n-1) c
+ | _ -> decomp (n-1) (applist (lift 1 p, [mkRel 1]))
+ in
+ let sign,s = decompose_prod_n n pj.uj_type in
+ let ind = build_dependent_inductive env indf in
+ let s' = mkProd (Anonymous, ind, s) in
+ let ccl = lift 1 (decomp n pj.uj_val) in
+ let ccl' = mkLambda (Anonymous, ind, ccl) in
+ {uj_val=lam_it ccl' sign; uj_type=prod_it s' sign}
+
+(*************************************************************************)
+(* Main pretyping function *)
+
+let pretype_ref isevars env ref =
+ let c = constr_of_reference ref in
+ make_judge c (Retyping.get_type_of env Evd.empty c)
+
+let pretype_sort = function
+ | RProp c -> judge_of_prop_contents c
+ | RType _ -> judge_of_new_Type ()
+
+(* [pretype tycon env isevars lvar lmeta cstr] attempts to type [cstr] *)
+(* in environment [env], with existential variables [(evars_of isevars)] and *)
+(* the type constraint tycon *)
+let rec pretype tycon env isevars lvar = function
+
+ | RRef (loc,ref) ->
+ inh_conv_coerce_to_tycon loc env isevars
+ (pretype_ref isevars env ref)
+ tycon
+
+ | RVar (loc, id) ->
+ inh_conv_coerce_to_tycon loc env isevars
+ (pretype_id loc env lvar id)
+ tycon
+
+ | REvar (loc, ev, instopt) ->
+ (* Ne faudrait-il pas s'assurer que hyps est bien un
+ sous-contexte du contexte courant, et qu'il n'y a pas de Rel "caché" *)
+ let hyps = (Evd.map (evars_of isevars) ev).evar_hyps in
+ let args = match instopt with
+ | None -> instance_from_named_context hyps
+ | Some inst -> failwith "Evar subtitutions not implemented" in
+ let c = mkEvar (ev, args) in
+ let j = (Retyping.get_judgment_of env (evars_of isevars) c) in
+ inh_conv_coerce_to_tycon loc env isevars j tycon
+
+ | RPatVar (loc,(someta,n)) ->
+ anomaly "Found a pattern variable in a rawterm to type"
+
+ | RHole (loc,k) ->
+ if !compter then nbimpl:=!nbimpl+1;
+ (match tycon with
+ | Some ty ->
+ { uj_val = new_isevar isevars env (loc,k) ty; uj_type = ty }
+ | None -> error_unsolvable_implicit loc env (evars_of isevars) k)
+
+ | RRec (loc,fixkind,names,bl,lar,vdef) ->
+ let rec type_bl env ctxt = function
+ [] -> ctxt
+ | (na,None,ty)::bl ->
+ let ty' = pretype_type empty_valcon env isevars lvar ty in
+ let dcl = (na,None,ty'.utj_val) in
+ type_bl (push_rel dcl env) (add_rel_decl dcl ctxt) bl
+ | (na,Some bd,ty)::bl ->
+ let ty' = pretype_type empty_valcon env isevars lvar ty in
+ let bd' = pretype (mk_tycon ty'.utj_val) env isevars lvar ty in
+ let dcl = (na,Some bd'.uj_val,ty'.utj_val) in
+ type_bl (push_rel dcl env) (add_rel_decl dcl ctxt) bl in
+ let ctxtv = Array.map (type_bl env empty_rel_context) bl in
+ let larj =
+ array_map2
+ (fun e ar ->
+ pretype_type empty_valcon (push_rel_context e env) isevars lvar ar)
+ ctxtv lar in
+ let lara = Array.map (fun a -> a.utj_val) larj in
+ let ftys = array_map2 (fun e a -> it_mkProd_or_LetIn a e) ctxtv lara in
+ let nbfix = Array.length lar in
+ let names = Array.map (fun id -> Name id) names in
+ (* Note: bodies are not used by push_rec_types, so [||] is safe *)
+ let newenv = push_rec_types (names,ftys,[||]) env in
+ let vdefj =
+ array_map2_i
+ (fun i ctxt def ->
+ (* we lift nbfix times the type in tycon, because of
+ * the nbfix variables pushed to newenv *)
+ let (ctxt,ty) =
+ decompose_prod_n_assum (rel_context_length ctxt)
+ (lift nbfix ftys.(i)) in
+ let nenv = push_rel_context ctxt newenv in
+ let j = pretype (mk_tycon ty) nenv isevars lvar def in
+ { uj_val = it_mkLambda_or_LetIn j.uj_val ctxt;
+ uj_type = it_mkProd_or_LetIn j.uj_type ctxt })
+ ctxtv vdef in
+ evar_type_fixpoint loc env isevars names ftys vdefj;
+ let fixj =
+ match fixkind with
+ | RFix (vn,i as vni) ->
+ let fix = (vni,(names,ftys,Array.map j_val vdefj)) in
+ (try check_fix env fix with e -> Stdpp.raise_with_loc loc e);
+ make_judge (mkFix fix) ftys.(i)
+ | RCoFix i ->
+ let cofix = (i,(names,ftys,Array.map j_val vdefj)) in
+ (try check_cofix env cofix with e -> Stdpp.raise_with_loc loc e);
+ make_judge (mkCoFix cofix) ftys.(i) in
+ inh_conv_coerce_to_tycon loc env isevars fixj tycon
+
+ | RSort (loc,s) ->
+ inh_conv_coerce_to_tycon loc env isevars (pretype_sort s) tycon
+
+ | RApp (loc,f,args) ->
+ let fj = pretype empty_tycon env isevars lvar f in
+ let floc = loc_of_rawconstr f in
+ let rec apply_rec env n resj = function
+ | [] -> resj
+ | c::rest ->
+ let argloc = loc_of_rawconstr c in
+ let resj = inh_app_fun env isevars resj in
+ let resty =
+ whd_betadeltaiota env (evars_of isevars) resj.uj_type in
+ match kind_of_term resty with
+ | Prod (na,c1,c2) ->
+ let hj = pretype (mk_tycon c1) env isevars lvar c in
+ let newresj =
+ { uj_val = applist (j_val resj, [j_val hj]);
+ uj_type = subst1 hj.uj_val c2 } in
+ apply_rec env (n+1) newresj rest
+
+ | _ ->
+ let hj = pretype empty_tycon env isevars lvar c in
+ error_cant_apply_not_functional_loc
+ (join_loc floc argloc) env (evars_of isevars)
+ resj [hj]
+
+ in let resj = apply_rec env 1 fj args in
+ (*
+ let apply_one_arg (floc,tycon,jl) c =
+ let (dom,rng) = split_tycon floc env isevars tycon in
+ let cj = pretype dom env isevars lvar c in
+ let rng_tycon = option_app (subst1 cj.uj_val) rng in
+ let argloc = loc_of_rawconstr c in
+ (join_loc floc argloc,rng_tycon,(argloc,cj)::jl) in
+ let _,_,jl =
+ List.fold_left apply_one_arg (floc,mk_tycon j.uj_type,[]) args in
+ let jl = List.rev jl in
+ let resj = inh_apply_rel_list loc env isevars jl (floc,j) tycon in
+ *)
+ inh_conv_coerce_to_tycon loc env isevars resj tycon
+
+ | RLambda(loc,name,c1,c2) ->
+ let (name',dom,rng) = split_tycon loc env isevars tycon in
+ let dom_valcon = valcon_of_tycon dom in
+ let j = pretype_type dom_valcon env isevars lvar c1 in
+ let var = (name,None,j.utj_val) in
+ let j' = pretype rng (push_rel var env) isevars lvar c2 in
+ judge_of_abstraction env name j j'
+
+ | RProd(loc,name,c1,c2) ->
+ let j = pretype_type empty_valcon env isevars lvar c1 in
+ let var = (name,j.utj_val) in
+ let env' = push_rel_assum var env in
+ let j' = pretype_type empty_valcon env' isevars lvar c2 in
+ let resj =
+ try judge_of_product env name j j'
+ with TypeError _ as e -> Stdpp.raise_with_loc loc e in
+ inh_conv_coerce_to_tycon loc env isevars resj tycon
+
+ | RLetIn(loc,name,c1,c2) ->
+ let j = pretype empty_tycon env isevars lvar c1 in
+ let t = Evarutil.refresh_universes j.uj_type in
+ let var = (name,Some j.uj_val,t) in
+ let tycon = option_app (lift 1) tycon in
+ let j' = pretype tycon (push_rel var env) isevars lvar c2 in
+ { uj_val = mkLetIn (name, j.uj_val, t, j'.uj_val) ;
+ uj_type = type_app (subst1 j.uj_val) j'.uj_type }
+
+ | RLetTuple (loc,nal,(na,po),c,d) ->
+ let cj = pretype empty_tycon env isevars lvar c in
+ let (IndType (indf,realargs) as indt) =
+ try find_rectype env (evars_of isevars) cj.uj_type
+ with Not_found ->
+ let cloc = loc_of_rawconstr c in
+ error_case_not_inductive_loc cloc env (evars_of isevars) cj
+ in
+ let cstrs = get_constructors env indf in
+ if Array.length cstrs <> 1 then
+ user_err_loc (loc,"",str "Destructing let is only for inductive types with one constructor");
+ let cs = cstrs.(0) in
+ if List.length nal <> cs.cs_nargs then
+ user_err_loc (loc,"", str "Destructing let on this type expects " ++ int cs.cs_nargs ++ str " variables");
+ let fsign = List.map2 (fun na (_,c,t) -> (na,c,t))
+ (List.rev nal) cs.cs_args in
+ let env_f = push_rels fsign env in
+ (* Make dependencies from arity signature impossible *)
+ let arsgn,_ = get_arity env indf in
+ let arsgn = List.map (fun (_,b,t) -> (Anonymous,b,t)) arsgn in
+ let psign = (na,None,build_dependent_inductive env indf)::arsgn in
+ let nar = List.length arsgn in
+ (match po with
+ | Some p ->
+ let env_p = push_rels psign env in
+ let pj = pretype_type empty_valcon env_p isevars lvar p in
+ let ccl = nf_evar (evars_of isevars) pj.utj_val in
+ let psign = make_arity_signature env true indf in (* with names *)
+ let p = it_mkLambda_or_LetIn ccl psign in
+ let inst =
+ (Array.to_list cs.cs_concl_realargs)
+ @[build_dependent_constructor cs] in
+ let lp = lift cs.cs_nargs p in
+ let fty = hnf_lam_applist env (evars_of isevars) lp inst in
+ let fj = pretype (mk_tycon fty) env_f isevars lvar d in
+ let f = it_mkLambda_or_LetIn fj.uj_val fsign in
+ let v =
+ let mis,_ = dest_ind_family indf in
+ let ci = make_default_case_info env LetStyle mis in
+ mkCase (ci, p, cj.uj_val,[|f|]) in
+ let cs = build_dependent_constructor cs in
+ { uj_val = v; uj_type = substl (realargs@[cj.uj_val]) ccl }
+
+ | None ->
+ let tycon = option_app (lift cs.cs_nargs) tycon in
+ let fj = pretype tycon env_f isevars lvar d in
+ let f = it_mkLambda_or_LetIn fj.uj_val fsign in
+ let ccl = nf_evar (evars_of isevars) fj.uj_type in
+ let ccl =
+ if noccur_between 1 cs.cs_nargs ccl then
+ lift (- cs.cs_nargs) ccl
+ else
+ error_cant_find_case_type_loc loc env (evars_of isevars)
+ cj.uj_val in
+ let p = it_mkLambda_or_LetIn (lift (nar+1) ccl) psign in
+ let v =
+ let mis,_ = dest_ind_family indf in
+ let ci = make_default_case_info env LetStyle mis in
+ mkCase (ci, p, cj.uj_val,[|f|] )
+ in
+ { uj_val = v; uj_type = ccl })
+
+ (* Special Case for let constructions to avoid exponential behavior *)
+ | ROrderedCase (loc,st,po,c,[|f|],xx) when st <> MatchStyle ->
+ let cj = pretype empty_tycon env isevars lvar c in
+ let (IndType (indf,realargs) as indt) =
+ try find_rectype env (evars_of isevars) cj.uj_type
+ with Not_found ->
+ let cloc = loc_of_rawconstr c in
+ error_case_not_inductive_loc cloc env (evars_of isevars) cj
+ in
+ let j = match po with
+ | Some p ->
+ let pj = pretype empty_tycon env isevars lvar p in
+ let dep = is_dependent_elimination env pj.uj_type indf in
+ let ar =
+ arity_of_case_predicate env indf dep (Type (new_univ())) in
+ let _ = the_conv_x_leq env isevars pj.uj_type ar in
+ let pj = j_nf_evar (evars_of isevars) pj in
+ let pj = if dep then pj else make_dep_of_undep env indt pj in
+ let (bty,rsty) =
+ Indrec.type_rec_branches
+ false env (evars_of isevars) indt pj.uj_val cj.uj_val
+ in
+ if Array.length bty <> 1 then
+ error_number_branches_loc
+ loc env (evars_of isevars) cj (Array.length bty);
+ let fj =
+ let tyc = bty.(0) in
+ pretype (mk_tycon tyc) env isevars lvar f
+ in
+ let fv = j_val fj in
+ let ft = fj.uj_type in
+ check_branches_message loc env isevars cj.uj_val (bty,[|ft|]);
+ let v =
+ let mis,_ = dest_ind_family indf in
+ let ci = make_default_case_info env st mis in
+ mkCase (ci, (nf_betaiota pj.uj_val), cj.uj_val,[|fv|])
+ in
+ { uj_val = v; uj_type = rsty }
+
+ | None ->
+ (* get type information from type of branches *)
+ let expbr = Cases.branch_scheme env isevars false indf in
+ if Array.length expbr <> 1 then
+ error_number_branches_loc loc env (evars_of isevars)
+ cj (Array.length expbr);
+ let expti = expbr.(0) in
+ let fj = pretype (mk_tycon expti) env isevars lvar f in
+ let use_constraint () =
+ (* get type information from constraint *)
+ (* warning: if the constraint comes from an evar type, it *)
+ (* may be Type while Prop or Set would be expected *)
+ match tycon with
+ | Some pred ->
+ let arsgn = make_arity_signature env true indf in
+ let pred = lift (List.length arsgn) pred in
+ let pred =
+ it_mkLambda_or_LetIn (nf_evar (evars_of isevars) pred)
+ arsgn in
+ false, pred
+ | None ->
+ let sigma = evars_of isevars in
+ error_cant_find_case_type_loc loc env sigma cj.uj_val
+ in
+ let ok, p =
+ try
+ let pred =
+ Cases.pred_case_ml
+ env (evars_of isevars) false indt (0,fj.uj_type)
+ in
+ if has_undefined_isevars isevars pred then
+ use_constraint ()
+ else
+ true, pred
+ with Cases.NotInferable _ ->
+ use_constraint ()
+ in
+ let p = nf_evar (evars_of isevars) p in
+ let (bty,rsty) =
+ Indrec.type_rec_branches
+ false env (evars_of isevars) indt p cj.uj_val
+ in
+ let _ = option_app (the_conv_x_leq env isevars rsty) tycon in
+ let fj =
+ if ok then fj
+ else pretype (mk_tycon bty.(0)) env isevars lvar f
+ in
+ let fv = fj.uj_val in
+ let ft = fj.uj_type in
+ let v =
+ let mis,_ = dest_ind_family indf in
+ let ci = make_default_case_info env st mis in
+ mkCase (ci, (nf_betaiota p), cj.uj_val,[|fv|] )
+ in
+ { uj_val = v; uj_type = rsty } in
+
+ (* Build the LetTuple form for v8 *)
+ let c =
+ let (ind,params) = dest_ind_family indf in
+ let rtntypopt, indnalopt = match po with
+ | None -> None, (Anonymous,None)
+ | Some p ->
+ let pj = pretype empty_tycon env isevars lvar p in
+ let dep = is_dependent_elimination env pj.uj_type indf in
+ let rec decomp_lam_force n avoid l p =
+ (* avoid is not exhaustive ! *)
+ if n = 0 then (List.rev l,p,avoid) else
+ match p with
+ | RLambda (_,(Name id as na),_,c) ->
+ decomp_lam_force (n-1) (id::avoid) (na::l) c
+ | RLambda (_,(Anonymous as na),_,c) ->
+ decomp_lam_force (n-1) avoid (na::l) c
+ | _ ->
+ let x = Nameops.next_ident_away (id_of_string "x") avoid in
+ decomp_lam_force (n-1) (x::avoid) (Name x :: l)
+ (* eta-expansion *)
+ (RApp (dummy_loc,p, [RVar (dummy_loc,x)])) in
+ let (nal,p,avoid) =
+ decomp_lam_force (List.length realargs) [] [] p in
+ let na,rtntyp,_ =
+ if dep then decomp_lam_force 1 avoid [] p
+ else [Anonymous],p,[] in
+ let intyp =
+ if List.for_all
+ (function
+ | Anonymous -> true
+ | Name id -> not (occur_rawconstr id rtntyp)) nal
+ then (* No dependency in realargs *)
+ None
+ else
+ let args = List.map (fun _ -> Anonymous) params @ nal in
+ Some (dummy_loc,ind,args) in
+ (Some rtntyp,(List.hd na,intyp)) in
+ let cs = (get_constructors env indf).(0) in
+ match indnalopt with
+ | (na,None) -> (* Represented as a let *)
+ let rec decomp_lam_force n avoid l p =
+ if n = 0 then (List.rev l,p) else
+ match p with
+ | RLambda (_,(Name id as na),_,c) ->
+ decomp_lam_force (n-1) (id::avoid) (na::l) c
+ | RLambda (_,(Anonymous as na),_,c) ->
+ decomp_lam_force (n-1) avoid (na::l) c
+ | _ ->
+ let x = Nameops.next_ident_away (id_of_string "x") avoid in
+ decomp_lam_force (n-1) (x::avoid) (Name x :: l)
+ (* eta-expansion *)
+ (let a = RVar (dummy_loc,x) in
+ match p with
+ | RApp (loc,p,l) -> RApp (loc,p,l@[a])
+ | _ -> (RApp (dummy_loc,p,[a]))) in
+ let (nal,d) = decomp_lam_force cs.cs_nargs [] [] f in
+ RLetTuple (loc,nal,(na,rtntypopt),c,d)
+ | _ -> (* Represented as a match *)
+ let detype_eqn constr construct_nargs branch =
+ let name_cons = function
+ | Anonymous -> fun l -> l
+ | Name id -> fun l -> id::l in
+ let make_pat na avoid b ids =
+ PatVar (dummy_loc,na),
+ name_cons na avoid,name_cons na ids
+ in
+ let rec buildrec ids patlist avoid n b =
+ if n=0 then
+ (dummy_loc, ids,
+ [PatCstr(dummy_loc, constr, List.rev patlist,Anonymous)],
+ b)
+ else
+ match b with
+ | RLambda (_,x,_,b) ->
+ let pat,new_avoid,new_ids = make_pat x avoid b ids in
+ buildrec new_ids (pat::patlist) new_avoid (n-1) b
+
+ | RLetIn (_,x,_,b) ->
+ let pat,new_avoid,new_ids = make_pat x avoid b ids in
+ buildrec new_ids (pat::patlist) new_avoid (n-1) b
+
+ | RCast (_,c,_) -> (* Oui, il y a parfois des cast *)
+ buildrec ids patlist avoid n c
+
+ | _ -> (* eta-expansion *)
+ (* nommage de la nouvelle variable *)
+ let id = Nameops.next_ident_away (id_of_string "x") avoid in
+ let new_b = RApp (dummy_loc, b, [RVar(dummy_loc,id)])in
+ let pat,new_avoid,new_ids =
+ make_pat (Name id) avoid new_b ids in
+ buildrec new_ids (pat::patlist) new_avoid (n-1) new_b
+
+ in
+ buildrec [] [] [] construct_nargs branch in
+ let eqn = detype_eqn (ind,1) cs.cs_nargs f in
+ RCases (loc,(po,ref rtntypopt),[c,ref indnalopt],[eqn])
+ in
+ xx := Some c;
+ (* End building the v8 syntax *)
+ j
+
+ | RIf (loc,c,(na,po),b1,b2) ->
+ let cj = pretype empty_tycon env isevars lvar c in
+ let (IndType (indf,realargs) as indt) =
+ try find_rectype env (evars_of isevars) cj.uj_type
+ with Not_found ->
+ let cloc = loc_of_rawconstr c in
+ error_case_not_inductive_loc cloc env (evars_of isevars) cj in
+ let cstrs = get_constructors env indf in
+ if Array.length cstrs <> 2 then
+ user_err_loc (loc,"",
+ str "If is only for inductive types with two constructors");
+
+ (* Make dependencies from arity signature impossible *)
+ let arsgn,_ = get_arity env indf in
+ let arsgn = List.map (fun (_,b,t) -> (Anonymous,b,t)) arsgn in
+ let nar = List.length arsgn in
+ let psign = (na,None,build_dependent_inductive env indf)::arsgn in
+ let pred,p = match po with
+ | Some p ->
+ let env_p = push_rels psign env in
+ let pj = pretype_type empty_valcon env_p isevars lvar p in
+ let ccl = nf_evar (evars_of isevars) pj.utj_val in
+ let pred = it_mkLambda_or_LetIn ccl psign in
+ pred, lift (- nar) (beta_applist (pred,[cj.uj_val]))
+ | None ->
+ let p = match tycon with
+ | Some ty -> ty
+ | None -> new_isevar isevars env (loc,InternalHole) (new_Type ())
+ in
+ it_mkLambda_or_LetIn (lift (nar+1) p) psign, p in
+ let f cs b =
+ let n = rel_context_length cs.cs_args in
+ let pi = liftn n 2 pred in
+ let pi = beta_applist (pi, [build_dependent_constructor cs]) in
+ let csgn = List.map (fun (_,b,t) -> (Anonymous,b,t)) cs.cs_args in
+ let env_c = push_rels csgn env in
+ let bj = pretype (Some pi) env_c isevars lvar b in
+ it_mkLambda_or_LetIn bj.uj_val cs.cs_args in
+ let b1 = f cstrs.(0) b1 in
+ let b2 = f cstrs.(1) b2 in
+ let pred = nf_evar (evars_of isevars) pred in
+ let p = nf_evar (evars_of isevars) p in
+ let v =
+ let mis,_ = dest_ind_family indf in
+ let ci = make_default_case_info env IfStyle mis in
+ mkCase (ci, pred, cj.uj_val, [|b1;b2|])
+ in
+ { uj_val = v; uj_type = p }
+
+ | ROrderedCase (loc,st,po,c,lf,x) ->
+ let isrec = (st = MatchStyle) in
+ let cj = pretype empty_tycon env isevars lvar c in
+ let (IndType (indf,realargs) as indt) =
+ try find_rectype env (evars_of isevars) cj.uj_type
+ with Not_found ->
+ let cloc = loc_of_rawconstr c in
+ error_case_not_inductive_loc cloc env (evars_of isevars) cj in
+ let (dep,pj) = match po with
+ | Some p ->
+ let pj = pretype empty_tycon env isevars lvar p in
+ let dep = is_dependent_elimination env pj.uj_type indf in
+ let ar =
+ arity_of_case_predicate env indf dep (Type (new_univ())) in
+ let _ = the_conv_x_leq env isevars pj.uj_type ar in
+ (dep, pj)
+ | None ->
+ (* get type information from type of branches *)
+ let expbr = Cases.branch_scheme env isevars isrec indf in
+ let rec findtype i =
+ if i >= Array.length lf
+ then
+ (* get type information from constraint *)
+ (* warning: if the constraint comes from an evar type, it *)
+ (* may be Type while Prop or Set would be expected *)
+ match tycon with
+ | Some pred ->
+ let arsgn = make_arity_signature env true indf in
+ let pred = lift (List.length arsgn) pred in
+ let pred =
+ it_mkLambda_or_LetIn (nf_evar (evars_of isevars) pred)
+ arsgn in
+ (true,
+ Retyping.get_judgment_of env (evars_of isevars) pred)
+ | None ->
+ let sigma = evars_of isevars in
+ error_cant_find_case_type_loc loc env sigma cj.uj_val
+ else
+ try
+ let expti = expbr.(i) in
+ let fj =
+ pretype (mk_tycon expti) env isevars lvar lf.(i) in
+ let pred =
+ Cases.pred_case_ml (* eta-expanse *)
+ env (evars_of isevars) isrec indt (i,fj.uj_type) in
+ if has_undefined_isevars isevars pred then findtype (i+1)
+ else
+ let pty =
+ Retyping.get_type_of env (evars_of isevars) pred in
+ let pj = { uj_val = pred; uj_type = pty } in
+(*
+ let _ = option_app (the_conv_x_leq env isevars pred) tycon
+ in
+*)
+ (true,pj)
+ with Cases.NotInferable _ -> findtype (i+1) in
+ findtype 0
+ in
+ let pj = j_nf_evar (evars_of isevars) pj in
+ let pj = if dep then pj else make_dep_of_undep env indt pj in
+ let (bty,rsty) =
+ Indrec.type_rec_branches
+ isrec env (evars_of isevars) indt pj.uj_val cj.uj_val in
+ let _ = option_app (the_conv_x_leq env isevars rsty) tycon in
+ if Array.length bty <> Array.length lf then
+ error_number_branches_loc loc env (evars_of isevars)
+ cj (Array.length bty)
+ else
+ let lfj =
+ array_map2
+ (fun tyc f -> pretype (mk_tycon tyc) env isevars lvar f) bty
+ lf in
+ let lfv = Array.map j_val lfj in
+ let lft = Array.map (fun j -> j.uj_type) lfj in
+ check_branches_message loc env isevars cj.uj_val (bty,lft);
+ let v =
+ if isrec
+ then
+ transform_rec loc env (evars_of isevars)(pj,cj.uj_val,lfv) indt
+ else
+ let mis,_ = dest_ind_family indf in
+ let ci = make_default_case_info env st mis in
+ mkCase (ci, (nf_betaiota pj.uj_val), cj.uj_val,
+ Array.map (fun j-> j.uj_val) lfj)
+ in
+ (* Build the Cases form for v8 *)
+ let c =
+ let (ind,params) = dest_ind_family indf in
+ let (mib,mip) = lookup_mind_specif env ind in
+ let recargs = mip.mind_recargs in
+ let mI = mkInd ind in
+ let nconstr = Array.length mip.mind_consnames in
+ let tyi = snd ind in
+ if isrec && mis_is_recursive_subset [tyi] recargs then
+ Some (Detyping.detype (false,env)
+ (ids_of_context env) (names_of_rel_context env)
+ (nf_evar (evars_of isevars) v))
+ else
+ (* Translate into a "match ... with" *)
+ let rtntypopt, indnalopt = match po with
+ | None -> None, (Anonymous,None)
+ | Some p ->
+ let rec decomp_lam_force n avoid l p =
+ (* avoid is not exhaustive ! *)
+ if n = 0 then (List.rev l,p,avoid) else
+ match p with
+ | RLambda (_,(Name id as na),_,c) ->
+ decomp_lam_force (n-1) (id::avoid) (na::l) c
+ | RLambda (_,(Anonymous as na),_,c) ->
+ decomp_lam_force (n-1) avoid (na::l) c
+ | _ ->
+ let x = Nameops.next_ident_away (id_of_string "x") avoid in
+ decomp_lam_force (n-1) (x::avoid) (Name x :: l)
+ (* eta-expansion *)
+ (RApp (dummy_loc,p, [RVar (dummy_loc,x)])) in
+ let (nal,p,avoid) =
+ decomp_lam_force (List.length realargs) [] [] p in
+ let na,rtntyopt,_ =
+ if dep then decomp_lam_force 1 avoid [] p
+ else [Anonymous],p,[] in
+ let intyp =
+ if nal=[] then None else
+ let args = List.map (fun _ -> Anonymous) params @ nal in
+ Some (dummy_loc,ind,args) in
+ (Some rtntyopt,(List.hd na,intyp)) in
+ let rawbranches =
+ array_map3 (fun bj b cstr ->
+ let rec strip n r = if n=0 then r else
+ match r with
+ | RLambda (_,_,_,t) -> strip (n-1) t
+ | RLetIn (_,_,_,t) -> strip (n-1) t
+ | _ -> assert false in
+ let n = rel_context_length cstr.cs_args in
+ try
+ let _,ccl = decompose_lam_n_assum n bj.uj_val in
+ if noccur_between 1 n ccl then Some (strip n b) else None
+ with _ -> (* Not eta-expanded or not reduced *) None)
+ lfj lf (get_constructors env indf) in
+ if st = IfStyle & snd indnalopt = None
+ & rawbranches.(0) <> None && rawbranches.(1) <> None then
+ (* Translate into a "if ... then ... else" *)
+ (* TODO: translate into a "if" even if po is dependent *)
+ Some (RIf (loc,c,(fst indnalopt,rtntypopt),
+ out_some rawbranches.(0),out_some rawbranches.(1)))
+ else
+ let detype_eqn constr construct_nargs branch =
+ let name_cons = function
+ | Anonymous -> fun l -> l
+ | Name id -> fun l -> id::l in
+ let make_pat na avoid b ids =
+ PatVar (dummy_loc,na),
+ name_cons na avoid,name_cons na ids
+ in
+ let rec buildrec ids patlist avoid n b =
+ if n=0 then
+ (dummy_loc, ids,
+ [PatCstr(dummy_loc, constr, List.rev patlist,Anonymous)],
+ b)
+ else
+ match b with
+ | RLambda (_,x,_,b) ->
+ let pat,new_avoid,new_ids = make_pat x avoid b ids in
+ buildrec new_ids (pat::patlist) new_avoid (n-1) b
+
+ | RLetIn (_,x,_,b) ->
+ let pat,new_avoid,new_ids = make_pat x avoid b ids in
+ buildrec new_ids (pat::patlist) new_avoid (n-1) b
+
+ | RCast (_,c,_) -> (* Oui, il y a parfois des cast *)
+ buildrec ids patlist avoid n c
+
+ | _ -> (* eta-expansion *)
+ (* nommage de la nouvelle variable *)
+ let id = Nameops.next_ident_away (id_of_string "x") avoid in
+ let new_b = RApp (dummy_loc, b, [RVar(dummy_loc,id)])in
+ let pat,new_avoid,new_ids =
+ make_pat (Name id) avoid new_b ids in
+ buildrec new_ids (pat::patlist) new_avoid (n-1) new_b
+
+ in
+ buildrec [] [] [] construct_nargs branch in
+ let (mib,mip) = Inductive.lookup_mind_specif (Global.env()) ind in
+ let get_consnarg j =
+ let typi = mis_nf_constructor_type (ind,mib,mip) (j+1) in
+ let _,t = decompose_prod_n_assum mip.mind_nparams typi in
+ List.rev (fst (decompose_prod_assum t)) in
+ let consnargs = Array.init (Array.length mip.mind_consnames) get_consnarg in
+ let consnargsl = Array.map List.length consnargs in
+ let constructs = Array.init (Array.length lf) (fun i -> (ind,i+1)) in
+ let eqns = array_map3 detype_eqn constructs consnargsl lf in
+ Some (RCases (loc,(po,ref rtntypopt),[c,ref indnalopt],Array.to_list eqns)) in
+ x := c;
+ (* End build the Cases form for v8 *)
+ { uj_val = v;
+ uj_type = rsty }
+
+ | RCases (loc,po,tml,eqns) ->
+ Cases.compile_cases loc
+ ((fun vtyc env -> pretype vtyc env isevars lvar),isevars)
+ tycon env (* loc *) (po,tml,eqns)
+
+ | RCast(loc,c,t) ->
+ let tj = pretype_type empty_tycon env isevars lvar t in
+ let cj = pretype (mk_tycon tj.utj_val) env isevars lvar c in
+ (* User Casts are for helping pretyping, experimentally not to be kept*)
+ (* ... except for Correctness *)
+ let v = mkCast (cj.uj_val, tj.utj_val) in
+ let cj = { uj_val = v; uj_type = tj.utj_val } in
+ inh_conv_coerce_to_tycon loc env isevars cj tycon
+
+ | RDynamic (loc,d) ->
+ if (tag d) = "constr" then
+ let c = constr_out d in
+ let j = (Retyping.get_judgment_of env (evars_of isevars) c) in
+ j
+ (*inh_conv_coerce_to_tycon loc env isevars j tycon*)
+ else
+ user_err_loc (loc,"pretype",(str "Not a constr tagged Dynamic"))
+
+(* [pretype_type valcon env isevars lvar c] coerces [c] into a type *)
+and pretype_type valcon env isevars lvar = function
+ | RHole loc ->
+ if !compter then nbimpl:=!nbimpl+1;
+ (match valcon with
+ | Some v ->
+ let s =
+ let sigma = evars_of isevars in
+ let t = Retyping.get_type_of env sigma v in
+ match kind_of_term (whd_betadeltaiota env sigma t) with
+ | Sort s -> s
+ | Evar v when is_Type (existential_type sigma v) ->
+ define_evar_as_sort isevars v
+ | _ -> anomaly "Found a type constraint which is not a type"
+ in
+ { utj_val = v;
+ utj_type = s }
+ | None ->
+ let s = new_Type_sort () in
+ { utj_val = new_isevar isevars env loc (mkSort s);
+ utj_type = s})
+ | c ->
+ let j = pretype empty_tycon env isevars lvar c in
+ let tj = inh_coerce_to_sort env isevars j in
+ match valcon with
+ | None -> tj
+ | Some v ->
+ if the_conv_x_leq env isevars v tj.utj_val then tj
+ else
+ error_unexpected_type_loc
+ (loc_of_rawconstr c) env (evars_of isevars) tj.utj_val v
+
+
+let unsafe_infer tycon isevars env lvar constr =
+ let j = pretype tycon env isevars lvar constr in
+ j_nf_evar (evars_of isevars) j
+
+let unsafe_infer_type valcon isevars env lvar constr =
+ let tj = pretype_type valcon env isevars lvar constr in
+ tj_nf_evar (evars_of isevars) tj
+
+(* If fail_evar is false, [process_evars] builds a meta_map with the
+ unresolved Evar that were not in initial sigma; otherwise it fail
+ on the first unresolved Evar not already in the initial sigma. *)
+(* [fail_evar] says how to process unresolved evars:
+ * true -> raise an error message
+ * false -> convert them into new Metas (casted with their type)
+ *)
+(* assumes the defined existentials have been replaced in c (should be
+ done in unsafe_infer and unsafe_infer_type) *)
+let check_evars fail_evar env initial_sigma isevars c =
+ let sigma = evars_of isevars in
+ let rec proc_rec c =
+ match kind_of_term c with
+ | Evar (ev,args as k) ->
+ assert (Evd.in_dom sigma ev);
+ if not (Evd.in_dom initial_sigma ev) then
+ (if fail_evar then
+ let (loc,k) = evar_source ev isevars in
+ error_unsolvable_implicit loc env sigma k)
+ | _ -> iter_constr proc_rec c
+ in
+ proc_rec c
+
+(* TODO: comment faire remonter l'information si le typage a resolu des
+ variables du sigma original. il faudrait que la fonction de typage
+ retourne aussi le nouveau sigma...
+*)
+
+(* constr with holes *)
+type open_constr = evar_map * constr
+
+let ise_resolve_casted_gen fail_evar sigma env lvar typ c =
+ let isevars = create_evar_defs sigma in
+ let j = unsafe_infer (mk_tycon typ) isevars env lvar c in
+ check_evars fail_evar env sigma isevars (mkCast(j.uj_val,j.uj_type));
+ (evars_of isevars, j)
+
+let ise_resolve_casted sigma env typ c =
+ ise_resolve_casted_gen true sigma env ([],[]) typ c
+
+(* Raw calls to the unsafe inference machine: boolean says if we must fail
+ on unresolved evars, or replace them by Metas; the unsafe_judgment list
+ allows us to extend env with some bindings *)
+let ise_infer_gen fail_evar sigma env lvar exptyp c =
+ let tycon = match exptyp with None -> empty_tycon | Some t -> mk_tycon t in
+ let isevars = create_evar_defs sigma in
+ let j = unsafe_infer tycon isevars env lvar c in
+ check_evars fail_evar env sigma isevars (mkCast(j.uj_val,j.uj_type));
+ (evars_of isevars, j)
+
+let ise_infer_type_gen fail_evar sigma env lvar c =
+ let isevars = create_evar_defs sigma in
+ let tj = unsafe_infer_type empty_valcon isevars env lvar c in
+ check_evars fail_evar env sigma isevars tj.utj_val;
+ (evars_of isevars, tj)
+
+type var_map = (identifier * unsafe_judgment) list
+
+let understand_judgment sigma env c =
+ snd (ise_infer_gen true sigma env ([],[]) None c)
+
+let understand_type_judgment sigma env c =
+ snd (ise_infer_type_gen true sigma env ([],[]) c)
+
+let understand sigma env c =
+ let _, c = ise_infer_gen true sigma env ([],[]) None c in
+ c.uj_val
+
+let understand_type sigma env c =
+ let _,c = ise_infer_type_gen true sigma env ([],[]) c in
+ c.utj_val
+
+let understand_gen_ltac sigma env lvar ~expected_type:exptyp c =
+ let _, c = ise_infer_gen true sigma env lvar exptyp c in
+ c.uj_val
+
+let understand_gen sigma env lvar ~expected_type:exptyp c =
+ let _, c = ise_infer_gen true sigma env (lvar,[]) exptyp c in
+ c.uj_val
+
+let understand_gen_tcc sigma env lvar exptyp c =
+ let metamap, c = ise_infer_gen false sigma env (lvar,[]) exptyp c in
+ metamap, c.uj_val
+
+let interp_sort = function
+ | RProp c -> Prop c
+ | RType _ -> new_Type_sort ()
+
+let interp_elimination_sort = function
+ | RProp Null -> InProp
+ | RProp Pos -> InSet
+ | RType _ -> InType
diff --git a/pretyping/pretyping.mli b/pretyping/pretyping.mli
new file mode 100644
index 00000000..4357e504
--- /dev/null
+++ b/pretyping/pretyping.mli
@@ -0,0 +1,86 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: pretyping.mli,v 1.28.2.1 2004/07/16 19:30:46 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Sign
+open Term
+open Environ
+open Evd
+open Rawterm
+open Evarutil
+(*i*)
+
+type var_map = (identifier * unsafe_judgment) list
+
+(* constr with holes *)
+type open_constr = evar_map * constr
+
+
+(* Generic call to the interpreter from rawconstr to constr, failing
+ unresolved holes in the rawterm cannot be instantiated.
+
+ In [understand_gen sigma env varmap typopt raw],
+
+ sigma : initial set of existential variables (typically dependent subgoals)
+ varmap : partial subtitution of variables (used for the tactic language)
+ metamap : partial subtitution of meta (used for the tactic language)
+ typopt : is not None, this is the expected type for raw (used to define evars)
+*)
+val understand_gen :
+ evar_map -> env -> var_map
+ -> expected_type:(constr option) -> rawconstr -> constr
+
+val understand_gen_ltac :
+ evar_map -> env -> var_map * (identifier * identifier option) list
+ -> expected_type:(constr option) -> rawconstr -> constr
+
+(* Generic call to the interpreter from rawconstr to constr, turning
+ unresolved holes into metas. Returns also the typing context of
+ these metas. Work as [understand_gen] for the rest. *)
+val understand_gen_tcc :
+ evar_map -> env -> var_map
+ -> constr option -> rawconstr -> open_constr
+
+(* Standard call to get a constr from a rawconstr, resolving implicit args *)
+val understand : evar_map -> env -> rawconstr -> constr
+
+(* Idem but the rawconstr is intended to be a type *)
+val understand_type : evar_map -> env -> rawconstr -> constr
+
+(* Idem but returns the judgment of the understood term *)
+val understand_judgment : evar_map -> env -> rawconstr -> unsafe_judgment
+
+(* Idem but returns the judgment of the understood type *)
+val understand_type_judgment : evar_map -> env -> rawconstr
+ -> unsafe_type_judgment
+
+(* To embed constr in rawconstr *)
+val constr_in : constr -> Dyn.t
+val constr_out : Dyn.t -> constr
+
+(*i*)
+(* Internal of Pretyping...
+ * Unused outside, but useful for debugging
+ *)
+val pretype :
+ type_constraint -> env -> evar_defs ->
+ var_map * (identifier * identifier option) list ->
+ rawconstr -> unsafe_judgment
+
+val pretype_type :
+ val_constraint -> env -> evar_defs ->
+ var_map * (identifier * identifier option) list ->
+ rawconstr -> unsafe_type_judgment
+(*i*)
+
+val interp_sort : rawsort -> sorts
+
+val interp_elimination_sort : rawsort -> sorts_family
diff --git a/pretyping/rawterm.ml b/pretyping/rawterm.ml
new file mode 100644
index 00000000..520f09e9
--- /dev/null
+++ b/pretyping/rawterm.ml
@@ -0,0 +1,365 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: rawterm.ml,v 1.43.2.2 2004/07/16 19:30:46 herbelin Exp $ *)
+
+(*i*)
+open Util
+open Names
+open Sign
+open Term
+open Libnames
+open Nametab
+(*i*)
+
+(* Untyped intermediate terms, after ASTs and before constr. *)
+
+(* locs here refers to the ident's location, not whole pat *)
+(* the last argument of PatCstr is a possible alias ident for the pattern *)
+type cases_pattern =
+ | PatVar of loc * name
+ | PatCstr of loc * constructor * cases_pattern list * name
+
+let pattern_loc = function
+ PatVar(loc,_) -> loc
+ | PatCstr(loc,_,_,_) -> loc
+
+type patvar = identifier
+
+type rawsort = RProp of Term.contents | RType of Univ.universe option
+
+type fix_kind = RFix of (int array * int) | RCoFix of int
+
+type binder_kind = BProd | BLambda | BLetIn
+
+type quantified_hypothesis = AnonHyp of int | NamedHyp of identifier
+
+type 'a explicit_bindings = (loc * quantified_hypothesis * 'a) list
+
+type 'a bindings =
+ | ImplicitBindings of 'a list
+ | ExplicitBindings of 'a explicit_bindings
+ | NoBindings
+
+type 'a with_bindings = 'a * 'a bindings
+
+type hole_kind =
+ | ImplicitArg of global_reference * int
+ | BinderType of name
+ | QuestionMark
+ | CasesType
+ | InternalHole
+ | TomatchTypeParameter of inductive * int
+
+type rawconstr =
+ | RRef of (loc * global_reference)
+ | RVar of (loc * identifier)
+ | REvar of loc * existential_key * rawconstr list option
+ | RPatVar of loc * (bool * patvar) (* Used for patterns only *)
+ | RApp of loc * rawconstr * rawconstr list
+ | RLambda of loc * name * rawconstr * rawconstr
+ | RProd of loc * name * rawconstr * rawconstr
+ | RLetIn of loc * name * rawconstr * rawconstr
+ | RCases of loc * (rawconstr option * rawconstr option ref) *
+ (rawconstr * (name * (loc * inductive * name list) option) ref) list *
+ (loc * identifier list * cases_pattern list * rawconstr) list
+ | ROrderedCase of loc * case_style * rawconstr option * rawconstr *
+ rawconstr array * rawconstr option ref
+ | RLetTuple of loc * name list * (name * rawconstr option) *
+ rawconstr * rawconstr
+ | RIf of loc * rawconstr * (name * rawconstr option) * rawconstr * rawconstr
+ | RRec of loc * fix_kind * identifier array * rawdecl list array *
+ rawconstr array * rawconstr array
+ | RSort of loc * rawsort
+ | RHole of (loc * hole_kind)
+ | RCast of loc * rawconstr * rawconstr
+ | RDynamic of loc * Dyn.t
+
+and rawdecl = name * rawconstr option * rawconstr
+
+let cases_predicate_names tml =
+ List.flatten (List.map (function
+ | (tm,{contents=(na,None)}) -> [na]
+ | (tm,{contents=(na,Some (_,_,nal))}) -> na::nal) tml)
+
+(*i - if PRec (_, names, arities, bodies) is in env then arities are
+ typed in env too and bodies are typed in env enriched by the
+ arities incrementally lifted
+
+ [On pourrait plutot mettre les arités aves le type qu'elles auront
+ dans le contexte servant à typer les body ???]
+
+ - boolean in POldCase means it is recursive
+i*)
+let map_rawdecl f (na,obd,ty) = (na,option_app f obd,f ty)
+
+let map_rawconstr f = function
+ | RVar (loc,id) -> RVar (loc,id)
+ | RApp (loc,g,args) -> RApp (loc,f g, List.map f args)
+ | RLambda (loc,na,ty,c) -> RLambda (loc,na,f ty,f c)
+ | RProd (loc,na,ty,c) -> RProd (loc,na,f ty,f c)
+ | RLetIn (loc,na,b,c) -> RLetIn (loc,na,f b,f c)
+ | RCases (loc,(tyopt,rtntypopt),tml,pl) ->
+ RCases (loc,(option_app f tyopt,ref (option_app f !rtntypopt)),
+ List.map (fun (tm,x) -> (f tm,x)) tml,
+ List.map (fun (loc,idl,p,c) -> (loc,idl,p,f c)) pl)
+ | ROrderedCase (loc,b,tyopt,tm,bv,x) ->
+ ROrderedCase (loc,b,option_app f tyopt,f tm, Array.map f bv,ref (option_app f !x))
+ | RLetTuple (loc,nal,(na,po),b,c) ->
+ RLetTuple (loc,nal,(na,option_app f po),f b,f c)
+ | RIf (loc,c,(na,po),b1,b2) ->
+ RIf (loc,f c,(na,option_app f po),f b1,f b2)
+ | RRec (loc,fk,idl,bl,tyl,bv) ->
+ RRec (loc,fk,idl,Array.map (List.map (map_rawdecl f)) bl,
+ Array.map f tyl,Array.map f bv)
+ | RCast (loc,c,t) -> RCast (loc,f c,f t)
+ | (RSort _ | RHole _ | RRef _ | REvar _ | RPatVar _ | RDynamic _) as x -> x
+
+
+(*
+let name_app f e = function
+ | Name id -> let (id, e) = f id e in (Name id, e)
+ | Anonymous -> Anonymous, e
+
+let fold_ident g idl e =
+ let (idl,e) =
+ Array.fold_right
+ (fun id (idl,e) -> let id,e = g id e in (id::idl,e)) idl ([],e)
+ in (Array.of_list idl,e)
+
+let map_rawconstr_with_binders_loc loc g f e = function
+ | RVar (_,id) -> RVar (loc,id)
+ | RApp (_,a,args) -> RApp (loc,f e a, List.map (f e) args)
+ | RLambda (_,na,ty,c) ->
+ let na,e = name_app g e na in RLambda (loc,na,f e ty,f e c)
+ | RProd (_,na,ty,c) ->
+ let na,e = name_app g e na in RProd (loc,na,f e ty,f e c)
+ | RLetIn (_,na,b,c) ->
+ let na,e = name_app g e na in RLetIn (loc,na,f e b,f e c)
+ | RCases (_,tyopt,tml,pl) ->
+ (* We don't modify pattern variable since we don't traverse patterns *)
+ let g' id e = snd (g id e) in
+ let h (_,idl,p,c) = (loc,idl,p,f (List.fold_right g' idl e) c) in
+ RCases
+ (loc,option_app (f e) tyopt,List.map (f e) tml, List.map h pl)
+ | ROrderedCase (_,b,tyopt,tm,bv) ->
+ ROrderedCase (loc,b,option_app (f e) tyopt,f e tm,Array.map (f e) bv)
+ | RRec (_,fk,idl,tyl,bv) ->
+ let idl',e' = fold_ident g idl e in
+ RRec (loc,fk,idl',Array.map (f e) tyl,Array.map (f e') bv)
+ | RCast (_,c,t) -> RCast (loc,f e c,f e t)
+ | RSort (_,x) -> RSort (loc,x)
+ | RHole (_,x) -> RHole (loc,x)
+ | RRef (_,x) -> RRef (loc,x)
+ | REvar (_,x,l) -> REvar (loc,x,l)
+ | RPatVar (_,x) -> RPatVar (loc,x)
+ | RDynamic (_,x) -> RDynamic (loc,x)
+*)
+
+let occur_rawconstr id =
+ let rec occur = function
+ | RVar (loc,id') -> id = id'
+ | RApp (loc,f,args) -> (occur f) or (List.exists occur args)
+ | RLambda (loc,na,ty,c) -> (occur ty) or ((na <> Name id) & (occur c))
+ | RProd (loc,na,ty,c) -> (occur ty) or ((na <> Name id) & (occur c))
+ | RLetIn (loc,na,b,c) -> (occur b) or ((na <> Name id) & (occur c))
+ | RCases (loc,(tyopt,rtntypopt),tml,pl) ->
+ (occur_option tyopt) or (occur_option !rtntypopt)
+ or (List.exists (fun (tm,_) -> occur tm) tml)
+ or (List.exists occur_pattern pl)
+ | ROrderedCase (loc,b,tyopt,tm,bv,_) ->
+ (occur_option tyopt) or (occur tm) or (array_exists occur bv)
+ | RLetTuple (loc,nal,rtntyp,b,c) ->
+ occur_return_type rtntyp id
+ or (occur b) or (not (List.mem (Name id) nal) & (occur c))
+ | RIf (loc,c,rtntyp,b1,b2) ->
+ occur_return_type rtntyp id or (occur c) or (occur b1) or (occur b2)
+ | RRec (loc,fk,idl,bl,tyl,bv) ->
+ not (array_for_all4 (fun fid bl ty bd ->
+ let rec occur_fix = function
+ [] -> not (occur ty) && (fid=id or not(occur bd))
+ | (na,bbd,bty)::bl ->
+ not (occur bty) &&
+ (match bbd with
+ Some bd -> not (occur bd)
+ | _ -> true) &&
+ (na=Name id or not(occur_fix bl)) in
+ occur_fix bl)
+ idl bl tyl bv)
+ | RCast (loc,c,t) -> (occur c) or (occur t)
+ | (RSort _ | RHole _ | RRef _ | REvar _ | RPatVar _ | RDynamic _) -> false
+
+ and occur_pattern (loc,idl,p,c) = not (List.mem id idl) & (occur c)
+
+ and occur_option = function None -> false | Some p -> occur p
+
+ and occur_return_type (na,tyopt) id = na <> Name id & occur_option tyopt
+
+ in occur
+
+let rec subst_pat subst pat =
+ match pat with
+ | PatVar _ -> pat
+ | PatCstr (loc,((kn,i),j),cpl,n) ->
+ let kn' = subst_kn subst kn
+ and cpl' = list_smartmap (subst_pat subst) cpl in
+ if kn' == kn && cpl' == cpl then pat else
+ PatCstr (loc,((kn',i),j),cpl',n)
+
+let rec subst_raw subst raw =
+ match raw with
+ | RRef (loc,ref) ->
+ let ref' = subst_global subst ref in
+ if ref' == ref then raw else
+ RRef (loc,ref')
+
+ | RVar _ -> raw
+ | REvar _ -> raw
+ | RPatVar _ -> raw
+
+ | RApp (loc,r,rl) ->
+ let r' = subst_raw subst r
+ and rl' = list_smartmap (subst_raw subst) rl in
+ if r' == r && rl' == rl then raw else
+ RApp(loc,r',rl')
+
+ | RLambda (loc,n,r1,r2) ->
+ let r1' = subst_raw subst r1 and r2' = subst_raw subst r2 in
+ if r1' == r1 && r2' == r2 then raw else
+ RLambda (loc,n,r1',r2')
+
+ | RProd (loc,n,r1,r2) ->
+ let r1' = subst_raw subst r1 and r2' = subst_raw subst r2 in
+ if r1' == r1 && r2' == r2 then raw else
+ RProd (loc,n,r1',r2')
+
+ | RLetIn (loc,n,r1,r2) ->
+ let r1' = subst_raw subst r1 and r2' = subst_raw subst r2 in
+ if r1' == r1 && r2' == r2 then raw else
+ RLetIn (loc,n,r1',r2')
+
+ | RCases (loc,(ro,rtno),rl,branches) ->
+ let ro' = option_smartmap (subst_raw subst) ro
+ and rtno' = ref (option_smartmap (subst_raw subst) !rtno)
+ and rl' = list_smartmap (fun (a,x as y) ->
+ let a' = subst_raw subst a in
+ let (n,topt) = !x in
+ let topt' = option_smartmap
+ (fun (loc,(sp,i),x as t) ->
+ let sp' = subst_kn subst sp in
+ if sp == sp' then t else (loc,(sp',i),x)) topt in
+ if a == a' && topt == topt' then y else (a',ref (n,topt'))) rl
+ and branches' = list_smartmap
+ (fun (loc,idl,cpl,r as branch) ->
+ let cpl' = list_smartmap (subst_pat subst) cpl
+ and r' = subst_raw subst r in
+ if cpl' == cpl && r' == r then branch else
+ (loc,idl,cpl',r'))
+ branches
+ in
+ if ro' == ro && rl' == rl && branches' == branches then raw else
+ RCases (loc,(ro',rtno'),rl',branches')
+
+ | ROrderedCase (loc,b,ro,r,ra,x) ->
+ let ro' = option_smartmap (subst_raw subst) ro
+ and r' = subst_raw subst r
+ and ra' = array_smartmap (subst_raw subst) ra in
+ if ro' == ro && r' == r && ra' == ra then raw else
+ ROrderedCase (loc,b,ro',r',ra',x)
+
+ | RLetTuple (loc,nal,(na,po),b,c) ->
+ let po' = option_smartmap (subst_raw subst) po
+ and b' = subst_raw subst b
+ and c' = subst_raw subst c in
+ if po' == po && b' == b && c' == c then raw else
+ RLetTuple (loc,nal,(na,po'),b',c')
+
+ | RIf (loc,c,(na,po),b1,b2) ->
+ let po' = option_smartmap (subst_raw subst) po
+ and b1' = subst_raw subst b1
+ and b2' = subst_raw subst b2
+ and c' = subst_raw subst c in
+ if c' == c & po' == po && b1' == b1 && b2' == b2 then raw else
+ RIf (loc,c',(na,po'),b1',b2')
+
+ | RRec (loc,fix,ida,bl,ra1,ra2) ->
+ let ra1' = array_smartmap (subst_raw subst) ra1
+ and ra2' = array_smartmap (subst_raw subst) ra2 in
+ let bl' = array_smartmap
+ (list_smartmap (fun (na,obd,ty as dcl) ->
+ let ty' = subst_raw subst ty in
+ let obd' = option_smartmap (subst_raw subst) obd in
+ if ty'==ty & obd'==obd then dcl else (na,obd',ty')))
+ bl in
+ if ra1' == ra1 && ra2' == ra2 && bl'==bl then raw else
+ RRec (loc,fix,ida,bl',ra1',ra2')
+
+ | RSort _ -> raw
+
+ | RHole (loc,ImplicitArg (ref,i)) ->
+ let ref' = subst_global subst ref in
+ if ref' == ref then raw else
+ RHole (loc,ImplicitArg (ref',i))
+ | RHole (loc, (BinderType _ | QuestionMark | CasesType |
+ InternalHole | TomatchTypeParameter _)) -> raw
+
+ | RCast (loc,r1,r2) ->
+ let r1' = subst_raw subst r1 and r2' = subst_raw subst r2 in
+ if r1' == r1 && r2' == r2 then raw else
+ RCast (loc,r1',r2')
+
+ | RDynamic _ -> raw
+
+let loc_of_rawconstr = function
+ | RRef (loc,_) -> loc
+ | RVar (loc,_) -> loc
+ | REvar (loc,_,_) -> loc
+ | RPatVar (loc,_) -> loc
+ | RApp (loc,_,_) -> loc
+ | RLambda (loc,_,_,_) -> loc
+ | RProd (loc,_,_,_) -> loc
+ | RLetIn (loc,_,_,_) -> loc
+ | RCases (loc,_,_,_) -> loc
+ | ROrderedCase (loc,_,_,_,_,_) -> loc
+ | RLetTuple (loc,_,_,_,_) -> loc
+ | RIf (loc,_,_,_,_) -> loc
+ | RRec (loc,_,_,_,_,_) -> loc
+ | RSort (loc,_) -> loc
+ | RHole (loc,_) -> loc
+ | RCast (loc,_,_) -> loc
+ | RDynamic (loc,_) -> loc
+
+type 'a raw_red_flag = {
+ rBeta : bool;
+ rIota : bool;
+ rZeta : bool;
+ rDelta : bool; (* true = delta all but rConst; false = delta only on rConst*)
+ rConst : 'a list
+}
+
+let all_flags =
+ {rBeta = true; rIota = true; rZeta = true; rDelta = true; rConst = []}
+
+type 'a occurrences = int list * 'a
+
+type ('a,'b) red_expr_gen =
+ | Red of bool
+ | Hnf
+ | Simpl of 'a occurrences option
+ | Cbv of 'b raw_red_flag
+ | Lazy of 'b raw_red_flag
+ | Unfold of 'b occurrences list
+ | Fold of 'a list
+ | Pattern of 'a occurrences list
+ | ExtraRedExpr of string * 'a
+
+type ('a,'b) may_eval =
+ | ConstrTerm of 'a
+ | ConstrEval of ('a, 'b) red_expr_gen * 'a
+ | ConstrContext of (loc * identifier) * 'a
+ | ConstrTypeOf of 'a
diff --git a/pretyping/rawterm.mli b/pretyping/rawterm.mli
new file mode 100644
index 00000000..d78d1866
--- /dev/null
+++ b/pretyping/rawterm.mli
@@ -0,0 +1,139 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: rawterm.mli,v 1.47.2.2 2004/07/16 19:30:46 herbelin Exp $ i*)
+
+(*i*)
+open Util
+open Names
+open Sign
+open Term
+open Libnames
+open Nametab
+(*i*)
+
+(* Untyped intermediate terms, after ASTs and before constr. *)
+
+(* locs here refers to the ident's location, not whole pat *)
+(* the last argument of PatCstr is a possible alias ident for the pattern *)
+type cases_pattern =
+ | PatVar of loc * name
+ | PatCstr of loc * constructor * cases_pattern list * name
+
+val pattern_loc : cases_pattern -> loc
+
+type patvar = identifier
+
+type rawsort = RProp of Term.contents | RType of Univ.universe option
+
+type fix_kind = RFix of (int array * int) | RCoFix of int
+
+type binder_kind = BProd | BLambda | BLetIn
+
+type quantified_hypothesis = AnonHyp of int | NamedHyp of identifier
+
+type 'a explicit_bindings = (loc * quantified_hypothesis * 'a) list
+
+type 'a bindings =
+ | ImplicitBindings of 'a list
+ | ExplicitBindings of 'a explicit_bindings
+ | NoBindings
+
+type 'a with_bindings = 'a * 'a bindings
+
+type hole_kind =
+ | ImplicitArg of global_reference * int
+ | BinderType of name
+ | QuestionMark
+ | CasesType
+ | InternalHole
+ | TomatchTypeParameter of inductive * int
+
+type rawconstr =
+ | RRef of (loc * global_reference)
+ | RVar of (loc * identifier)
+ | REvar of loc * existential_key * rawconstr list option
+ | RPatVar of loc * (bool * patvar) (* Used for patterns only *)
+ | RApp of loc * rawconstr * rawconstr list
+ | RLambda of loc * name * rawconstr * rawconstr
+ | RProd of loc * name * rawconstr * rawconstr
+ | RLetIn of loc * name * rawconstr * rawconstr
+ | RCases of loc * (rawconstr option * rawconstr option ref) *
+ (rawconstr * (name * (loc * inductive * name list) option) ref) list *
+ (loc * identifier list * cases_pattern list * rawconstr) list
+ | ROrderedCase of loc * case_style * rawconstr option * rawconstr *
+ rawconstr array * rawconstr option ref
+ | RLetTuple of loc * name list * (name * rawconstr option) *
+ rawconstr * rawconstr
+ | RIf of loc * rawconstr * (name * rawconstr option) * rawconstr * rawconstr
+ | RRec of loc * fix_kind * identifier array * rawdecl list array *
+ rawconstr array * rawconstr array
+ | RSort of loc * rawsort
+ | RHole of (loc * hole_kind)
+ | RCast of loc * rawconstr * rawconstr
+ | RDynamic of loc * Dyn.t
+
+and rawdecl = name * rawconstr option * rawconstr
+
+val cases_predicate_names :
+ (rawconstr * (name * (loc * inductive * name list) option) ref) list ->
+ name list
+
+(*i - if PRec (_, names, arities, bodies) is in env then arities are
+ typed in env too and bodies are typed in env enriched by the
+ arities incrementally lifted
+
+ [On pourrait plutot mettre les arités aves le type qu'elles auront
+ dans le contexte servant à typer les body ???]
+
+ - boolean in POldCase means it is recursive
+ - option in PHole tell if the "?" was apparent or has been implicitely added
+i*)
+
+val map_rawconstr : (rawconstr -> rawconstr) -> rawconstr -> rawconstr
+
+(*
+val map_rawconstr_with_binders_loc : loc ->
+ (identifier -> 'a -> identifier * 'a) ->
+ ('a -> rawconstr -> rawconstr) -> 'a -> rawconstr -> rawconstr
+*)
+
+val occur_rawconstr : identifier -> rawconstr -> bool
+
+val loc_of_rawconstr : rawconstr -> loc
+
+val subst_raw : Names.substitution -> rawconstr -> rawconstr
+
+type 'a raw_red_flag = {
+ rBeta : bool;
+ rIota : bool;
+ rZeta : bool;
+ rDelta : bool; (* true = delta all but rConst; false = delta only on rConst*)
+ rConst : 'a list
+}
+
+val all_flags : 'a raw_red_flag
+
+type 'a occurrences = int list * 'a
+
+type ('a,'b) red_expr_gen =
+ | Red of bool
+ | Hnf
+ | Simpl of 'a occurrences option
+ | Cbv of 'b raw_red_flag
+ | Lazy of 'b raw_red_flag
+ | Unfold of 'b occurrences list
+ | Fold of 'a list
+ | Pattern of 'a occurrences list
+ | ExtraRedExpr of string * 'a
+
+type ('a,'b) may_eval =
+ | ConstrTerm of 'a
+ | ConstrEval of ('a, 'b) red_expr_gen * 'a
+ | ConstrContext of (loc * identifier) * 'a
+ | ConstrTypeOf of 'a
diff --git a/pretyping/recordops.ml b/pretyping/recordops.ml
new file mode 100755
index 00000000..f34d5624
--- /dev/null
+++ b/pretyping/recordops.ml
@@ -0,0 +1,176 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: recordops.ml,v 1.26.2.1 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Util
+open Pp
+open Names
+open Libnames
+open Nametab
+open Term
+open Termops
+open Typeops
+open Libobject
+open Library
+open Classops
+
+let nbimpl = ref 0
+let nbpathc = ref 0
+let nbcoer = ref 0
+let nbstruc = ref 0
+let nbimplstruc = ref 0
+
+let compter = ref false
+
+(*s Une structure S est un type inductif non récursif à un seul
+ constructeur (de nom par défaut Build_S) *)
+
+(* Table des structures: le nom de la structure (un [inductive]) donne
+ le nom du constructeur, le nombre de paramètres et pour chaque
+ argument réels du constructeur, le noms de la projection
+ correspondante, si valide *)
+
+type struc_typ = {
+ s_CONST : identifier;
+ s_PARAM : int;
+ s_PROJ : constant option list }
+
+let structure_table = ref (Indmap.empty : struc_typ Indmap.t)
+let projection_table = ref KNmap.empty
+
+let option_fold_right f p e = match p with Some a -> f a e | None -> e
+
+let cache_structure (_,(ind,struc)) =
+ structure_table := Indmap.add ind struc !structure_table;
+ projection_table :=
+ List.fold_right (option_fold_right (fun proj -> KNmap.add proj struc))
+ struc.s_PROJ !projection_table
+
+let subst_structure (_,subst,((kn,i),struc as obj)) =
+ let kn' = subst_kn subst kn in
+ let proj' = list_smartmap
+ (option_smartmap (subst_kn subst))
+ struc.s_PROJ
+ in
+ if proj' == struc.s_PROJ && kn' == kn then obj else
+ (kn',i),{struc with s_PROJ = proj'}
+
+let (inStruc,outStruc) =
+ declare_object {(default_object "STRUCTURE") with
+ cache_function = cache_structure;
+ load_function = (fun _ o -> cache_structure o);
+ subst_function = subst_structure;
+ classify_function = (fun (_,x) -> Substitute x);
+ export_function = (function x -> Some x) }
+
+let add_new_struc (s,c,n,l) =
+ Lib.add_anonymous_leaf (inStruc (s,{s_CONST=c;s_PARAM=n;s_PROJ=l}))
+
+let find_structure indsp = Indmap.find indsp !structure_table
+
+let find_projection_nparams = function
+ | ConstRef cst -> (KNmap.find cst !projection_table).s_PARAM
+ | _ -> raise Not_found
+
+(*s Un "object" est une fonction construisant une instance d'une structure *)
+
+(* Table des definitions "object" : pour chaque object c,
+
+ c := [x1:B1]...[xk:Bk](Build_R a1...am t1...t_n)
+
+ avec ti = (ci ui1...uir)
+
+ Pour tout ci, et Li, la ième projection de la structure R (si
+ définie), on déclare une "coercion"
+
+ o_DEF = c
+ o_TABS = B1...Bk
+ o_PARAMS = a1...am
+ o_TCOMP = ui1...uir
+*)
+
+type obj_typ = {
+ o_DEF : constr;
+ o_TABS : constr list; (* dans l'ordre *)
+ o_TPARAMS : constr list; (* dans l'ordre *)
+ o_TCOMPS : constr list } (* dans l'ordre *)
+
+let subst_obj subst obj =
+ let o_DEF' = subst_mps subst obj.o_DEF in
+ let o_TABS' = list_smartmap (subst_mps subst) obj.o_TABS in
+ let o_TPARAMS' = list_smartmap (subst_mps subst) obj.o_TPARAMS in
+ let o_TCOMPS' = list_smartmap (subst_mps subst) obj.o_TCOMPS in
+ if o_DEF' == obj.o_DEF
+ && o_TABS' == obj.o_TABS
+ && o_TPARAMS' == obj.o_TPARAMS
+ && o_TCOMPS' == obj.o_TCOMPS
+ then
+ obj
+ else
+ { o_DEF = o_DEF' ;
+ o_TABS = o_TABS' ;
+ o_TPARAMS = o_TPARAMS' ;
+ o_TCOMPS = o_TCOMPS' }
+
+let object_table =
+ (ref [] : ((global_reference * global_reference) * obj_typ) list ref)
+
+let cache_object (_,x) = object_table := x :: (!object_table)
+
+let subst_object (_,subst,((r1,r2),o as obj)) =
+ let r1' = subst_global subst r1 in
+ let r2' = subst_global subst r2 in
+ let o' = subst_obj subst o in
+ if r1' == r1 && r2' == r2 && o' == o then obj else
+ (r1',r2'),o'
+
+let (inObjDef,outObjDef) =
+ declare_object {(default_object "OBJDEF") with
+ open_function = (fun i o -> if i=1 then cache_object o);
+ cache_function = cache_object;
+ subst_function = subst_object;
+ classify_function = (fun (_,x) -> Substitute x);
+ export_function = (function x -> Some x) }
+
+let add_new_objdef (o,c,la,lp,l) =
+ try
+ let _ = List.assoc o !object_table in ()
+ with Not_found ->
+ Lib.add_anonymous_leaf
+ (inObjDef (o,{o_DEF=c;o_TABS=la;o_TPARAMS=lp;o_TCOMPS=l}))
+
+let cache_objdef1 (_,sp) = ()
+
+let (inObjDef1,outObjDef1) =
+ declare_object {(default_object "OBJDEF1") with
+ open_function = (fun i o -> if i=1 then cache_objdef1 o);
+ cache_function = cache_objdef1;
+ export_function = (function x -> Some x) }
+
+let objdef_info o = List.assoc o !object_table
+
+let freeze () =
+ !structure_table, !projection_table, !object_table
+
+let unfreeze (s,p,o) =
+ structure_table := s; projection_table := p; object_table := o
+
+let init () =
+ structure_table := Indmap.empty; projection_table := KNmap.empty;
+ object_table:=[]
+
+let _ = init()
+
+let _ =
+ Summary.declare_summary "objdefs"
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init;
+ Summary.survive_module = false;
+ Summary.survive_section = false }
diff --git a/pretyping/recordops.mli b/pretyping/recordops.mli
new file mode 100755
index 00000000..66c1f34d
--- /dev/null
+++ b/pretyping/recordops.mli
@@ -0,0 +1,58 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: recordops.mli,v 1.15.2.1 2004/07/16 19:30:46 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Nametab
+open Term
+open Libnames
+open Classops
+open Libobject
+open Library
+(*i*)
+
+val nbimpl : int ref
+val nbpathc : int ref
+val nbcoer : int ref
+val nbstruc : int ref
+val nbimplstruc : int ref
+val compter : bool ref
+
+type struc_typ = {
+ s_CONST : identifier;
+ s_PARAM : int;
+ s_PROJ : constant option list }
+
+val add_new_struc :
+ inductive * identifier * int * constant option list -> unit
+
+(* [find_structure isp] returns the infos associated to inductive path
+ [isp] if it corresponds to a structure, otherwise fails with [Not_found] *)
+val find_structure : inductive -> struc_typ
+
+(* raise [Not_found] if not a projection *)
+val find_projection_nparams : global_reference -> int
+
+type obj_typ = {
+ o_DEF : constr;
+ o_TABS : constr list; (* dans l'ordre *)
+ o_TPARAMS : constr list; (* dans l'ordre *)
+ o_TCOMPS : constr list } (* dans l'ordre *)
+
+val objdef_info : (global_reference * global_reference) -> obj_typ
+val add_new_objdef :
+ (global_reference * global_reference) * Term.constr * Term.constr list *
+ Term.constr list * Term.constr list -> unit
+
+
+val inStruc : inductive * struc_typ -> obj
+val outStruc : obj -> inductive * struc_typ
+val inObjDef1 : kernel_name -> obj
+val outObjDef1 : obj -> kernel_name
diff --git a/pretyping/reductionops.ml b/pretyping/reductionops.ml
new file mode 100644
index 00000000..a030dcf2
--- /dev/null
+++ b/pretyping/reductionops.ml
@@ -0,0 +1,717 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: reductionops.ml,v 1.6.2.2 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Term
+open Termops
+open Univ
+open Evd
+open Declarations
+open Environ
+open Instantiate
+open Closure
+open Esubst
+open Reduction
+
+exception Elimconst
+
+(* The type of (machine) states (= lambda-bar-calculus' cuts) *)
+type state = constr * constr stack
+
+type contextual_reduction_function = env -> evar_map -> constr -> constr
+type reduction_function = contextual_reduction_function
+type local_reduction_function = constr -> constr
+
+type contextual_stack_reduction_function =
+ env -> evar_map -> constr -> constr * constr list
+type stack_reduction_function = contextual_stack_reduction_function
+type local_stack_reduction_function = constr -> constr * constr list
+
+type contextual_state_reduction_function =
+ env -> evar_map -> state -> state
+type state_reduction_function = contextual_state_reduction_function
+type local_state_reduction_function = state -> state
+
+(*************************************)
+(*** Reduction Functions Operators ***)
+(*************************************)
+
+let rec whd_state (x, stack as s) =
+ match kind_of_term x with
+ | App (f,cl) -> whd_state (f, append_stack cl stack)
+ | Cast (c,_) -> whd_state (c, stack)
+ | _ -> s
+
+let appterm_of_stack (f,s) = (f,list_of_stack s)
+
+let whd_stack x = appterm_of_stack (whd_state (x, empty_stack))
+let whd_castapp_stack = whd_stack
+
+let stack_reduction_of_reduction red_fun env sigma s =
+ let t = red_fun env sigma (app_stack s) in
+ whd_stack t
+
+let strong whdfun env sigma t =
+ let rec strongrec env t =
+ map_constr_with_full_binders push_rel strongrec env (whdfun env sigma t) in
+ strongrec env t
+
+let local_strong whdfun =
+ let rec strongrec t = map_constr strongrec (whdfun t) in
+ strongrec
+
+let rec strong_prodspine redfun c =
+ let x = redfun c in
+ match kind_of_term x with
+ | Prod (na,a,b) -> mkProd (na,a,strong_prodspine redfun b)
+ | _ -> x
+
+(*************************************)
+(*** Reduction using bindingss ***)
+(*************************************)
+
+(* This signature is very similar to Closure.RedFlagsSig except there
+ is eta but no per-constant unfolding *)
+
+module type RedFlagsSig = sig
+ type flags
+ type flag
+ val fbeta : flag
+ val fevar : flag
+ val fdelta : flag
+ val feta : flag
+ val fiota : flag
+ val fzeta : flag
+ val mkflags : flag list -> flags
+ val red_beta : flags -> bool
+ val red_delta : flags -> bool
+ val red_evar : flags -> bool
+ val red_eta : flags -> bool
+ val red_iota : flags -> bool
+ val red_zeta : flags -> bool
+end
+
+(* Naive Implementation
+module RedFlags = (struct
+ type flag = BETA | DELTA | EVAR | IOTA | ZETA | ETA
+ type flags = flag list
+ let fbeta = BETA
+ let fdelta = DELTA
+ let fevar = EVAR
+ let fiota = IOTA
+ let fzeta = ZETA
+ let feta = ETA
+ let mkflags l = l
+ let red_beta = List.mem BETA
+ let red_delta = List.mem DELTA
+ let red_evar = List.mem EVAR
+ let red_eta = List.mem ETA
+ let red_iota = List.mem IOTA
+ let red_zeta = List.mem ZETA
+end : RedFlagsSig)
+*)
+
+(* Compact Implementation *)
+module RedFlags = (struct
+ type flag = int
+ type flags = int
+ let fbeta = 1
+ let fdelta = 2
+ let fevar = 4
+ let feta = 8
+ let fiota = 16
+ let fzeta = 32
+ let mkflags = List.fold_left (lor) 0
+ let red_beta f = f land fbeta <> 0
+ let red_delta f = f land fdelta <> 0
+ let red_evar f = f land fevar <> 0
+ let red_eta f = f land feta <> 0
+ let red_iota f = f land fiota <> 0
+ let red_zeta f = f land fzeta <> 0
+end : RedFlagsSig)
+
+open RedFlags
+
+(* Local *)
+let beta = mkflags [fbeta]
+let evar = mkflags [fevar]
+let betaevar = mkflags [fevar; fbeta]
+let betaiota = mkflags [fiota; fbeta]
+let betaiotazeta = mkflags [fiota; fbeta;fzeta]
+
+(* Contextual *)
+let delta = mkflags [fdelta;fevar]
+let betadelta = mkflags [fbeta;fdelta;fzeta;fevar]
+let betadeltaeta = mkflags [fbeta;fdelta;fzeta;fevar;feta]
+let betadeltaiota = mkflags [fbeta;fdelta;fzeta;fevar;fiota]
+let betadeltaiota_nolet = mkflags [fbeta;fdelta;fevar;fiota]
+let betadeltaiotaeta = mkflags [fbeta;fdelta;fzeta;fevar;fiota;feta]
+let betaiotaevar = mkflags [fbeta;fiota;fevar]
+let betaetalet = mkflags [fbeta;feta;fzeta]
+let betalet = mkflags [fbeta;fzeta]
+
+(* Beta Reduction tools *)
+
+let rec stacklam recfun env t stack =
+ match (decomp_stack stack,kind_of_term t) with
+ | Some (h,stacktl), Lambda (_,_,c) -> stacklam recfun (h::env) c stacktl
+ | _ -> recfun (substl env t, stack)
+
+let beta_applist (c,l) =
+ stacklam app_stack [] c (append_stack (Array.of_list l) empty_stack)
+
+(* Iota reduction tools *)
+
+type 'a miota_args = {
+ mP : constr; (* the result type *)
+ mconstr : constr; (* the constructor *)
+ mci : case_info; (* special info to re-build pattern *)
+ mcargs : 'a list; (* the constructor's arguments *)
+ mlf : 'a array } (* the branch code vector *)
+
+let reducible_mind_case c = match kind_of_term c with
+ | Construct _ | CoFix _ -> true
+ | _ -> false
+
+let contract_cofix (bodynum,(types,names,bodies as typedbodies)) =
+ let nbodies = Array.length bodies in
+ let make_Fi j = mkCoFix (nbodies-j-1,typedbodies) in
+ substl (list_tabulate make_Fi nbodies) bodies.(bodynum)
+
+let reduce_mind_case mia =
+ match kind_of_term mia.mconstr with
+ | Construct (ind_sp,i as cstr_sp) ->
+(* let ncargs = (fst mia.mci).(i-1) in*)
+ let real_cargs = list_skipn mia.mci.ci_npar mia.mcargs in
+ applist (mia.mlf.(i-1),real_cargs)
+ | CoFix cofix ->
+ let cofix_def = contract_cofix cofix in
+ mkCase (mia.mci, mia.mP, applist(cofix_def,mia.mcargs), mia.mlf)
+ | _ -> assert false
+
+(* contracts fix==FIX[nl;i](A1...Ak;[F1...Fk]{B1....Bk}) to produce
+ Bi[Fj --> FIX[nl;j](A1...Ak;[F1...Fk]{B1...Bk})] *)
+
+let contract_fix ((recindices,bodynum),(types,names,bodies as typedbodies)) =
+ let nbodies = Array.length recindices in
+ let make_Fi j = mkFix ((recindices,nbodies-j-1),typedbodies) in
+ substl (list_tabulate make_Fi nbodies) bodies.(bodynum)
+
+let fix_recarg ((recindices,bodynum),_) stack =
+ assert (0 <= bodynum & bodynum < Array.length recindices);
+ let recargnum = Array.get recindices bodynum in
+ try
+ Some (recargnum, stack_nth stack recargnum)
+ with Not_found ->
+ None
+
+type fix_reduction_result = NotReducible | Reduced of state
+
+let reduce_fix whdfun fix stack =
+ match fix_recarg fix stack with
+ | None -> NotReducible
+ | Some (recargnum,recarg) ->
+ let (recarg'hd,_ as recarg') = whdfun (recarg, empty_stack) in
+ let stack' = stack_assign stack recargnum (app_stack recarg') in
+ (match kind_of_term recarg'hd with
+ | Construct _ -> Reduced (contract_fix fix, stack')
+ | _ -> NotReducible)
+
+(* Generic reduction function *)
+
+(* Y avait un commentaire pour whd_betadeltaiota :
+
+ NB : Cette fonction alloue peu c'est l'appel
+ ``let (c,cargs) = whfun (recarg, empty_stack)''
+ -------------------
+ qui coute cher *)
+
+let rec whd_state_gen flags env sigma =
+ let rec whrec (x, stack as s) =
+ match kind_of_term x with
+ | Rel n when red_delta flags ->
+ (match lookup_rel n env with
+ | (_,Some body,_) -> whrec (lift n body, stack)
+ | _ -> s)
+ | Var id when red_delta flags ->
+ (match lookup_named id env with
+ | (_,Some body,_) -> whrec (body, stack)
+ | _ -> s)
+ | Evar ev when red_evar flags ->
+ (match existential_opt_value sigma ev with
+ | Some body -> whrec (body, stack)
+ | None -> s)
+ | Const const when red_delta flags ->
+ (match constant_opt_value env const with
+ | Some body -> whrec (body, stack)
+ | None -> s)
+ | LetIn (_,b,_,c) when red_zeta flags -> stacklam whrec [b] c stack
+ | Cast (c,_) -> whrec (c, stack)
+ | App (f,cl) -> whrec (f, append_stack cl stack)
+ | Lambda (na,t,c) ->
+ (match decomp_stack stack with
+ | Some (a,m) when red_beta flags -> stacklam whrec [a] c m
+ | None when red_eta flags ->
+ let env' = push_rel (na,None,t) env in
+ let whrec' = whd_state_gen flags env' sigma in
+ (match kind_of_term (app_stack (whrec' (c, empty_stack))) with
+ | App (f,cl) ->
+ let napp = Array.length cl in
+ if napp > 0 then
+ let x', l' = whrec' (array_last cl, empty_stack) in
+ match kind_of_term x', decomp_stack l' with
+ | Rel 1, None ->
+ let lc = Array.sub cl 0 (napp-1) in
+ let u = if napp=1 then f else appvect (f,lc) in
+ if noccurn 1 u then (pop u,empty_stack) else s
+ | _ -> s
+ else s
+ | _ -> s)
+ | _ -> s)
+
+ | Case (ci,p,d,lf) when red_iota flags ->
+ let (c,cargs) = whrec (d, empty_stack) in
+ if reducible_mind_case c then
+ whrec (reduce_mind_case
+ {mP=p; mconstr=c; mcargs=list_of_stack cargs;
+ mci=ci; mlf=lf}, stack)
+ else
+ (mkCase (ci, p, app_stack (c,cargs), lf), stack)
+
+ | Fix fix when red_iota flags ->
+ (match reduce_fix whrec fix stack with
+ | Reduced s' -> whrec s'
+ | NotReducible -> s)
+
+ | x -> s
+ in
+ whrec
+
+let local_whd_state_gen flags =
+ let rec whrec (x, stack as s) =
+ match kind_of_term x with
+ | LetIn (_,b,_,c) when red_zeta flags -> stacklam whrec [b] c stack
+ | Cast (c,_) -> whrec (c, stack)
+ | App (f,cl) -> whrec (f, append_stack cl stack)
+ | Lambda (_,_,c) ->
+ (match decomp_stack stack with
+ | Some (a,m) when red_beta flags -> stacklam whrec [a] c m
+ | None when red_eta flags ->
+ (match kind_of_term (app_stack (whrec (c, empty_stack))) with
+ | App (f,cl) ->
+ let napp = Array.length cl in
+ if napp > 0 then
+ let x', l' = whrec (array_last cl, empty_stack) in
+ match kind_of_term x', decomp_stack l' with
+ | Rel 1, None ->
+ let lc = Array.sub cl 0 (napp-1) in
+ let u = if napp=1 then f else appvect (f,lc) in
+ if noccurn 1 u then (pop u,empty_stack) else s
+ | _ -> s
+ else s
+ | _ -> s)
+ | _ -> s)
+
+ | Case (ci,p,d,lf) when red_iota flags ->
+ let (c,cargs) = whrec (d, empty_stack) in
+ if reducible_mind_case c then
+ whrec (reduce_mind_case
+ {mP=p; mconstr=c; mcargs=list_of_stack cargs;
+ mci=ci; mlf=lf}, stack)
+ else
+ (mkCase (ci, p, app_stack (c,cargs), lf), stack)
+
+ | Fix fix when red_iota flags ->
+ (match reduce_fix whrec fix stack with
+ | Reduced s' -> whrec s'
+ | NotReducible -> s)
+
+ | x -> s
+ in
+ whrec
+
+(* 1. Beta Reduction Functions *)
+
+let whd_beta_state = local_whd_state_gen beta
+let whd_beta_stack x = appterm_of_stack (whd_beta_state (x, empty_stack))
+let whd_beta x = app_stack (whd_beta_state (x,empty_stack))
+
+(* Nouveau ! *)
+let whd_betaetalet_state = local_whd_state_gen betaetalet
+let whd_betaetalet_stack x =
+ appterm_of_stack (whd_betaetalet_state (x, empty_stack))
+let whd_betaetalet x = app_stack (whd_betaetalet_state (x,empty_stack))
+
+let whd_betalet_state = local_whd_state_gen betalet
+let whd_betalet_stack x = appterm_of_stack (whd_betalet_state (x, empty_stack))
+let whd_betalet x = app_stack (whd_betalet_state (x,empty_stack))
+
+(* 2. Delta Reduction Functions *)
+
+let whd_delta_state e = whd_state_gen delta e
+let whd_delta_stack env sigma x =
+ appterm_of_stack (whd_delta_state env sigma (x, empty_stack))
+let whd_delta env sigma c =
+ app_stack (whd_delta_state env sigma (c, empty_stack))
+
+let whd_betadelta_state e = whd_state_gen betadelta e
+let whd_betadelta_stack env sigma x =
+ appterm_of_stack (whd_betadelta_state env sigma (x, empty_stack))
+let whd_betadelta env sigma c =
+ app_stack (whd_betadelta_state env sigma (c, empty_stack))
+
+let whd_betaevar_state e = whd_state_gen betaevar e
+let whd_betaevar_stack env sigma c =
+ appterm_of_stack (whd_betaevar_state env sigma (c, empty_stack))
+let whd_betaevar env sigma c =
+ app_stack (whd_betaevar_state env sigma (c, empty_stack))
+
+
+let whd_betadeltaeta_state e = whd_state_gen betadeltaeta e
+let whd_betadeltaeta_stack env sigma x =
+ appterm_of_stack (whd_betadeltaeta_state env sigma (x, empty_stack))
+let whd_betadeltaeta env sigma x =
+ app_stack (whd_betadeltaeta_state env sigma (x, empty_stack))
+
+(* 3. Iota reduction Functions *)
+
+let whd_betaiota_state = local_whd_state_gen betaiota
+let whd_betaiota_stack x =
+ appterm_of_stack (whd_betaiota_state (x, empty_stack))
+let whd_betaiota x =
+ app_stack (whd_betaiota_state (x, empty_stack))
+
+let whd_betaiotazeta_state = local_whd_state_gen betaiotazeta
+let whd_betaiotazeta_stack x =
+ appterm_of_stack (whd_betaiotazeta_state (x, empty_stack))
+let whd_betaiotazeta x =
+ app_stack (whd_betaiotazeta_state (x, empty_stack))
+
+let whd_betaiotaevar_state e = whd_state_gen betaiotaevar e
+let whd_betaiotaevar_stack env sigma x =
+ appterm_of_stack (whd_betaiotaevar_state env sigma (x, empty_stack))
+let whd_betaiotaevar env sigma x =
+ app_stack (whd_betaiotaevar_state env sigma (x, empty_stack))
+
+let whd_betadeltaiota_state e = whd_state_gen betadeltaiota e
+let whd_betadeltaiota_stack env sigma x =
+ appterm_of_stack (whd_betadeltaiota_state env sigma (x, empty_stack))
+let whd_betadeltaiota env sigma x =
+ app_stack (whd_betadeltaiota_state env sigma (x, empty_stack))
+
+let whd_betadeltaiotaeta_state e = whd_state_gen betadeltaiotaeta e
+let whd_betadeltaiotaeta_stack env sigma x =
+ appterm_of_stack (whd_betadeltaiotaeta_state env sigma (x, empty_stack))
+let whd_betadeltaiotaeta env sigma x =
+ app_stack (whd_betadeltaiotaeta_state env sigma (x, empty_stack))
+
+let whd_betadeltaiota_nolet_state e = whd_state_gen betadeltaiota_nolet e
+let whd_betadeltaiota_nolet_stack env sigma x =
+ appterm_of_stack (whd_betadeltaiota_nolet_state env sigma (x, empty_stack))
+let whd_betadeltaiota_nolet env sigma x =
+ app_stack (whd_betadeltaiota_nolet_state env sigma (x, empty_stack))
+
+(****************************************************************************)
+(* Reduction Functions *)
+(****************************************************************************)
+
+(* Replacing defined evars for error messages *)
+let rec whd_evar sigma c =
+ match kind_of_term c with
+ | Evar (ev,args) when Evd.in_dom sigma ev & Evd.is_defined sigma ev ->
+ whd_evar sigma (Instantiate.existential_value sigma (ev,args))
+ | _ -> collapse_appl c
+
+let nf_evar sigma =
+ local_strong (whd_evar sigma)
+
+(* lazy reduction functions. The infos must be created for each term *)
+let clos_norm_flags flgs env sigma t =
+ norm_val (create_clos_infos flgs env) (inject (nf_evar sigma t))
+
+let nf_beta = clos_norm_flags Closure.beta empty_env Evd.empty
+let nf_betaiota = clos_norm_flags Closure.betaiota empty_env Evd.empty
+let nf_betadeltaiota env sigma =
+ clos_norm_flags Closure.betadeltaiota env sigma
+
+(* lazy weak head reduction functions *)
+let whd_flags flgs env sigma t =
+ whd_val (create_clos_infos flgs env) (inject (nf_evar sigma t))
+
+(********************************************************************)
+(* Conversion *)
+(********************************************************************)
+(*
+let fkey = Profile.declare_profile "fhnf";;
+let fhnf info v = Profile.profile2 fkey fhnf info v;;
+
+let fakey = Profile.declare_profile "fhnf_apply";;
+let fhnf_apply info k h a = Profile.profile4 fakey fhnf_apply info k h a;;
+*)
+
+(* Conversion utility functions *)
+
+type conversion_test = constraints -> constraints
+
+type conv_pb =
+ | CONV
+ | CUMUL
+
+let pb_is_equal pb = pb = CONV
+
+let pb_equal = function
+ | CUMUL -> CONV
+ | CONV -> CONV
+
+let sort_cmp pb s0 s1 cuniv =
+ match (s0,s1) with
+ | (Prop c1, Prop c2) -> if c1 = c2 then cuniv else raise NotConvertible
+ | (Prop c1, Type u) ->
+ (match pb with
+ CUMUL -> cuniv
+ | _ -> raise NotConvertible)
+ | (Type u1, Type u2) ->
+ (match pb with
+ | CONV -> enforce_eq u1 u2 cuniv
+ | CUMUL -> enforce_geq u2 u1 cuniv)
+ | (_, _) -> raise NotConvertible
+
+let base_sort_cmp pb s0 s1 =
+ match (s0,s1) with
+ | (Prop c1, Prop c2) -> c1 = c2
+ | (Prop c1, Type u) -> pb = CUMUL
+ | (Type u1, Type u2) -> true
+ | (_, _) -> false
+
+
+let test_conversion f env sigma x y =
+ try let _ = f env (nf_evar sigma x) (nf_evar sigma y) in true
+ with NotConvertible -> false
+
+let is_conv env sigma = test_conversion Reduction.conv env sigma
+let is_conv_leq env sigma = test_conversion Reduction.conv_leq env sigma
+let is_fconv = function | CONV -> is_conv | CUMUL -> is_conv_leq
+
+(********************************************************************)
+(* Special-Purpose Reduction *)
+(********************************************************************)
+
+let whd_meta metamap c = match kind_of_term c with
+ | Meta p -> (try List.assoc p metamap with Not_found -> c)
+ | _ -> c
+
+(* Try to replace all metas. Does not replace metas in the metas' values
+ * Differs from (strong whd_meta). *)
+let plain_instance s c =
+ let rec irec u = match kind_of_term u with
+ | Meta p -> (try List.assoc p s with Not_found -> u)
+ | App (f,l) when isCast f ->
+ let (f,t) = destCast f in
+ let l' = Array.map irec l in
+ (match kind_of_term f with
+ | Meta p ->
+ (* Don't flatten application nodes: this is used to extract a
+ proof-term from a proof-tree and we want to keep the structure
+ of the proof-tree *)
+ (try let g = List.assoc p s in
+ match kind_of_term g with
+ | App _ ->
+ let h = id_of_string "H" in
+ mkLetIn (Name h,g,t,mkApp(mkRel 1,Array.map (lift 1) l'))
+ | _ -> mkApp (g,l')
+ with Not_found -> mkApp (f,l'))
+ | _ -> mkApp (irec f,l'))
+ | Cast (m,_) when isMeta m ->
+ (try List.assoc (destMeta m) s with Not_found -> u)
+ | _ -> map_constr irec u
+ in
+ if s = [] then c else irec c
+
+(* Pourquoi ne fait-on pas nf_betaiota si s=[] ? *)
+let instance s c =
+ if s = [] then c else local_strong whd_betaiota (plain_instance s c)
+
+
+(* pseudo-reduction rule:
+ * [hnf_prod_app env s (Prod(_,B)) N --> B[N]
+ * with an HNF on the first argument to produce a product.
+ * if this does not work, then we use the string S as part of our
+ * error message. *)
+
+let hnf_prod_app env sigma t n =
+ match kind_of_term (whd_betadeltaiota env sigma t) with
+ | Prod (_,_,b) -> subst1 n b
+ | _ -> anomaly "hnf_prod_app: Need a product"
+
+let hnf_prod_appvect env sigma t nl =
+ Array.fold_left (hnf_prod_app env sigma) t nl
+
+let hnf_prod_applist env sigma t nl =
+ List.fold_left (hnf_prod_app env sigma) t nl
+
+let hnf_lam_app env sigma t n =
+ match kind_of_term (whd_betadeltaiota env sigma t) with
+ | Lambda (_,_,b) -> subst1 n b
+ | _ -> anomaly "hnf_lam_app: Need an abstraction"
+
+let hnf_lam_appvect env sigma t nl =
+ Array.fold_left (hnf_lam_app env sigma) t nl
+
+let hnf_lam_applist env sigma t nl =
+ List.fold_left (hnf_lam_app env sigma) t nl
+
+let splay_prod env sigma =
+ let rec decrec env m c =
+ let t = whd_betadeltaiota env sigma c in
+ match kind_of_term t with
+ | Prod (n,a,c0) ->
+ decrec (push_rel (n,None,a) env)
+ ((n,a)::m) c0
+ | _ -> m,t
+ in
+ decrec env []
+
+let splay_prod_assum env sigma =
+ let rec prodec_rec env l c =
+ let t = whd_betadeltaiota_nolet env sigma c in
+ match kind_of_term c with
+ | Prod (x,t,c) ->
+ prodec_rec (push_rel (x,None,t) env)
+ (Sign.add_rel_decl (x, None, t) l) c
+ | LetIn (x,b,t,c) ->
+ prodec_rec (push_rel (x, Some b, t) env)
+ (Sign.add_rel_decl (x, Some b, t) l) c
+ | Cast (c,_) -> prodec_rec env l c
+ | _ -> l,t
+ in
+ prodec_rec env Sign.empty_rel_context
+
+let splay_arity env sigma c =
+ let l, c = splay_prod env sigma c in
+ match kind_of_term c with
+ | Sort s -> l,s
+ | _ -> error "not an arity"
+
+let sort_of_arity env c = snd (splay_arity env Evd.empty c)
+
+let decomp_n_prod env sigma n =
+ let rec decrec env m ln c = if m = 0 then (ln,c) else
+ match kind_of_term (whd_betadeltaiota env sigma c) with
+ | Prod (n,a,c0) ->
+ decrec (push_rel (n,None,a) env)
+ (m-1) (Sign.add_rel_decl (n,None,a) ln) c0
+ | _ -> error "decomp_n_prod: Not enough products"
+ in
+ decrec env n Sign.empty_rel_context
+
+(* One step of approximation *)
+
+let rec apprec env sigma s =
+ let (t, stack as s) = whd_betaiota_state s in
+ match kind_of_term t with
+ | Case (ci,p,d,lf) ->
+ let (cr,crargs) = whd_betadeltaiota_stack env sigma d in
+ let rslt = mkCase (ci, p, applist (cr,crargs), lf) in
+ if reducible_mind_case cr then
+ apprec env sigma (rslt, stack)
+ else
+ s
+ | Fix fix ->
+ (match reduce_fix (whd_betadeltaiota_state env sigma) fix stack with
+ | Reduced s -> apprec env sigma s
+ | NotReducible -> s)
+ | _ -> s
+
+let hnf env sigma c = apprec env sigma (c, empty_stack)
+
+(* A reduction function like whd_betaiota but which keeps casts
+ * and does not reduce redexes containing existential variables.
+ * Used in Correctness.
+ * Added by JCF, 29/1/98. *)
+
+let whd_programs_stack env sigma =
+ let rec whrec (x, stack as s) =
+ match kind_of_term x with
+ | App (f,cl) ->
+ let n = Array.length cl - 1 in
+ let c = cl.(n) in
+ if occur_existential c then
+ s
+ else
+ whrec (mkApp (f, Array.sub cl 0 n), append_stack [|c|] stack)
+ | LetIn (_,b,_,c) ->
+ if occur_existential b then
+ s
+ else
+ stacklam whrec [b] c stack
+ | Lambda (_,_,c) ->
+ (match decomp_stack stack with
+ | None -> s
+ | Some (a,m) -> stacklam whrec [a] c m)
+ | Case (ci,p,d,lf) ->
+ if occur_existential d then
+ s
+ else
+ let (c,cargs) = whrec (d, empty_stack) in
+ if reducible_mind_case c then
+ whrec (reduce_mind_case
+ {mP=p; mconstr=c; mcargs=list_of_stack cargs;
+ mci=ci; mlf=lf}, stack)
+ else
+ (mkCase (ci, p, app_stack(c,cargs), lf), stack)
+ | Fix fix ->
+ (match reduce_fix whrec fix stack with
+ | Reduced s' -> whrec s'
+ | NotReducible -> s)
+ | _ -> s
+ in
+ whrec
+
+let whd_programs env sigma x =
+ app_stack (whd_programs_stack env sigma (x, empty_stack))
+
+exception IsType
+
+let find_conclusion env sigma =
+ let rec decrec env c =
+ let t = whd_betadeltaiota env sigma c in
+ match kind_of_term t with
+ | Prod (x,t,c0) -> decrec (push_rel (x,None,t) env) c0
+ | Lambda (x,t,c0) -> decrec (push_rel (x,None,t) env) c0
+ | t -> t
+ in
+ decrec env
+
+let is_arity env sigma c =
+ match find_conclusion env sigma c with
+ | Sort _ -> true
+ | _ -> false
+
+let info_arity env sigma c =
+ match find_conclusion env sigma c with
+ | Sort (Prop Null) -> false
+ | Sort (Prop Pos) -> true
+ | _ -> raise IsType
+
+let is_info_arity env sigma c =
+ try (info_arity env sigma c) with IsType -> true
+
+let is_type_arity env sigma c =
+ match find_conclusion env sigma c with
+ | Sort (Type _) -> true
+ | _ -> false
+
+let is_info_type env sigma t =
+ let s = t.utj_type in
+ (s = Prop Pos) ||
+ (s <> Prop Null &&
+ try info_arity env sigma t.utj_val with IsType -> true)
diff --git a/pretyping/reductionops.mli b/pretyping/reductionops.mli
new file mode 100644
index 00000000..65cdd5cd
--- /dev/null
+++ b/pretyping/reductionops.mli
@@ -0,0 +1,190 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: reductionops.mli,v 1.8.2.2 2004/07/16 19:30:46 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Univ
+open Evd
+open Environ
+open Closure
+(*i*)
+
+(* Reduction Functions. *)
+
+exception Elimconst
+
+type state = constr * constr stack
+
+type contextual_reduction_function = env -> evar_map -> constr -> constr
+type reduction_function = contextual_reduction_function
+type local_reduction_function = constr -> constr
+
+type contextual_stack_reduction_function =
+ env -> evar_map -> constr -> constr * constr list
+type stack_reduction_function = contextual_stack_reduction_function
+type local_stack_reduction_function = constr -> constr * constr list
+
+type contextual_state_reduction_function =
+ env -> evar_map -> state -> state
+type state_reduction_function = contextual_state_reduction_function
+type local_state_reduction_function = state -> state
+
+(* Removes cast and put into applicative form *)
+val whd_stack : local_stack_reduction_function
+
+(* For compatibility: alias for whd\_stack *)
+val whd_castapp_stack : local_stack_reduction_function
+
+(*s Reduction Function Operators *)
+
+val strong : reduction_function -> reduction_function
+val local_strong : local_reduction_function -> local_reduction_function
+val strong_prodspine : local_reduction_function -> local_reduction_function
+(*i
+val stack_reduction_of_reduction :
+ 'a reduction_function -> 'a state_reduction_function
+i*)
+val stacklam : (state -> 'a) -> constr list -> constr -> constr stack -> 'a
+
+(*s Generic Optimized Reduction Function using Closures *)
+
+val clos_norm_flags : Closure.RedFlags.reds -> reduction_function
+(* Same as [(strong whd_beta[delta][iota])], but much faster on big terms *)
+val nf_beta : local_reduction_function
+val nf_betaiota : local_reduction_function
+val nf_betadeltaiota : reduction_function
+val nf_evar : evar_map -> constr -> constr
+
+(* Lazy strategy, weak head reduction *)
+val whd_evar : evar_map -> constr -> constr
+val whd_beta : local_reduction_function
+val whd_betaiota : local_reduction_function
+val whd_betaiotazeta : local_reduction_function
+val whd_betadeltaiota : contextual_reduction_function
+val whd_betadeltaiota_nolet : contextual_reduction_function
+val whd_betaetalet : local_reduction_function
+val whd_betalet : local_reduction_function
+
+val whd_beta_stack : local_stack_reduction_function
+val whd_betaiota_stack : local_stack_reduction_function
+val whd_betaiotazeta_stack : local_stack_reduction_function
+val whd_betadeltaiota_stack : contextual_stack_reduction_function
+val whd_betadeltaiota_nolet_stack : contextual_stack_reduction_function
+val whd_betaetalet_stack : local_stack_reduction_function
+val whd_betalet_stack : local_stack_reduction_function
+
+val whd_state : local_state_reduction_function
+val whd_beta_state : local_state_reduction_function
+val whd_betaiota_state : local_state_reduction_function
+val whd_betaiotazeta_state : local_state_reduction_function
+val whd_betadeltaiota_state : contextual_state_reduction_function
+val whd_betadeltaiota_nolet_state : contextual_state_reduction_function
+val whd_betaetalet_state : local_state_reduction_function
+val whd_betalet_state : local_state_reduction_function
+
+(*s Head normal forms *)
+
+val whd_delta_stack : stack_reduction_function
+val whd_delta_state : state_reduction_function
+val whd_delta : reduction_function
+val whd_betadelta_stack : stack_reduction_function
+val whd_betadelta_state : state_reduction_function
+val whd_betadelta : reduction_function
+val whd_betaevar_stack : stack_reduction_function
+val whd_betaevar_state : state_reduction_function
+val whd_betaevar : reduction_function
+val whd_betaiotaevar_stack : stack_reduction_function
+val whd_betaiotaevar_state : state_reduction_function
+val whd_betaiotaevar : reduction_function
+val whd_betadeltaeta_stack : stack_reduction_function
+val whd_betadeltaeta_state : state_reduction_function
+val whd_betadeltaeta : reduction_function
+val whd_betadeltaiotaeta_stack : stack_reduction_function
+val whd_betadeltaiotaeta_state : state_reduction_function
+val whd_betadeltaiotaeta : reduction_function
+
+val beta_applist : constr * constr list -> constr
+
+val hnf_prod_app : env -> evar_map -> constr -> constr -> constr
+val hnf_prod_appvect : env -> evar_map -> constr -> constr array -> constr
+val hnf_prod_applist : env -> evar_map -> constr -> constr list -> constr
+val hnf_lam_app : env -> evar_map -> constr -> constr -> constr
+val hnf_lam_appvect : env -> evar_map -> constr -> constr array -> constr
+val hnf_lam_applist : env -> evar_map -> constr -> constr list -> constr
+
+val splay_prod : env -> evar_map -> constr -> (name * constr) list * constr
+val splay_arity : env -> evar_map -> constr -> (name * constr) list * sorts
+val sort_of_arity : env -> constr -> sorts
+val decomp_n_prod :
+ env -> evar_map -> int -> constr -> Sign.rel_context * constr
+val splay_prod_assum :
+ env -> evar_map -> constr -> Sign.rel_context * constr
+
+type 'a miota_args = {
+ mP : constr; (* the result type *)
+ mconstr : constr; (* the constructor *)
+ mci : case_info; (* special info to re-build pattern *)
+ mcargs : 'a list; (* the constructor's arguments *)
+ mlf : 'a array } (* the branch code vector *)
+
+val reducible_mind_case : constr -> bool
+val reduce_mind_case : constr miota_args -> constr
+
+val find_conclusion : env -> evar_map -> constr -> (constr,constr) kind_of_term
+val is_arity : env -> evar_map -> constr -> bool
+val is_info_type : env -> evar_map -> unsafe_type_judgment -> bool
+val is_info_arity : env -> evar_map -> constr -> bool
+(*i Pour l'extraction
+val is_type_arity : env -> 'a evar_map -> constr -> bool
+val is_info_cast_type : env -> 'a evar_map -> constr -> bool
+val contents_of_cast_type : env -> 'a evar_map -> constr -> contents
+i*)
+
+val whd_programs : reduction_function
+
+(* [reduce_fix] contracts a fix redex if it is actually reducible *)
+
+type fix_reduction_result = NotReducible | Reduced of state
+
+val fix_recarg : fixpoint -> constr stack -> (int * constr) option
+val reduce_fix : local_state_reduction_function -> fixpoint
+ -> constr stack -> fix_reduction_result
+
+(*s Conversion Functions (uses closures, lazy strategy) *)
+
+type conversion_test = constraints -> constraints
+
+type conv_pb =
+ | CONV
+ | CUMUL
+
+val pb_is_equal : conv_pb -> bool
+val pb_equal : conv_pb -> conv_pb
+
+val sort_cmp : conv_pb -> sorts -> sorts -> conversion_test
+val base_sort_cmp : conv_pb -> sorts -> sorts -> bool
+
+val is_conv : env -> evar_map -> constr -> constr -> bool
+val is_conv_leq : env -> evar_map -> constr -> constr -> bool
+val is_fconv : conv_pb -> env -> evar_map -> constr -> constr -> bool
+
+(*s Special-Purpose Reduction Functions *)
+
+val whd_meta : (metavariable * constr) list -> constr -> constr
+val plain_instance : (metavariable * constr) list -> constr -> constr
+val instance : (metavariable * constr) list -> constr -> constr
+
+(*s Obsolete Reduction Functions *)
+
+(*i
+val hnf : env -> 'a evar_map -> constr -> constr * constr list
+i*)
+val apprec : state_reduction_function
diff --git a/pretyping/retyping.ml b/pretyping/retyping.ml
new file mode 100644
index 00000000..061382f7
--- /dev/null
+++ b/pretyping/retyping.ml
@@ -0,0 +1,131 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: retyping.ml,v 1.43.2.1 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Util
+open Term
+open Inductive
+open Names
+open Reductionops
+open Environ
+open Typeops
+open Declarations
+open Instantiate
+
+let outsort env sigma t =
+ match kind_of_term (whd_betadeltaiota env sigma t) with
+ | Sort s -> s
+ | _ -> anomaly "Retyping: found a type of type which is not a sort"
+
+let rec subst_type env sigma typ = function
+ | [] -> typ
+ | h::rest ->
+ match kind_of_term (whd_betadeltaiota env sigma typ) with
+ | Prod (na,c1,c2) -> subst_type env sigma (subst1 h c2) rest
+ | _ -> anomaly "Non-functional construction"
+
+(* Si ft est le type d'un terme f, lequel est appliqué à args, *)
+(* [sort_of_atomic_ty] calcule ft[args] qui doit être une sorte *)
+(* On suit une méthode paresseuse, en espèrant que ft est une arité *)
+(* et sinon on substitue *)
+
+let sort_of_atomic_type env sigma ft args =
+ let rec concl_of_arity env ar =
+ match kind_of_term (whd_betadeltaiota env sigma ar) with
+ | Prod (na, t, b) -> concl_of_arity (push_rel (na,None,t) env) b
+ | Sort s -> s
+ | _ -> outsort env sigma (subst_type env sigma ft (Array.to_list args))
+ in concl_of_arity env ft
+
+let typeur sigma metamap =
+ let rec type_of env cstr=
+ match kind_of_term cstr with
+ | Meta n ->
+ (try strip_outer_cast (List.assoc n metamap)
+ with Not_found -> anomaly "type_of: this is not a well-typed term")
+ | Rel n ->
+ let (_,_,ty) = lookup_rel n env in
+ lift n ty
+ | Var id ->
+ (try
+ let (_,_,ty) = lookup_named id env in
+ body_of_type ty
+ with Not_found ->
+ anomaly ("type_of: variable "^(string_of_id id)^" unbound"))
+ | Const c ->
+ let cb = lookup_constant c env in
+ body_of_type cb.const_type
+ | Evar ev -> existential_type sigma ev
+ | Ind ind -> body_of_type (type_of_inductive env ind)
+ | Construct cstr -> body_of_type (type_of_constructor env cstr)
+ | Case (_,p,c,lf) ->
+ let Inductiveops.IndType(_,realargs) =
+ try Inductiveops.find_rectype env sigma (type_of env c)
+ with Not_found -> anomaly "type_of: Bad recursive type" in
+ let t = whd_beta (applist (p, realargs)) in
+ (match kind_of_term (whd_betadeltaiota env sigma (type_of env t)) with
+ | Prod _ -> whd_beta (applist (t, [c]))
+ | _ -> t)
+ | Lambda (name,c1,c2) ->
+ mkProd (name, c1, type_of (push_rel (name,None,c1) env) c2)
+ | LetIn (name,b,c1,c2) ->
+ subst1 b (type_of (push_rel (name,Some b,c1) env) c2)
+ | Fix ((_,i),(_,tys,_)) -> tys.(i)
+ | CoFix (i,(_,tys,_)) -> tys.(i)
+ | App(f,args)->
+ strip_outer_cast
+ (subst_type env sigma (type_of env f) (Array.to_list args))
+ | Cast (c,t) -> t
+ | Sort _ | Prod _ -> mkSort (sort_of env cstr)
+
+ and sort_of env t =
+ match kind_of_term t with
+ | Cast (c,s) when isSort s -> destSort s
+ | Sort (Prop c) -> type_0
+ | Sort (Type u) -> Type (Univ.super u)
+ | Prod (name,t,c2) ->
+ (match (sort_of env t, sort_of (push_rel (name,None,t) env) c2) with
+ | _, (Prop Null as s) -> s
+ | Prop _, (Prop Pos as s) -> s
+ | Type _, (Prop Pos as s) when
+ Environ.engagement env = Some ImpredicativeSet -> s
+ | Type _ as s, Prop Pos -> s
+ | _, (Type u2 as s) -> s (*Type Univ.dummy_univ*))
+ | App(f,args) -> sort_of_atomic_type env sigma (type_of env f) args
+ | Lambda _ | Fix _ | Construct _ ->
+ anomaly "sort_of: Not a type (1)"
+ | _ -> outsort env sigma (type_of env t)
+
+ and sort_family_of env t =
+ match kind_of_term t with
+ | Cast (c,s) when isSort s -> family_of_sort (destSort s)
+ | Sort (Prop c) -> InType
+ | Sort (Type u) -> InType
+ | Prod (name,t,c2) -> sort_family_of (push_rel (name,None,t) env) c2
+ | App(f,args) ->
+ family_of_sort (sort_of_atomic_type env sigma (type_of env f) args)
+ | Lambda _ | Fix _ | Construct _ ->
+ anomaly "sort_of: Not a type (1)"
+ | _ -> family_of_sort (outsort env sigma (type_of env t))
+
+ in type_of, sort_of, sort_family_of
+
+let get_type_of env sigma c = let f,_,_ = typeur sigma [] in f env c
+let get_sort_of env sigma t = let _,f,_ = typeur sigma [] in f env t
+let get_sort_family_of env sigma c = let _,_,f = typeur sigma [] in f env c
+
+let get_type_of_with_meta env sigma metamap =
+ let f,_,_ = typeur sigma metamap in f env
+
+(* Makes an assumption from a constr *)
+let get_assumption_of env evc c = c
+
+(* Makes an unsafe judgment from a constr *)
+let get_judgment_of env evc c = { uj_val = c; uj_type = get_type_of env evc c }
+
diff --git a/pretyping/retyping.mli b/pretyping/retyping.mli
new file mode 100644
index 00000000..f29ac8d8
--- /dev/null
+++ b/pretyping/retyping.mli
@@ -0,0 +1,36 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: retyping.mli,v 1.16.2.1 2004/07/16 19:30:46 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Evd
+open Environ
+open Pattern
+open Termops
+(*i*)
+
+(* This family of functions assumes its constr argument is known to be
+ well-typable. It does not type-check, just recompute the type
+ without any costly verifications. On non well-typable terms, it
+ either produces a wrong result or raise an anomaly. Use with care.
+ It doesn't handle predicative universes too. *)
+
+val get_type_of : env -> evar_map -> constr -> constr
+val get_sort_of : env -> evar_map -> types -> sorts
+val get_sort_family_of : env -> evar_map -> types -> sorts_family
+
+val get_type_of_with_meta : env -> evar_map -> metamap -> constr -> constr
+
+(* Makes an assumption from a constr *)
+val get_assumption_of : env -> evar_map -> constr -> types
+
+(* Makes an unsafe judgment from a constr *)
+val get_judgment_of : env -> evar_map -> constr -> unsafe_judgment
diff --git a/pretyping/tacred.ml b/pretyping/tacred.ml
new file mode 100644
index 00000000..7e79a4fe
--- /dev/null
+++ b/pretyping/tacred.ml
@@ -0,0 +1,953 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: tacred.ml,v 1.75.2.2 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Nameops
+open Term
+open Libnames
+open Termops
+open Declarations
+open Inductive
+open Environ
+open Reductionops
+open Closure
+open Instantiate
+open Cbv
+open Rawterm
+
+exception Elimconst
+exception Redelimination
+
+let set_opaque_const = Conv_oracle.set_opaque_const
+let set_transparent_const sp =
+ let cb = Global.lookup_constant sp in
+ if cb.const_body <> None & cb.const_opaque then
+ errorlabstrm "set_transparent_const"
+ (str "Cannot make" ++ spc () ++
+ Nametab.pr_global_env Idset.empty (ConstRef sp) ++
+ spc () ++ str "transparent because it was declared opaque.");
+ Conv_oracle.set_transparent_const sp
+
+let set_opaque_var = Conv_oracle.set_opaque_var
+let set_transparent_var = Conv_oracle.set_transparent_var
+
+let _ =
+ Summary.declare_summary "Transparent constants and variables"
+ { Summary.freeze_function = Conv_oracle.freeze;
+ Summary.unfreeze_function = Conv_oracle.unfreeze;
+ Summary.init_function = Conv_oracle.init;
+ Summary.survive_module = false;
+ Summary.survive_section = false }
+
+let is_evaluable env ref =
+ match ref with
+ EvalConstRef kn ->
+ let (ids,kns) = Conv_oracle.freeze() in
+ KNpred.mem kn kns &
+ let cb = Environ.lookup_constant kn env in
+ cb.const_body <> None & not cb.const_opaque
+ | EvalVarRef id ->
+ let (ids,sps) = Conv_oracle.freeze() in
+ Idpred.mem id ids &
+ let (_,value,_) = Environ.lookup_named id env in
+ value <> None
+
+type evaluable_reference =
+ | EvalConst of constant
+ | EvalVar of identifier
+ | EvalRel of int
+ | EvalEvar of existential
+
+let mkEvalRef = function
+ | EvalConst cst -> mkConst cst
+ | EvalVar id -> mkVar id
+ | EvalRel n -> mkRel n
+ | EvalEvar ev -> mkEvar ev
+
+let isEvalRef env c = match kind_of_term c with
+ | Const sp -> is_evaluable env (EvalConstRef sp)
+ | Var id -> is_evaluable env (EvalVarRef id)
+ | Rel _ | Evar _ -> true
+ | _ -> false
+
+let destEvalRef c = match kind_of_term c with
+ | Const cst -> EvalConst cst
+ | Var id -> EvalVar id
+ | Rel n -> EvalRel n
+ | Evar ev -> EvalEvar ev
+ | _ -> anomaly "Not an evaluable reference"
+
+let reference_opt_value sigma env = function
+ | EvalConst cst -> constant_opt_value env cst
+ | EvalVar id ->
+ let (_,v,_) = lookup_named id env in
+ v
+ | EvalRel n ->
+ let (_,v,_) = lookup_rel n env in
+ option_app (lift n) v
+ | EvalEvar ev -> existential_opt_value sigma ev
+
+exception NotEvaluable
+let reference_value sigma env c =
+ match reference_opt_value sigma env c with
+ | None -> raise NotEvaluable
+ | Some d -> d
+
+(************************************************************************)
+(* Reduction of constant hiding fixpoints (e.g. for Simpl). The trick *)
+(* is to reuse the name of the function after reduction of the fixpoint *)
+
+type constant_evaluation =
+ | EliminationFix of int * (int * (int * constr) list * int)
+ | EliminationMutualFix of
+ int * evaluable_reference *
+ (evaluable_reference option array * (int * (int * constr) list * int))
+ | EliminationCases of int
+ | NotAnElimination
+
+(* We use a cache registered as a global table *)
+
+
+module CstOrdered =
+ struct
+ type t = constant
+ let compare = Pervasives.compare
+ end
+module Cstmap = Map.Make(CstOrdered)
+
+let eval_table = ref Cstmap.empty
+
+type frozen = (int * constant_evaluation) Cstmap.t
+
+let init () =
+ eval_table := Cstmap.empty
+
+let freeze () =
+ !eval_table
+
+let unfreeze ct =
+ eval_table := ct
+
+let _ =
+ Summary.declare_summary "evaluation"
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init;
+ Summary.survive_module = false;
+ Summary.survive_section = false }
+
+
+(* Check that c is an "elimination constant"
+ [xn:An]..[x1:A1](<P>MutCase (Rel i) of f1..fk end g1 ..gp)
+ or [xn:An]..[x1:A1](Fix(f|t) (Rel i1) ..(Rel ip))
+ with i1..ip distinct variables not occuring in t
+ keep relevenant information ([i1,Ai1;..;ip,Aip],n,b)
+ with b = true in case of a fixpoint in order to compute
+ an equivalent of Fix(f|t)[xi<-ai] as
+ [yip:Bip]..[yi1:Bi1](F bn..b1)
+ == [yip:Bip]..[yi1:Bi1](Fix(f|t)[xi<-ai] (Rel 1)..(Rel p))
+ with bj=aj if j<>ik and bj=(Rel c) and Bic=Aic[xn..xic-1 <- an..aic-1] *)
+
+let check_fix_reversibility labs args ((lv,i),(_,tys,bds)) =
+ let n = List.length labs in
+ let nargs = List.length args in
+ if nargs > n then raise Elimconst;
+ let nbfix = Array.length bds in
+ let li =
+ List.map
+ (function d -> match kind_of_term d with
+ | Rel k ->
+ if
+ array_for_all (noccurn k) tys
+ && array_for_all (noccurn (k+nbfix)) bds
+ then
+ (k, List.nth labs (k-1))
+ else
+ raise Elimconst
+ | _ ->
+ raise Elimconst) args
+ in
+ if list_distinct (List.map fst li) then
+ let k = lv.(i) in
+ if k < nargs then
+(* Such an optimisation would need eta-expansion
+ let p = destRel (List.nth args k) in
+ EliminationFix (n-p+1,(nbfix,li,n))
+*)
+ EliminationFix (n,(nbfix,li,n))
+ else
+ EliminationFix (n-nargs+lv.(i)+1,(nbfix,li,n))
+ else
+ raise Elimconst
+
+(* Heuristic to look if global names are associated to other
+ components of a mutual fixpoint *)
+
+let invert_name labs l na0 env sigma ref = function
+ | Name id ->
+ if na0 <> Name id then
+ let refi = match ref with
+ | EvalRel _ | EvalEvar _ -> None
+ | EvalVar id' -> Some (EvalVar id)
+ | EvalConst kn ->
+ let (mp,dp,_) = repr_kn kn in
+ Some (EvalConst (make_kn mp dp (label_of_id id))) in
+ match refi with
+ | None -> None
+ | Some ref ->
+ match reference_opt_value sigma env ref with
+ | None -> None
+ | Some c ->
+ let labs',ccl = decompose_lam c in
+ let _, l' = whd_betalet_stack ccl in
+ let labs' = List.map snd labs' in
+ if labs' = labs & l = l' then Some ref else None
+ else Some ref
+ | Anonymous -> None (* Actually, should not occur *)
+
+(* [compute_consteval_direct] expand all constant in a whole, but
+ [compute_consteval_mutual_fix] only one by one, until finding the
+ last one before the Fix if the latter is mutually defined *)
+
+let compute_consteval_direct sigma env ref =
+ let rec srec env n labs c =
+ let c',l = whd_betadelta_stack env sigma c in
+ match kind_of_term c' with
+ | Lambda (id,t,g) when l=[] ->
+ srec (push_rel (id,None,t) env) (n+1) (t::labs) g
+ | Fix fix ->
+ (try check_fix_reversibility labs l fix
+ with Elimconst -> NotAnElimination)
+ | Case (_,_,d,_) when isRel d -> EliminationCases n
+ | _ -> NotAnElimination
+ in
+ match reference_opt_value sigma env ref with
+ | None -> NotAnElimination
+ | Some c -> srec env 0 [] c
+
+let compute_consteval_mutual_fix sigma env ref =
+ let rec srec env minarg labs ref c =
+ let c',l = whd_betalet_stack c in
+ let nargs = List.length l in
+ match kind_of_term c' with
+ | Lambda (na,t,g) when l=[] ->
+ srec (push_rel (na,None,t) env) (minarg+1) (t::labs) ref g
+ | Fix ((lv,i),(names,_,_) as fix) ->
+ (* Last known constant wrapping Fix is ref = [labs](Fix l) *)
+ (match compute_consteval_direct sigma env ref with
+ | NotAnElimination -> (*Above const was eliminable but this not!*)
+ NotAnElimination
+ | EliminationFix (minarg',infos) ->
+ let refs =
+ Array.map
+ (invert_name labs l names.(i) env sigma ref) names in
+ let new_minarg = max (minarg'+minarg-nargs) minarg' in
+ EliminationMutualFix (new_minarg,ref,(refs,infos))
+ | _ -> assert false)
+ | _ when isEvalRef env c' ->
+ (* Forget all \'s and args and do as if we had started with c' *)
+ let ref = destEvalRef c' in
+ (match reference_opt_value sigma env ref with
+ | None -> anomaly "Should have been trapped by compute_direct"
+ | Some c -> srec env (minarg-nargs) [] ref c)
+ | _ -> (* Should not occur *) NotAnElimination
+ in
+ match reference_opt_value sigma env ref with
+ | None -> (* Should not occur *) NotAnElimination
+ | Some c -> srec env 0 [] ref c
+
+let compute_consteval sigma env ref =
+ match compute_consteval_direct sigma env ref with
+ | EliminationFix (_,(nbfix,_,_)) when nbfix <> 1 ->
+ compute_consteval_mutual_fix sigma env ref
+ | elim -> elim
+
+let reference_eval sigma env = function
+ | EvalConst cst as ref ->
+ (try
+ Cstmap.find cst !eval_table
+ with Not_found -> begin
+ let v = compute_consteval sigma env ref in
+ eval_table := Cstmap.add cst v !eval_table;
+ v
+ end)
+ | ref -> compute_consteval sigma env ref
+
+let rev_firstn_liftn fn ln =
+ let rec rfprec p res l =
+ if p = 0 then
+ res
+ else
+ match l with
+ | [] -> invalid_arg "Reduction.rev_firstn_liftn"
+ | a::rest -> rfprec (p-1) ((lift ln a)::res) rest
+ in
+ rfprec fn []
+
+(* EliminationFix ([(yi1,Ti1);...;(yip,Tip)],n) means f is some
+ [y1:T1,...,yn:Tn](Fix(..) yi1 ... yip);
+ f is applied to largs and we need for recursive calls to build
+ [x1:Ti1',...,xp:Tip'](f a1..a(n-p) yi1 ... yip)
+ where a1...an are the n first arguments of largs and Tik' is Tik[yil=al]
+ To check ... *)
+
+let make_elim_fun (names,(nbfix,lv,n)) largs =
+ let labs = list_firstn n (list_of_stack largs) in
+ let p = List.length lv in
+ let ylv = List.map fst lv in
+ let la' = list_map_i
+ (fun q aq ->
+ try (mkRel (p+1-(list_index (n-q) ylv)))
+ with Not_found -> aq) 0
+ (List.map (lift p) labs)
+ in
+ fun i ->
+ match names.(i) with
+ | None -> None
+ | Some ref -> Some (
+(* let fi =
+ if nbfix = 1 then
+ mkEvalRef ref
+ else
+ match ref with
+ | EvalConst (sp,args) ->
+ mkConst (make_path (dirpath sp) id (kind_of_path sp),args)
+ | _ -> anomaly "elimination of local fixpoints not implemented"
+ in
+*)
+ list_fold_left_i
+ (fun i c (k,a) ->
+ mkLambda (Name(id_of_string"x"),
+ substl (rev_firstn_liftn (n-k) (-i) la') a,
+ c))
+ 0 (applistc (mkEvalRef ref) la') lv)
+
+(* [f] is convertible to [Fix(recindices,bodynum),bodyvect)] make
+ the reduction using this extra information *)
+
+let contract_fix_use_function f
+ ((recindices,bodynum),(types,names,bodies as typedbodies)) =
+ let nbodies = Array.length recindices in
+ let make_Fi j = match f j with
+ | None -> mkFix((recindices,j),typedbodies)
+ | Some c -> c in
+(* match List.nth names j with Name id -> f id | _ -> assert false in*)
+ let lbodies = list_tabulate make_Fi nbodies in
+ substl (List.rev lbodies) bodies.(bodynum)
+
+let reduce_fix_use_function f whfun fix stack =
+ match fix_recarg fix stack with
+ | None -> NotReducible
+ | Some (recargnum,recarg) ->
+ let (recarg'hd,_ as recarg') =
+ if isRel recarg then
+ (* The recarg cannot be a local def, no worry about the right env *)
+ (recarg, empty_stack)
+ else
+ whfun (recarg, empty_stack) in
+ let stack' = stack_assign stack recargnum (app_stack recarg') in
+ (match kind_of_term recarg'hd with
+ | Construct _ ->
+ Reduced (contract_fix_use_function f fix,stack')
+ | _ -> NotReducible)
+
+let contract_cofix_use_function f (bodynum,(_,names,bodies as typedbodies)) =
+ let nbodies = Array.length bodies in
+ let make_Fi j = match f j with
+ | None -> mkCoFix(j,typedbodies)
+ | Some c -> c in
+(* match List.nth names j with Name id -> f id | _ -> assert false in*)
+ let subbodies = list_tabulate make_Fi nbodies in
+ substl subbodies bodies.(bodynum)
+
+let reduce_mind_case_use_function func env mia =
+ match kind_of_term mia.mconstr with
+ | Construct(ind_sp,i as cstr_sp) ->
+ let real_cargs = list_skipn mia.mci.ci_npar mia.mcargs in
+ applist (mia.mlf.(i-1), real_cargs)
+ | CoFix (_,(names,_,_) as cofix) ->
+ let build_fix_name i =
+ match names.(i) with
+ | Name id ->
+ if isConst func then
+ let (mp,dp,_) = repr_kn (destConst func) in
+ let kn = make_kn mp dp (label_of_id id) in
+ (match constant_opt_value env kn with
+ | None -> None
+ | Some _ -> Some (mkConst kn))
+ else None
+ | Anonymous -> None in
+ let cofix_def = contract_cofix_use_function build_fix_name cofix in
+ mkCase (mia.mci, mia.mP, applist(cofix_def,mia.mcargs), mia.mlf)
+ | _ -> assert false
+
+let special_red_case sigma env whfun (ci, p, c, lf) =
+ let rec redrec s =
+ let (constr, cargs) = whfun s in
+ if isEvalRef env constr then
+ let ref = destEvalRef constr in
+ match reference_opt_value sigma env ref with
+ | None -> raise Redelimination
+ | Some gvalue ->
+ if reducible_mind_case gvalue then
+ reduce_mind_case_use_function constr env
+ {mP=p; mconstr=gvalue; mcargs=list_of_stack cargs;
+ mci=ci; mlf=lf}
+ else
+ redrec (gvalue, cargs)
+ else
+ if reducible_mind_case constr then
+ reduce_mind_case
+ {mP=p; mconstr=constr; mcargs=list_of_stack cargs;
+ mci=ci; mlf=lf}
+ else
+ raise Redelimination
+ in
+ redrec (c, empty_stack)
+
+
+let rec red_elim_const env sigma ref largs =
+ match reference_eval sigma env ref with
+ | EliminationCases n when stack_args_size largs >= n ->
+ let c = reference_value sigma env ref in
+ let c', lrest = whd_betadelta_state env sigma (c,largs) in
+ (special_red_case sigma env (construct_const env sigma) (destCase c'),
+ lrest)
+ | EliminationFix (min,infos) when stack_args_size largs >=min ->
+ let c = reference_value sigma env ref in
+ let d, lrest = whd_betadelta_state env sigma (c,largs) in
+ let f = make_elim_fun ([|Some ref|],infos) largs in
+ let co = construct_const env sigma in
+ (match reduce_fix_use_function f co (destFix d) lrest with
+ | NotReducible -> raise Redelimination
+ | Reduced (c,rest) -> (nf_beta c, rest))
+ | EliminationMutualFix (min,refgoal,refinfos)
+ when stack_args_size largs >= min ->
+ let rec descend ref args =
+ let c = reference_value sigma env ref in
+ if ref = refgoal then
+ (c,args)
+ else
+ let c', lrest = whd_betalet_state (c,args) in
+ descend (destEvalRef c') lrest in
+ let (_, midargs as s) = descend ref largs in
+ let d, lrest = whd_betadelta_state env sigma s in
+ let f = make_elim_fun refinfos midargs in
+ let co = construct_const env sigma in
+ (match reduce_fix_use_function f co (destFix d) lrest with
+ | NotReducible -> raise Redelimination
+ | Reduced (c,rest) -> (nf_beta c, rest))
+ | _ -> raise Redelimination
+
+and construct_const env sigma =
+ let rec hnfstack (x, stack as s) =
+ match kind_of_term x with
+ | Cast (c,_) -> hnfstack (c, stack)
+ | App (f,cl) -> hnfstack (f, append_stack cl stack)
+ | Lambda (id,t,c) ->
+ (match decomp_stack stack with
+ | None -> assert false
+ | Some (c',rest) ->
+ stacklam hnfstack [c'] c rest)
+ | LetIn (n,b,t,c) -> stacklam hnfstack [b] c stack
+ | Case (ci,p,c,lf) ->
+ hnfstack
+ (special_red_case sigma env
+ (construct_const env sigma) (ci,p,c,lf), stack)
+ | Construct _ -> s
+ | CoFix _ -> s
+ | Fix fix ->
+ (match reduce_fix hnfstack fix stack with
+ | Reduced s' -> hnfstack s'
+ | NotReducible -> raise Redelimination)
+ | _ when isEvalRef env x ->
+ let ref = destEvalRef x in
+ (try
+ hnfstack (red_elim_const env sigma ref stack)
+ with Redelimination ->
+ (match reference_opt_value sigma env ref with
+ | Some cval ->
+ (match kind_of_term cval with
+ | CoFix _ -> s
+ | _ -> hnfstack (cval, stack))
+ | None ->
+ raise Redelimination))
+ | _ -> raise Redelimination
+ in
+ hnfstack
+
+(************************************************************************)
+(* Special Purpose Reduction Strategies *)
+
+(* Red reduction tactic: reduction to a product *)
+
+let internal_red_product env sigma c =
+ let simpfun = clos_norm_flags betaiotazeta env sigma in
+ let rec redrec env x =
+ match kind_of_term x with
+ | App (f,l) ->
+ (match kind_of_term f with
+ | Fix fix ->
+ let stack = append_stack l empty_stack in
+ (match fix_recarg fix stack with
+ | None -> raise Redelimination
+ | Some (recargnum,recarg) ->
+ let recarg' = redrec env recarg in
+ let stack' = stack_assign stack recargnum recarg' in
+ simpfun (app_stack (f,stack')))
+ | _ -> simpfun (appvect (redrec env f, l)))
+ | Cast (c,_) -> redrec env c
+ | Prod (x,a,b) -> mkProd (x, a, redrec (push_rel (x,None,a) env) b)
+ | LetIn (x,a,b,t) -> redrec env (subst1 a t)
+ | Case (ci,p,d,lf) -> simpfun (mkCase (ci,p,redrec env d,lf))
+ | _ when isEvalRef env x ->
+ (* TO DO: re-fold fixpoints after expansion *)
+ (* to get true one-step reductions *)
+ let ref = destEvalRef x in
+ (match reference_opt_value sigma env ref with
+ | None -> raise Redelimination
+ | Some c -> c)
+ | _ -> raise Redelimination
+ in redrec env c
+
+let red_product env sigma c =
+ try internal_red_product env sigma c
+ with Redelimination -> error "Not reducible"
+
+(* Hnf reduction tactic: *)
+
+let hnf_constr env sigma c =
+ let rec redrec (x, largs as s) =
+ match kind_of_term x with
+ | Lambda (n,t,c) ->
+ (match decomp_stack largs with
+ | None -> app_stack s
+ | Some (a,rest) ->
+ stacklam redrec [a] c rest)
+ | LetIn (n,b,t,c) -> stacklam redrec [b] c largs
+ | App (f,cl) -> redrec (f, append_stack cl largs)
+ | Cast (c,_) -> redrec (c, largs)
+ | Case (ci,p,c,lf) ->
+ (try
+ redrec
+ (special_red_case sigma env (whd_betadeltaiota_state env sigma)
+ (ci, p, c, lf), largs)
+ with Redelimination ->
+ app_stack s)
+ | Fix fix ->
+ (match reduce_fix (whd_betadeltaiota_state env sigma) fix largs with
+ | Reduced s' -> redrec s'
+ | NotReducible -> app_stack s)
+ | _ when isEvalRef env x ->
+ let ref = destEvalRef x in
+ (try
+ let (c',lrest) = red_elim_const env sigma ref largs in
+ redrec (c', lrest)
+ with Redelimination ->
+ match reference_opt_value sigma env ref with
+ | Some c ->
+ (match kind_of_term (snd (decompose_lam c)) with
+ | CoFix _ | Fix _ -> app_stack (x,largs)
+ | _ -> redrec (c, largs))
+ | None -> app_stack s)
+ | _ -> app_stack s
+ in
+ redrec (c, empty_stack)
+
+(* Simpl reduction tactic: same as simplify, but also reduces
+ elimination constants *)
+
+let whd_nf env sigma c =
+ let rec nf_app (c, stack as s) =
+ match kind_of_term c with
+ | Lambda (name,c1,c2) ->
+ (match decomp_stack stack with
+ | None -> (c,empty_stack)
+ | Some (a1,rest) ->
+ stacklam nf_app [a1] c2 rest)
+ | LetIn (n,b,t,c) -> stacklam nf_app [b] c stack
+ | App (f,cl) -> nf_app (f, append_stack cl stack)
+ | Cast (c,_) -> nf_app (c, stack)
+ | Case (ci,p,d,lf) ->
+ (try
+ nf_app (special_red_case sigma env nf_app (ci,p,d,lf), stack)
+ with Redelimination ->
+ s)
+ | Fix fix ->
+ (match reduce_fix nf_app fix stack with
+ | Reduced s' -> nf_app s'
+ | NotReducible -> s)
+ | _ when isEvalRef env c ->
+ (try
+ nf_app (red_elim_const env sigma (destEvalRef c) stack)
+ with Redelimination ->
+ s)
+ | _ -> s
+ in
+ app_stack (nf_app (c, empty_stack))
+
+let nf env sigma c = strong whd_nf env sigma c
+
+let is_reference c =
+ try let r = reference_of_constr c in true with _ -> false
+
+let is_head c t =
+ match kind_of_term t with
+ | App (f,_) -> f = c
+ | _ -> false
+
+let contextually byhead (locs,c) f env sigma t =
+ let maxocc = List.fold_right max locs 0 in
+ let pos = ref 1 in
+ let check = ref true in
+ let except = List.exists (fun n -> n<0) locs in
+ if except & (List.exists (fun n -> n>=0) locs)
+ then error "mixing of positive and negative occurences"
+ else
+ let rec traverse (env,c as envc) t =
+ if locs <> [] & (not except) & (!pos > maxocc) then t
+ else
+ if (not byhead & eq_constr c t) or (byhead & is_head c t) then
+ let ok =
+ if except then not (List.mem (- !pos) locs)
+ else (locs = [] or List.mem !pos locs) in
+ incr pos;
+ if ok then
+ f env sigma t
+ else if byhead then
+ (* find other occurrences of c in t; TODO: ensure left-to-right *)
+ let (f,l) = destApplication t in
+ mkApp (f, array_map_left (traverse envc) l)
+ else
+ t
+ else
+ map_constr_with_binders_left_to_right
+ (fun d (env,c) -> (push_rel d env,lift 1 c))
+ traverse envc t
+ in
+ let t' = traverse (env,c) t in
+ if locs <> [] & List.exists (fun o -> o >= !pos or o <= - !pos) locs then
+ errorlabstrm "contextually" (str "Too few occurences");
+ t'
+
+(* linear bindings (following pretty-printer) of the value of name in c.
+ * n is the number of the next occurence of name.
+ * ol is the occurence list to find. *)
+let rec substlin env name n ol c =
+ match kind_of_term c with
+ | Const kn when EvalConstRef kn = name ->
+ if List.hd ol = n then
+ try
+ (n+1, List.tl ol, constant_value env kn)
+ with
+ NotEvaluableConst _ ->
+ errorlabstrm "substlin"
+ (pr_kn kn ++ str " is not a defined constant")
+ else
+ ((n+1), ol, c)
+
+ | Var id when EvalVarRef id = name ->
+ if List.hd ol = n then
+ match lookup_named id env with
+ | (_,Some c,_) -> (n+1, List.tl ol, c)
+ | _ ->
+ errorlabstrm "substlin"
+ (pr_id id ++ str " is not a defined constant")
+ else
+ ((n+1), ol, c)
+
+ (* INEFFICIENT: OPTIMIZE *)
+ | App (c1,cl) ->
+ Array.fold_left
+ (fun (n1,ol1,c1') c2 ->
+ (match ol1 with
+ | [] -> (n1,[],applist(c1',[c2]))
+ | _ ->
+ let (n2,ol2,c2') = substlin env name n1 ol1 c2 in
+ (n2,ol2,applist(c1',[c2']))))
+ (substlin env name n ol c1) cl
+
+ | Lambda (na,c1,c2) ->
+ let (n1,ol1,c1') = substlin env name n ol c1 in
+ (match ol1 with
+ | [] -> (n1,[],mkLambda (na,c1',c2))
+ | _ ->
+ let (n2,ol2,c2') = substlin env name n1 ol1 c2 in
+ (n2,ol2,mkLambda (na,c1',c2')))
+
+ | LetIn (na,c1,t,c2) ->
+ let (n1,ol1,c1') = substlin env name n ol c1 in
+ (match ol1 with
+ | [] -> (n1,[],mkLetIn (na,c1',t,c2))
+ | _ ->
+ let (n2,ol2,c2') = substlin env name n1 ol1 c2 in
+ (n2,ol2,mkLetIn (na,c1',t,c2')))
+
+ | Prod (na,c1,c2) ->
+ let (n1,ol1,c1') = substlin env name n ol c1 in
+ (match ol1 with
+ | [] -> (n1,[],mkProd (na,c1',c2))
+ | _ ->
+ let (n2,ol2,c2') = substlin env name n1 ol1 c2 in
+ (n2,ol2,mkProd (na,c1',c2')))
+
+ | Case (ci,p,d,llf) ->
+ let rec substlist nn oll = function
+ | [] -> (nn,oll,[])
+ | f::lfe ->
+ let (nn1,oll1,f') = substlin env name nn oll f in
+ (match oll1 with
+ | [] -> (nn1,[],f'::lfe)
+ | _ ->
+ let (nn2,oll2,lfe') = substlist nn1 oll1 lfe in
+ (nn2,oll2,f'::lfe'))
+ in
+ let (n1,ol1,p') = substlin env name n ol p in (* ATTENTION ERREUR *)
+ (match ol1 with (* si P pas affiche *)
+ | [] -> (n1,[],mkCase (ci, p', d, llf))
+ | _ ->
+ let (n2,ol2,d') = substlin env name n1 ol1 d in
+ (match ol2 with
+ | [] -> (n2,[],mkCase (ci, p', d', llf))
+ | _ ->
+ let (n3,ol3,lf') = substlist n2 ol2 (Array.to_list llf)
+ in (n3,ol3,mkCase (ci, p', d', Array.of_list lf'))))
+
+ | Cast (c1,c2) ->
+ let (n1,ol1,c1') = substlin env name n ol c1 in
+ (match ol1 with
+ | [] -> (n1,[],mkCast (c1',c2))
+ | _ ->
+ let (n2,ol2,c2') = substlin env name n1 ol1 c2 in
+ (n2,ol2,mkCast (c1',c2')))
+
+ | Fix _ ->
+ (warning "do not consider occurrences inside fixpoints"; (n,ol,c))
+
+ | CoFix _ ->
+ (warning "do not consider occurrences inside cofixpoints"; (n,ol,c))
+
+ | (Rel _|Meta _|Var _|Sort _
+ |Evar _|Const _|Ind _|Construct _) -> (n,ol,c)
+
+let string_of_evaluable_ref env = function
+ | EvalVarRef id -> string_of_id id
+ | EvalConstRef kn ->
+ string_of_qualid
+ (Nametab.shortest_qualid_of_global (vars_of_env env) (ConstRef kn))
+
+let unfold env sigma name =
+ if is_evaluable env name then
+ clos_norm_flags (unfold_red name) env sigma
+ else
+ error (string_of_evaluable_ref env name^" is opaque")
+
+(* [unfoldoccs : (readable_constraints -> (int list * section_path) -> constr -> constr)]
+ * Unfolds the constant name in a term c following a list of occurrences occl.
+ * at the occurrences of occ_list. If occ_list is empty, unfold all occurences.
+ * Performs a betaiota reduction after unfolding. *)
+let unfoldoccs env sigma (occl,name) c =
+ match occl with
+ | [] -> unfold env sigma name c
+ | l ->
+ match substlin env name 1 (Sort.list (<) l) c with
+ | (_,[],uc) -> nf_betaiota uc
+ | (1,_,_) ->
+ error ((string_of_evaluable_ref env name)^" does not occur")
+ | _ -> error ("bad occurrence numbers of "
+ ^(string_of_evaluable_ref env name))
+
+(* Unfold reduction tactic: *)
+let unfoldn loccname env sigma c =
+ List.fold_left (fun c occname -> unfoldoccs env sigma occname c) c loccname
+
+(* Re-folding constants tactics: refold com in term c *)
+let fold_one_com com env sigma c =
+ let rcom =
+ try red_product env sigma com
+ with Redelimination -> error "Not reducible" in
+ subst1 com (subst_term rcom c)
+
+let fold_commands cl env sigma c =
+ List.fold_right (fun com -> fold_one_com com env sigma) (List.rev cl) c
+
+
+(* call by value reduction functions *)
+let cbv_norm_flags flags env sigma t =
+ cbv_norm (create_cbv_infos flags env) (nf_evar sigma t)
+
+let cbv_beta = cbv_norm_flags beta empty_env Evd.empty
+let cbv_betaiota = cbv_norm_flags betaiota empty_env Evd.empty
+let cbv_betadeltaiota env sigma = cbv_norm_flags betadeltaiota env sigma
+
+let compute = cbv_betadeltaiota
+
+(* Pattern *)
+
+(* gives [na:ta]c' such that c converts to ([na:ta]c' a), abstracting only
+ * the specified occurrences. *)
+
+let abstract_scheme env sigma (locc,a) t =
+ let ta = Retyping.get_type_of env sigma a in
+ let na = named_hd env ta Anonymous in
+ if occur_meta ta then error "cannot find a type for the generalisation";
+ if occur_meta a then
+ mkLambda (na,ta,t)
+ else
+ mkLambda (na, ta,subst_term_occ locc a t)
+
+
+let pattern_occs loccs_trm env sigma c =
+ let abstr_trm = List.fold_right (abstract_scheme env sigma) loccs_trm c in
+ applist(abstr_trm, List.map snd loccs_trm)
+
+(* Generic reduction: reduction functions used in reduction tactics *)
+
+type red_expr = (constr, evaluable_global_reference) red_expr_gen
+
+open RedFlags
+
+let make_flag_constant = function
+ | EvalVarRef id -> fVAR id
+ | EvalConstRef sp -> fCONST sp
+
+let make_flag f =
+ let red = no_red in
+ let red = if f.rBeta then red_add red fBETA else red in
+ let red = if f.rIota then red_add red fIOTA else red in
+ let red = if f.rZeta then red_add red fZETA else red in
+ let red =
+ if f.rDelta then (* All but rConst *)
+ let red = red_add red fDELTA in
+ let red = red_add_transparent red (Conv_oracle.freeze ()) in
+ List.fold_right
+ (fun v red -> red_sub red (make_flag_constant v))
+ f.rConst red
+ else (* Only rConst *)
+ let red = red_add_transparent (red_add red fDELTA) all_opaque in
+ List.fold_right
+ (fun v red -> red_add red (make_flag_constant v))
+ f.rConst red
+ in red
+
+let red_expr_tab = ref Stringmap.empty
+
+let declare_red_expr s f =
+ try
+ let _ = Stringmap.find s !red_expr_tab in
+ error ("There is already a reduction expression of name "^s)
+ with Not_found ->
+ red_expr_tab := Stringmap.add s f !red_expr_tab
+
+let reduction_of_redexp = function
+ | Red internal -> if internal then internal_red_product else red_product
+ | Hnf -> hnf_constr
+ | Simpl (Some (_,c as lp)) -> contextually (is_reference c) lp nf
+ | Simpl None -> nf
+ | Cbv f -> cbv_norm_flags (make_flag f)
+ | Lazy f -> clos_norm_flags (make_flag f)
+ | Unfold ubinds -> unfoldn ubinds
+ | Fold cl -> fold_commands cl
+ | Pattern lp -> pattern_occs lp
+ | ExtraRedExpr (s,c) ->
+ (try Stringmap.find s !red_expr_tab
+ with Not_found -> error("unknown user-defined reduction \""^s^"\""))
+(* Used in several tactics. *)
+
+exception NotStepReducible
+
+let one_step_reduce env sigma c =
+ let rec redrec (x, largs as s) =
+ match kind_of_term x with
+ | Lambda (n,t,c) ->
+ (match decomp_stack largs with
+ | None -> raise NotStepReducible
+ | Some (a,rest) -> (subst1 a c, rest))
+ | App (f,cl) -> redrec (f, append_stack cl largs)
+ | LetIn (_,f,_,cl) -> (subst1 f cl,largs)
+ | Case (ci,p,c,lf) ->
+ (try
+ (special_red_case sigma env (whd_betadeltaiota_state env sigma)
+ (ci,p,c,lf), largs)
+ with Redelimination -> raise NotStepReducible)
+ | Fix fix ->
+ (match reduce_fix (whd_betadeltaiota_state env sigma) fix largs with
+ | Reduced s' -> s'
+ | NotReducible -> raise NotStepReducible)
+ | Cast (c,_) -> redrec (c,largs)
+ | _ when isEvalRef env x ->
+ let ref =
+ try destEvalRef x
+ with Redelimination -> raise NotStepReducible in
+ (try
+ red_elim_const env sigma ref largs
+ with Redelimination ->
+ match reference_opt_value sigma env ref with
+ | Some d -> d, largs
+ | None -> raise NotStepReducible)
+
+ | _ -> raise NotStepReducible
+ in
+ app_stack (redrec (c, empty_stack))
+
+(* put t as t'=(x1:A1)..(xn:An)B with B an inductive definition of name name
+ return name, B and t' *)
+
+let reduce_to_ind_gen allow_product env sigma t =
+ let rec elimrec env t l =
+ let c, _ = Reductionops.whd_stack t in
+ match kind_of_term c with
+ | Ind (mind,args) -> ((mind,args),it_mkProd_or_LetIn t l)
+ | Prod (n,ty,t') ->
+ if allow_product then
+ elimrec (push_rel (n,None,t) env) t' ((n,None,ty)::l)
+ else
+ errorlabstrm "tactics__reduce_to_mind"
+ (str"Not an inductive definition")
+ | _ ->
+ (try
+ let t' = nf_betaiota (one_step_reduce env sigma t) in
+ elimrec env t' l
+ with NotStepReducible ->
+ errorlabstrm "tactics__reduce_to_mind"
+ (str"Not an inductive product"))
+ in
+ elimrec env t []
+
+let reduce_to_quantified_ind x = reduce_to_ind_gen true x
+let reduce_to_atomic_ind x = reduce_to_ind_gen false x
+
+let reduce_to_ref_gen allow_product env sigma ref t =
+ let rec elimrec env t l =
+ let c, _ = Reductionops.whd_stack t in
+ match kind_of_term c with
+ | Prod (n,ty,t') ->
+ if allow_product then
+ elimrec (push_rel (n,None,t) env) t' ((n,None,ty)::l)
+ else
+ errorlabstrm "Tactics.reduce_to_ref_gen"
+ (str"Not an induction object of atomic type")
+ | _ ->
+ try
+ if reference_of_constr c = ref
+ then it_mkProd_or_LetIn t l
+ else raise Not_found
+ with Not_found ->
+ try
+ let t' = nf_betaiota (one_step_reduce env sigma t) in
+ elimrec env t' l
+ with NotStepReducible -> raise Not_found
+ in
+ elimrec env t []
+
+let reduce_to_quantified_ref = reduce_to_ref_gen true
+let reduce_to_atomic_ref = reduce_to_ref_gen false
diff --git a/pretyping/tacred.mli b/pretyping/tacred.mli
new file mode 100644
index 00000000..162275d5
--- /dev/null
+++ b/pretyping/tacred.mli
@@ -0,0 +1,85 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: tacred.mli,v 1.21.2.1 2004/07/16 19:30:46 herbelin Exp $ i*)
+
+(*i*)
+open Names
+open Term
+open Environ
+open Evd
+open Reductionops
+open Closure
+open Rawterm
+(*i*)
+
+(*s Reduction functions associated to tactics. \label{tacred} *)
+
+val is_evaluable : env -> evaluable_global_reference -> bool
+
+exception Redelimination
+
+(* Red (raise Redelimination if nothing reducible) *)
+val red_product : reduction_function
+
+(* Hnf *)
+val hnf_constr : reduction_function
+
+(* Simpl *)
+val nf : reduction_function
+
+(* Unfold *)
+val unfoldn :
+ (int list * evaluable_global_reference) list -> reduction_function
+
+(* Fold *)
+val fold_commands : constr list -> reduction_function
+
+(* Pattern *)
+val pattern_occs : (int list * constr) list -> reduction_function
+(* Rem: Lazy strategies are defined in Reduction *)
+
+(* Call by value strategy (uses Closures) *)
+val cbv_norm_flags : Closure.RedFlags.reds -> reduction_function
+ val cbv_beta : local_reduction_function
+ val cbv_betaiota : local_reduction_function
+ val cbv_betadeltaiota : reduction_function
+ val compute : reduction_function (* = [cbv_betadeltaiota] *)
+
+(* [reduce_to_atomic_ind env sigma t] puts [t] in the form [t'=(I args)]
+ with [I] an inductive definition;
+ returns [I] and [t'] or fails with a user error *)
+val reduce_to_atomic_ind : env -> evar_map -> types -> inductive * types
+
+(* [reduce_to_quantified_ind env sigma t] puts [t] in the form
+ [t'=(x1:A1)..(xn:An)(I args)] with [I] an inductive definition;
+ returns [I] and [t'] or fails with a user error *)
+val reduce_to_quantified_ind : env -> evar_map -> types -> inductive * types
+
+(* [reduce_to_quantified_ref env sigma ref t] try to put [t] in the form
+ [t'=(x1:A1)..(xn:An)(ref args)] and raise Not_found if not possible *)
+val reduce_to_quantified_ref :
+ env -> evar_map -> Libnames.global_reference -> types -> types
+
+val reduce_to_atomic_ref :
+ env -> evar_map -> Libnames.global_reference -> types -> types
+
+type red_expr = (constr, evaluable_global_reference) red_expr_gen
+
+val contextually : bool -> constr occurrences -> reduction_function
+ -> reduction_function
+val reduction_of_redexp : red_expr -> reduction_function
+
+val declare_red_expr : string -> reduction_function -> unit
+
+(* Opaque and Transparent commands. *)
+val set_opaque_const : constant -> unit
+val set_transparent_const : constant -> unit
+
+val set_opaque_var : identifier -> unit
+val set_transparent_var : identifier -> unit
diff --git a/pretyping/termops.ml b/pretyping/termops.ml
new file mode 100644
index 00000000..8f12ca62
--- /dev/null
+++ b/pretyping/termops.ml
@@ -0,0 +1,938 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: termops.ml,v 1.29.2.1 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Nameops
+open Term
+open Sign
+open Environ
+open Libnames
+open Nametab
+
+(* Sorts and sort family *)
+
+let print_sort = function
+ | Prop Pos -> (str "Set")
+ | Prop Null -> (str "Prop")
+ | Type u -> (str "Type(" ++ Univ.pr_uni u ++ str ")")
+
+let print_sort_family = function
+ | InSet -> (str "Set")
+ | InProp -> (str "Prop")
+ | InType -> (str "Type")
+
+let pr_name = function
+ | Name id -> pr_id id
+ | Anonymous -> str "_"
+
+let pr_sp sp = str(string_of_kn sp)
+
+let rec print_constr c = match kind_of_term c with
+ | Rel n -> str "#"++int n
+ | Meta n -> str "Meta(" ++ int n ++ str ")"
+ | Var id -> pr_id id
+ | Sort s -> print_sort s
+ | Cast (c,t) -> hov 1
+ (str"(" ++ print_constr c ++ cut() ++
+ str":" ++ print_constr t ++ str")")
+ | Prod (Name(id),t,c) -> hov 1
+ (str"forall " ++ pr_id id ++ str":" ++ print_constr t ++ str"," ++
+ spc() ++ print_constr c)
+ | Prod (Anonymous,t,c) -> hov 0
+ (str"(" ++ print_constr t ++ str " ->" ++ spc() ++
+ print_constr c ++ str")")
+ | Lambda (na,t,c) -> hov 1
+ (str"fun " ++ pr_name na ++ str":" ++
+ print_constr t ++ str" =>" ++ spc() ++ print_constr c)
+ | LetIn (na,b,t,c) -> hov 0
+ (str"let " ++ pr_name na ++ str":=" ++ print_constr b ++
+ str":" ++ brk(1,2) ++ print_constr t ++ cut() ++
+ print_constr c)
+ | App (c,l) -> hov 1
+ (str"(" ++ print_constr c ++ spc() ++
+ prlist_with_sep spc print_constr (Array.to_list l) ++ str")")
+ | Evar (e,l) -> hov 1
+ (str"Evar#" ++ int e ++ str"{" ++
+ prlist_with_sep spc print_constr (Array.to_list l) ++str"}")
+ | Const c -> str"Cst(" ++ pr_sp c ++ str")"
+ | Ind (sp,i) -> str"Ind(" ++ pr_sp sp ++ str"," ++ int i ++ str")"
+ | Construct ((sp,i),j) ->
+ str"Constr(" ++ pr_sp sp ++ str"," ++ int i ++ str"," ++ int j ++ str")"
+ | Case (ci,p,c,bl) -> v 0
+ (hv 0 (str"<"++print_constr p++str">"++ cut() ++ str"Case " ++
+ print_constr c ++ str"of") ++ cut() ++
+ prlist_with_sep (fun _ -> brk(1,2)) print_constr (Array.to_list bl) ++
+ cut() ++ str"end")
+ | Fix ((t,i),(lna,tl,bl)) ->
+ let fixl = Array.mapi (fun i na -> (na,t.(i),tl.(i),bl.(i))) lna in
+ hov 1
+ (str"fix " ++ int i ++ spc() ++ str"{" ++
+ v 0 (prlist_with_sep spc (fun (na,i,ty,bd) ->
+ pr_name na ++ str"/" ++ int i ++ str":" ++ print_constr ty ++
+ cut() ++ str":=" ++ print_constr bd) (Array.to_list fixl)) ++
+ str"}")
+ | CoFix(i,(lna,tl,bl)) ->
+ let fixl = Array.mapi (fun i na -> (na,tl.(i),bl.(i))) lna in
+ hov 1
+ (str"cofix " ++ int i ++ spc() ++ str"{" ++
+ v 0 (prlist_with_sep spc (fun (na,ty,bd) ->
+ pr_name na ++ str":" ++ print_constr ty ++
+ cut() ++ str":=" ++ print_constr bd) (Array.to_list fixl)) ++
+ str"}")
+
+(*let current_module = ref empty_dirpath
+
+let set_module m = current_module := m*)
+
+let new_univ =
+ let univ_gen = ref 0 in
+ (fun sp ->
+ incr univ_gen;
+ Univ.make_univ (Lib.library_dp(),!univ_gen))
+
+let new_sort_in_family = function
+ | InProp -> mk_Prop
+ | InSet -> mk_Set
+ | InType -> Type (new_univ ())
+
+
+
+(* prod_it b [xn:Tn;..;x1:T1] = (x1:T1)..(xn:Tn)b *)
+let prod_it ~init = List.fold_left (fun c (n,t) -> mkProd (n, t, c)) init
+
+(* lam_it b [xn:Tn;..;x1:T1] = [x1:T1]..[xn:Tn]b *)
+let lam_it ~init = List.fold_left (fun c (n,t) -> mkLambda (n, t, c)) init
+
+(* [Rel (n+m);...;Rel(n+1)] *)
+let rel_vect n m = Array.init m (fun i -> mkRel(n+m-i))
+
+let rel_list n m =
+ let rec reln l p =
+ if p>m then l else reln (mkRel(n+p)::l) (p+1)
+ in
+ reln [] 1
+
+(* Same as [rel_list] but takes a context as argument and skips let-ins *)
+let extended_rel_list n hyps =
+ let rec reln l p = function
+ | (_,None,_) :: hyps -> reln (mkRel (n+p) :: l) (p+1) hyps
+ | (_,Some _,_) :: hyps -> reln l (p+1) hyps
+ | [] -> l
+ in
+ reln [] 1 hyps
+
+let extended_rel_vect n hyps = Array.of_list (extended_rel_list n hyps)
+
+
+
+let push_rel_assum (x,t) env = push_rel (x,None,t) env
+
+let push_rels_assum assums =
+ push_rel_context (List.map (fun (x,t) -> (x,None,t)) assums)
+
+let push_named_rec_types (lna,typarray,_) env =
+ let ctxt =
+ array_map2_i
+ (fun i na t ->
+ match na with
+ | Name id -> (id, None, type_app (lift i) t)
+ | Anonymous -> anomaly "Fix declarations must be named")
+ lna typarray in
+ Array.fold_left
+ (fun e assum -> push_named assum e) env ctxt
+
+let rec lookup_rel_id id sign =
+ let rec lookrec = function
+ | (n, (Anonymous,_,_)::l) -> lookrec (n+1,l)
+ | (n, (Name id',_,t)::l) -> if id' = id then (n,t) else lookrec (n+1,l)
+ | (_, []) -> raise Not_found
+ in
+ lookrec (1,sign)
+
+(* Constructs either [(x:t)c] or [[x=b:t]c] *)
+let mkProd_or_LetIn (na,body,t) c =
+ match body with
+ | None -> mkProd (na, t, c)
+ | Some b -> mkLetIn (na, b, t, c)
+
+(* Constructs either [(x:t)c] or [c] where [x] is replaced by [b] *)
+let mkProd_wo_LetIn (na,body,t) c =
+ match body with
+ | None -> mkProd (na, t, c)
+ | Some b -> subst1 b c
+
+let it_mkProd_wo_LetIn ~init =
+ List.fold_left (fun c d -> mkProd_wo_LetIn d c) init
+
+let it_mkProd_or_LetIn ~init =
+ List.fold_left (fun c d -> mkProd_or_LetIn d c) init
+
+let it_mkLambda_or_LetIn ~init =
+ List.fold_left (fun c d -> mkLambda_or_LetIn d c) init
+
+let it_named_context_quantifier f ~init =
+ List.fold_left (fun c d -> f d c) init
+
+let it_mkNamedProd_or_LetIn = it_named_context_quantifier mkNamedProd_or_LetIn
+let it_mkNamedLambda_or_LetIn = it_named_context_quantifier mkNamedLambda_or_LetIn
+
+(* *)
+
+(* strips head casts and flattens head applications *)
+let rec strip_head_cast c = match kind_of_term c with
+ | App (f,cl) ->
+ let rec collapse_rec f cl2 = match kind_of_term f with
+ | App (g,cl1) -> collapse_rec g (Array.append cl1 cl2)
+ | Cast (c,_) -> collapse_rec c cl2
+ | _ -> if cl2 = [||] then f else mkApp (f,cl2)
+ in
+ collapse_rec f cl
+ | Cast (c,t) -> strip_head_cast c
+ | _ -> c
+
+(* [map_constr_with_named_binders g f l c] maps [f l] on the immediate
+ subterms of [c]; it carries an extra data [l] (typically a name
+ list) which is processed by [g na] (which typically cons [na] to
+ [l]) at each binder traversal (with name [na]); it is not recursive
+ and the order with which subterms are processed is not specified *)
+
+let map_constr_with_named_binders g f l c = match kind_of_term c with
+ | (Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _
+ | Construct _) -> c
+ | Cast (c,t) -> mkCast (f l c, f l t)
+ | Prod (na,t,c) -> mkProd (na, f l t, f (g na l) c)
+ | Lambda (na,t,c) -> mkLambda (na, f l t, f (g na l) c)
+ | LetIn (na,b,t,c) -> mkLetIn (na, f l b, f l t, f (g na l) c)
+ | App (c,al) -> mkApp (f l c, Array.map (f l) al)
+ | Evar (e,al) -> mkEvar (e, Array.map (f l) al)
+ | Case (ci,p,c,bl) -> mkCase (ci, f l p, f l c, Array.map (f l) bl)
+ | Fix (ln,(lna,tl,bl)) ->
+ let l' = Array.fold_left (fun l na -> g na l) l lna in
+ mkFix (ln,(lna,Array.map (f l) tl,Array.map (f l') bl))
+ | CoFix(ln,(lna,tl,bl)) ->
+ let l' = Array.fold_left (fun l na -> g na l) l lna in
+ mkCoFix (ln,(lna,Array.map (f l) tl,Array.map (f l') bl))
+
+(* [map_constr_with_binders_left_to_right g f n c] maps [f n] on the
+ immediate subterms of [c]; it carries an extra data [n] (typically
+ a lift index) which is processed by [g] (which typically add 1 to
+ [n]) at each binder traversal; the subterms are processed from left
+ to right according to the usual representation of the constructions
+ (this may matter if [f] does a side-effect); it is not recursive;
+ in fact, the usual representation of the constructions is at the
+ time being almost those of the ML representation (except for
+ (co-)fixpoint) *)
+
+let fold_rec_types g (lna,typarray,_) e =
+ let ctxt =
+ array_map2_i
+ (fun i na t -> (na, None, type_app (lift i) t)) lna typarray in
+ Array.fold_left
+ (fun e assum -> g assum e) e ctxt
+
+
+let map_constr_with_binders_left_to_right g f l c = match kind_of_term c with
+ | (Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _
+ | Construct _) -> c
+ | Cast (c,t) -> let c' = f l c in mkCast (c', f l t)
+ | Prod (na,t,c) ->
+ let t' = f l t in
+ mkProd (na, t', f (g (na,None,t) l) c)
+ | Lambda (na,t,c) ->
+ let t' = f l t in
+ mkLambda (na, t', f (g (na,None,t) l) c)
+ | LetIn (na,b,t,c) ->
+ let b' = f l b in
+ let t' = f l t in
+ let c' = f (g (na,Some b,t) l) c in
+ mkLetIn (na, b', t', c')
+ | App (c,[||]) -> assert false
+ | App (c,al) ->
+ (*Special treatment to be able to recognize partially applied subterms*)
+ let a = al.(Array.length al - 1) in
+ let hd = f l (mkApp (c, Array.sub al 0 (Array.length al - 1))) in
+ mkApp (hd, [| f l a |])
+ | Evar (e,al) -> mkEvar (e, array_map_left (f l) al)
+ | Case (ci,p,c,bl) ->
+ let p' = f l p in let c' = f l c in
+ mkCase (ci, p', c', array_map_left (f l) bl)
+ | Fix (ln,(lna,tl,bl as fx)) ->
+ let l' = fold_rec_types g fx l in
+ let (tl',bl') = array_map_left_pair (f l) tl (f l') bl in
+ mkFix (ln,(lna,tl',bl'))
+ | CoFix(ln,(lna,tl,bl as fx)) ->
+ let l' = fold_rec_types g fx l in
+ let (tl',bl') = array_map_left_pair (f l) tl (f l') bl in
+ mkCoFix (ln,(lna,tl',bl'))
+
+(* strong *)
+let map_constr_with_full_binders g f l cstr = match kind_of_term cstr with
+ | (Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _
+ | Construct _) -> cstr
+ | Cast (c,t) ->
+ let c' = f l c in
+ let t' = f l t in
+ if c==c' && t==t' then cstr else mkCast (c', t')
+ | Prod (na,t,c) ->
+ let t' = f l t in
+ let c' = f (g (na,None,t) l) c in
+ if t==t' && c==c' then cstr else mkProd (na, t', c')
+ | Lambda (na,t,c) ->
+ let t' = f l t in
+ let c' = f (g (na,None,t) l) c in
+ if t==t' && c==c' then cstr else mkLambda (na, t', c')
+ | LetIn (na,b,t,c) ->
+ let b' = f l b in
+ let t' = f l t in
+ let c' = f (g (na,Some b,t) l) c in
+ if b==b' && t==t' && c==c' then cstr else mkLetIn (na, b', t', c')
+ | App (c,al) ->
+ let c' = f l c in
+ let al' = Array.map (f l) al in
+ if c==c' && array_for_all2 (==) al al' then cstr else mkApp (c', al')
+ | Evar (e,al) ->
+ let al' = Array.map (f l) al in
+ if array_for_all2 (==) al al' then cstr else mkEvar (e, al')
+ | Case (ci,p,c,bl) ->
+ let p' = f l p in
+ let c' = f l c in
+ let bl' = Array.map (f l) bl in
+ if p==p' && c==c' && array_for_all2 (==) bl bl' then cstr else
+ mkCase (ci, p', c', bl')
+ | Fix (ln,(lna,tl,bl)) ->
+ let tl' = Array.map (f l) tl in
+ let l' =
+ array_fold_left2 (fun l na t -> g (na,None,t) l) l lna tl in
+ let bl' = Array.map (f l') bl in
+ if array_for_all2 (==) tl tl' && array_for_all2 (==) bl bl'
+ then cstr
+ else mkFix (ln,(lna,tl',bl'))
+ | CoFix(ln,(lna,tl,bl)) ->
+ let tl' = Array.map (f l) tl in
+ let l' =
+ array_fold_left2 (fun l na t -> g (na,None,t) l) l lna tl in
+ let bl' = Array.map (f l') bl in
+ if array_for_all2 (==) tl tl' && array_for_all2 (==) bl bl'
+ then cstr
+ else mkCoFix (ln,(lna,tl',bl'))
+
+(* [fold_constr_with_binders g f n acc c] folds [f n] on the immediate
+ subterms of [c] starting from [acc] and proceeding from left to
+ right according to the usual representation of the constructions as
+ [fold_constr] but it carries an extra data [n] (typically a lift
+ index) which is processed by [g] (which typically add 1 to [n]) at
+ each binder traversal; it is not recursive *)
+
+let fold_constr_with_binders g f n acc c = match kind_of_term c with
+ | (Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _
+ | Construct _) -> acc
+ | Cast (c,t) -> f n (f n acc c) t
+ | Prod (_,t,c) -> f (g n) (f n acc t) c
+ | Lambda (_,t,c) -> f (g n) (f n acc t) c
+ | LetIn (_,b,t,c) -> f (g n) (f n (f n acc b) t) c
+ | App (c,l) -> Array.fold_left (f n) (f n acc c) l
+ | Evar (_,l) -> Array.fold_left (f n) acc l
+ | Case (_,p,c,bl) -> Array.fold_left (f n) (f n (f n acc p) c) bl
+ | Fix (_,(lna,tl,bl)) ->
+ let n' = iterate g (Array.length tl) n in
+ let fd = array_map2 (fun t b -> (t,b)) tl bl in
+ Array.fold_left (fun acc (t,b) -> f n (f n' acc t) b) acc fd
+ | CoFix (_,(lna,tl,bl)) ->
+ let n' = iterate g (Array.length tl) n in
+ let fd = array_map2 (fun t b -> (t,b)) tl bl in
+ Array.fold_left (fun acc (t,b) -> f n (f n' acc t) b) acc fd
+
+(* [iter_constr_with_full_binders g f acc c] iters [f acc] on the immediate
+ subterms of [c]; it carries an extra data [acc] which is processed by [g] at
+ each binder traversal; it is not recursive and the order with which
+ subterms are processed is not specified *)
+
+let iter_constr_with_full_binders g f l c = match kind_of_term c with
+ | (Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _
+ | Construct _) -> ()
+ | Cast (c,t) -> f l c; f l t
+ | Prod (na,t,c) -> f l t; f (g (na,None,t) l) c
+ | Lambda (na,t,c) -> f l t; f (g (na,None,t) l) c
+ | LetIn (na,b,t,c) -> f l b; f l t; f (g (na,Some b,t) l) c
+ | App (c,args) -> f l c; Array.iter (f l) args
+ | Evar (_,args) -> Array.iter (f l) args
+ | Case (_,p,c,bl) -> f l p; f l c; Array.iter (f l) bl
+ | Fix (_,(lna,tl,bl)) ->
+ let l' = array_fold_left2 (fun l na t -> g (na,None,t) l) l lna tl in
+ Array.iter (f l) tl;
+ Array.iter (f l') bl
+ | CoFix (_,(lna,tl,bl)) ->
+ let l' = array_fold_left2 (fun l na t -> g (na,None,t) l) l lna tl in
+ Array.iter (f l) tl;
+ Array.iter (f l') bl
+
+(***************************)
+(* occurs check functions *)
+(***************************)
+
+exception Occur
+
+let occur_meta c =
+ let rec occrec c = match kind_of_term c with
+ | Meta _ -> raise Occur
+ | _ -> iter_constr occrec c
+ in try occrec c; false with Occur -> true
+
+let occur_existential c =
+ let rec occrec c = match kind_of_term c with
+ | Evar _ -> raise Occur
+ | _ -> iter_constr occrec c
+ in try occrec c; false with Occur -> true
+
+let occur_const s c =
+ let rec occur_rec c = match kind_of_term c with
+ | Const sp when sp=s -> raise Occur
+ | _ -> iter_constr occur_rec c
+ in
+ try occur_rec c; false with Occur -> true
+
+let occur_evar n c =
+ let rec occur_rec c = match kind_of_term c with
+ | Evar (sp,_) when sp=n -> raise Occur
+ | _ -> iter_constr occur_rec c
+ in
+ try occur_rec c; false with Occur -> true
+
+let occur_in_global env id constr =
+ let vars = vars_of_global env constr in
+ if List.mem id vars then raise Occur
+
+let occur_var env s c =
+ let rec occur_rec c =
+ occur_in_global env s c;
+ iter_constr occur_rec c
+ in
+ try occur_rec c; false with Occur -> true
+
+let occur_var_in_decl env hyp (_,c,typ) =
+ match c with
+ | None -> occur_var env hyp typ
+ | Some body ->
+ occur_var env hyp typ ||
+ occur_var env hyp body
+
+(* Tests that t is a subterm of c *)
+let occur_term t c =
+ let eq_constr_fail c = if eq_constr t c then raise Occur
+ in let rec occur_rec c = eq_constr_fail c; iter_constr occur_rec c
+ in try occur_rec c; false with Occur -> true
+
+(* returns the list of free debruijn indices in a term *)
+
+let free_rels m =
+ let rec frec depth acc c = match kind_of_term c with
+ | Rel n -> if n >= depth then Intset.add (n-depth+1) acc else acc
+ | _ -> fold_constr_with_binders succ frec depth acc c
+ in
+ frec 1 Intset.empty m
+
+
+(* (dependent M N) is true iff M is eq_term with a subterm of N
+ M is appropriately lifted through abstractions of N *)
+
+let dependent m t =
+ let rec deprec m t =
+ if eq_constr m t then
+ raise Occur
+ else
+ match kind_of_term m, kind_of_term t with
+ | App (fm,lm), App (ft,lt) when Array.length lm < Array.length lt ->
+ deprec m (mkApp (ft,Array.sub lt 0 (Array.length lm)));
+ Array.iter (deprec m)
+ (Array.sub lt
+ (Array.length lm) ((Array.length lt) - (Array.length lm)))
+ | _ -> iter_constr_with_binders (lift 1) deprec m t
+ in
+ try deprec m t; false with Occur -> true
+
+let pop t = lift (-1) t
+
+(***************************)
+(* bindings functions *)
+(***************************)
+
+type metamap = (metavariable * constr) list
+
+let rec subst_meta bl c =
+ match kind_of_term c with
+ | Meta i -> (try List.assoc i bl with Not_found -> c)
+ | _ -> map_constr (subst_meta bl) c
+
+(* First utilities for avoiding telescope computation for subst_term *)
+
+let prefix_application eq_fun (k,c) (t : constr) =
+ let c' = collapse_appl c and t' = collapse_appl t in
+ match kind_of_term c', kind_of_term t' with
+ | App (f1,cl1), App (f2,cl2) ->
+ let l1 = Array.length cl1
+ and l2 = Array.length cl2 in
+ if l1 <= l2
+ && eq_fun c' (mkApp (f2, Array.sub cl2 0 l1)) then
+ Some (mkApp (mkRel k, Array.sub cl2 l1 (l2 - l1)))
+ else
+ None
+ | _ -> None
+
+let my_prefix_application eq_fun (k,c) (by_c : constr) (t : constr) =
+ let c' = collapse_appl c and t' = collapse_appl t in
+ match kind_of_term c', kind_of_term t' with
+ | App (f1,cl1), App (f2,cl2) ->
+ let l1 = Array.length cl1
+ and l2 = Array.length cl2 in
+ if l1 <= l2
+ && eq_fun c' (mkApp (f2, Array.sub cl2 0 l1)) then
+ Some (mkApp ((lift k by_c), Array.sub cl2 l1 (l2 - l1)))
+ else
+ None
+ | _ -> None
+
+(* Recognizing occurrences of a given (closed) subterm in a term for Pattern :
+ [subst_term c t] substitutes [(Rel 1)] for all occurrences of (closed)
+ term [c] in a term [t] *)
+(*i Bizarre : si on cherche un sous terme clos, pourquoi le lifter ? i*)
+
+let subst_term_gen eq_fun c t =
+ let rec substrec (k,c as kc) t =
+ match prefix_application eq_fun kc t with
+ | Some x -> x
+ | None ->
+ if eq_fun c t then mkRel k
+ else
+ map_constr_with_binders (fun (k,c) -> (k+1,lift 1 c)) substrec kc t
+ in
+ substrec (1,c) t
+
+(* Recognizing occurrences of a given (closed) subterm in a term :
+ [replace_term c1 c2 t] substitutes [c2] for all occurrences of (closed)
+ term [c1] in a term [t] *)
+(*i Meme remarque : a priori [c] n'est pas forcement clos i*)
+
+let replace_term_gen eq_fun c by_c in_t =
+ let rec substrec (k,c as kc) t =
+ match my_prefix_application eq_fun kc by_c t with
+ | Some x -> x
+ | None ->
+ (if eq_fun c t then (lift k by_c) else
+ map_constr_with_binders (fun (k,c) -> (k+1,lift 1 c))
+ substrec kc t)
+ in
+ substrec (0,c) in_t
+
+let subst_term = subst_term_gen eq_constr
+
+let replace_term = replace_term_gen eq_constr
+
+(* Substitute only a list of locations locs, the empty list is
+ interpreted as substitute all, if 0 is in the list then no
+ bindings is done. The list may contain only negative occurrences
+ that will not be substituted. *)
+
+let subst_term_occ_gen locs occ c t =
+ let maxocc = List.fold_right max locs 0 in
+ let pos = ref occ in
+ let check = ref true in
+ let except = List.exists (fun n -> n<0) locs in
+ if except & (List.exists (fun n -> n>=0) locs)
+ then error "mixing of positive and negative occurences"
+ else
+ let rec substrec (k,c as kc) t =
+ if (not except) & (!pos > maxocc) then t
+ else
+ if eq_constr c t then
+ let r =
+ if except then
+ if List.mem (- !pos) locs then t else (mkRel k)
+ else
+ if List.mem !pos locs then (mkRel k) else t
+ in incr pos; r
+ else
+ map_constr_with_binders_left_to_right
+ (fun d (k,c) -> (k+1,lift 1 c))
+ substrec kc t
+ in
+ let t' = substrec (1,c) t in
+ (!pos, t')
+
+let subst_term_occ locs c t =
+ if locs = [] then subst_term c t
+ else if List.mem 0 locs then
+ t
+ else
+ let (nbocc,t') = subst_term_occ_gen locs 1 c t in
+ if List.exists (fun o -> o >= nbocc or o <= -nbocc) locs then
+ errorlabstrm "subst_term_occ" (str "Too few occurences");
+ t'
+
+let subst_term_occ_decl locs c (id,bodyopt,typ as d) =
+ match bodyopt with
+ | None -> (id,None,subst_term_occ locs c typ)
+ | Some body ->
+ if locs = [] then
+ (id,Some (subst_term c body),type_app (subst_term c) typ)
+ else if List.mem 0 locs then
+ d
+ else
+ let (nbocc,body') = subst_term_occ_gen locs 1 c body in
+ let (nbocc',t') = subst_term_occ_gen locs nbocc c typ in
+ if List.exists (fun o -> o >= nbocc' or o <= -nbocc') locs then
+ errorlabstrm "subst_term_occ_decl" (str "Too few occurences");
+ (id,Some body',t')
+
+
+(* First character of a constr *)
+
+let first_char id =
+ let id = string_of_id id in
+ assert (id <> "");
+ String.make 1 id.[0]
+
+let lowercase_first_char id = String.lowercase (first_char id)
+
+let vars_of_env env =
+ let s =
+ Sign.fold_named_context (fun (id,_,_) s -> Idset.add id s)
+ (named_context env) ~init:Idset.empty in
+ Sign.fold_rel_context
+ (fun (na,_,_) s -> match na with Name id -> Idset.add id s | _ -> s)
+ (rel_context env) ~init:s
+
+let add_vname vars = function
+ Name id -> Idset.add id vars
+ | _ -> vars
+
+let id_of_global = Nametab.id_of_global
+
+let sort_hdchar = function
+ | Prop(_) -> "P"
+ | Type(_) -> "T"
+
+let hdchar env c =
+ let rec hdrec k c =
+ match kind_of_term c with
+ | Prod (_,_,c) -> hdrec (k+1) c
+ | Lambda (_,_,c) -> hdrec (k+1) c
+ | LetIn (_,_,_,c) -> hdrec (k+1) c
+ | Cast (c,_) -> hdrec k c
+ | App (f,l) -> hdrec k f
+ | Const kn ->
+ let c = lowercase_first_char (id_of_label (label kn)) in
+ if c = "?" then "y" else c
+ | Ind ((kn,i) as x) ->
+ if i=0 then
+ lowercase_first_char (id_of_label (label kn))
+ else
+ lowercase_first_char (id_of_global (IndRef x))
+ | Construct ((sp,i) as x) ->
+ lowercase_first_char (id_of_global (ConstructRef x))
+ | Var id -> lowercase_first_char id
+ | Sort s -> sort_hdchar s
+ | Rel n ->
+ (if n<=k then "p" (* the initial term is flexible product/function *)
+ else
+ try match Environ.lookup_rel (n-k) env with
+ | (Name id,_,_) -> lowercase_first_char id
+ | (Anonymous,_,t) -> hdrec 0 (lift (n-k) t)
+ with Not_found -> "y")
+ | Fix ((_,i),(lna,_,_)) ->
+ let id = match lna.(i) with Name id -> id | _ -> assert false in
+ lowercase_first_char id
+ | CoFix (i,(lna,_,_)) ->
+ let id = match lna.(i) with Name id -> id | _ -> assert false in
+ lowercase_first_char id
+ | Meta _|Evar _|Case (_, _, _, _) -> "y"
+ in
+ hdrec 0 c
+
+let id_of_name_using_hdchar env a = function
+ | Anonymous -> id_of_string (hdchar env a)
+ | Name id -> id
+
+let named_hd env a = function
+ | Anonymous -> Name (id_of_string (hdchar env a))
+ | x -> x
+
+let named_hd_type env a = named_hd env (body_of_type a)
+
+let prod_name env (n,a,b) = mkProd (named_hd_type env a n, a, b)
+let lambda_name env (n,a,b) = mkLambda (named_hd_type env a n, a, b)
+
+let prod_create env (a,b) = mkProd (named_hd_type env a Anonymous, a, b)
+let lambda_create env (a,b) = mkLambda (named_hd_type env a Anonymous, a, b)
+
+let name_assumption env (na,c,t) =
+ match c with
+ | None -> (named_hd_type env t na, None, t)
+ | Some body -> (named_hd env body na, c, t)
+
+let name_context env hyps =
+ snd
+ (List.fold_left
+ (fun (env,hyps) d ->
+ let d' = name_assumption env d in (push_rel d' env, d' :: hyps))
+ (env,[]) (List.rev hyps))
+
+let mkProd_or_LetIn_name env b d = mkProd_or_LetIn (name_assumption env d) b
+let mkLambda_or_LetIn_name env b d = mkLambda_or_LetIn (name_assumption env d)b
+
+let it_mkProd_or_LetIn_name env b hyps =
+ it_mkProd_or_LetIn b (name_context env hyps)
+let it_mkLambda_or_LetIn_name env b hyps =
+ it_mkLambda_or_LetIn b (name_context env hyps)
+
+(*************************)
+(* Names environments *)
+(*************************)
+type names_context = name list
+let add_name n nl = n::nl
+let lookup_name_of_rel p names =
+ try List.nth names (p-1)
+ with Invalid_argument _ | Failure _ -> raise Not_found
+let rec lookup_rel_of_name id names =
+ let rec lookrec n = function
+ | Anonymous :: l -> lookrec (n+1) l
+ | (Name id') :: l -> if id' = id then n else lookrec (n+1) l
+ | [] -> raise Not_found
+ in
+ lookrec 1 names
+let empty_names_context = []
+
+let ids_of_rel_context sign =
+ Sign.fold_rel_context
+ (fun (na,_,_) l -> match na with Name id -> id::l | Anonymous -> l)
+ sign ~init:[]
+let ids_of_named_context sign =
+ Sign.fold_named_context (fun (id,_,_) idl -> id::idl) sign ~init:[]
+
+let ids_of_context env =
+ (ids_of_rel_context (rel_context env))
+ @ (ids_of_named_context (named_context env))
+
+let names_of_rel_context env =
+ List.map (fun (na,_,_) -> na) (rel_context env)
+
+(**** Globality of identifiers *)
+
+(* TODO temporary hack!!! *)
+let rec is_imported_modpath = function
+ | MPfile dp -> dp <> (Lib.library_dp ())
+(* | MPdot (mp,_) -> is_imported_modpath mp *)
+ | _ -> false
+
+let is_imported_ref = function
+ | VarRef _ -> false
+ | ConstRef kn
+ | IndRef (kn,_)
+ | ConstructRef ((kn,_),_)
+(* | ModTypeRef ln *) ->
+ let (mp,_,_) = repr_kn kn in is_imported_modpath mp
+(* | ModRef mp ->
+ is_imported_modpath mp
+*)
+
+let is_global id =
+ try
+ let ref = locate (make_short_qualid id) in
+ not (is_imported_ref ref)
+ with Not_found ->
+ false
+
+let is_section_variable id =
+ try let _ = Sign.lookup_named id (Global.named_context()) in true
+ with Not_found -> false
+
+let next_global_ident_from allow_secvar id avoid =
+ let rec next_rec id =
+ let id = next_ident_away_from id avoid in
+ if (allow_secvar && is_section_variable id) || not (is_global id) then
+ id
+ else
+ next_rec (lift_ident id)
+ in
+ next_rec id
+
+let next_global_ident_away allow_secvar id avoid =
+ let id = next_ident_away id avoid in
+ if (allow_secvar && is_section_variable id) || not (is_global id) then
+ id
+ else
+ next_global_ident_from allow_secvar (lift_ident id) avoid
+
+(* Nouvelle version de renommage des variables (DEC 98) *)
+(* This is the algorithm to display distinct bound variables
+
+ - Règle 1 : un nom non anonyme, même non affiché, contribue à la liste
+ des noms à éviter
+ - Règle 2 : c'est la dépendance qui décide si on affiche ou pas
+
+ Exemple :
+ si bool_ind = (P:bool->Prop)(f:(P true))(f:(P false))(b:bool)(P b), alors
+ il est affiché (P:bool->Prop)(P true)->(P false)->(b:bool)(P b)
+ mais f et f0 contribue à la liste des variables à éviter (en supposant
+ que les noms f et f0 ne sont pas déjà pris)
+ Intérêt : noms homogènes dans un but avant et après Intro
+*)
+
+type used_idents = identifier list
+
+let occur_rel p env id =
+ try lookup_name_of_rel p env = Name id
+ with Not_found -> false (* Unbound indice : may happen in debug *)
+
+let occur_id nenv id0 c =
+ let rec occur n c = match kind_of_term c with
+ | Var id when id=id0 -> raise Occur
+ | Const kn when id_of_global (ConstRef kn) = id0 -> raise Occur
+ | Ind ind_sp
+ when id_of_global (IndRef ind_sp) = id0 ->
+ raise Occur
+ | Construct cstr_sp
+ when id_of_global (ConstructRef cstr_sp) = id0 ->
+ raise Occur
+ | Rel p when p>n & occur_rel (p-n) nenv id0 -> raise Occur
+ | _ -> iter_constr_with_binders succ occur n c
+ in
+ try occur 1 c; false
+ with Occur -> true
+ | Not_found -> false (* Case when a global is not in the env *)
+
+let next_name_not_occuring is_goal_ccl name l env_names t =
+ let rec next id =
+ if List.mem id l or occur_id env_names id t or
+ (* To be consistent with intro mechanism *)
+ (is_goal_ccl & is_global id & not (is_section_variable id))
+ then next (lift_ident id)
+ else id
+ in
+ match name with
+ | Name id -> next id
+ | Anonymous ->
+ (* Normally, an anonymous name is not dependent and will not be *)
+ (* taken into account by the function concrete_name; just in case *)
+ (* invent a valid name *)
+ id_of_string "H"
+
+(* On reduit une serie d'eta-redex de tete ou rien du tout *)
+(* [x1:c1;...;xn:cn]@(f;a1...an;x1;...;xn) --> @(f;a1...an) *)
+(* Remplace 2 versions précédentes buggées *)
+
+let rec eta_reduce_head c =
+ match kind_of_term c with
+ | Lambda (_,c1,c') ->
+ (match kind_of_term (eta_reduce_head c') with
+ | App (f,cl) ->
+ let lastn = (Array.length cl) - 1 in
+ if lastn < 1 then anomaly "application without arguments"
+ else
+ (match kind_of_term cl.(lastn) with
+ | Rel 1 ->
+ let c' =
+ if lastn = 1 then f
+ else mkApp (f, Array.sub cl 0 lastn)
+ in
+ if noccurn 1 c'
+ then lift (-1) c'
+ else c
+ | _ -> c)
+ | _ -> c)
+ | _ -> c
+
+(* alpha-eta conversion : ignore print names and casts *)
+let eta_eq_constr =
+ let rec aux t1 t2 =
+ let t1 = eta_reduce_head (strip_head_cast t1)
+ and t2 = eta_reduce_head (strip_head_cast t2) in
+ t1=t2 or compare_constr aux t1 t2
+ in aux
+
+
+(* iterator on rel context *)
+let process_rel_context f env =
+ let sign = named_context env in
+ let rels = rel_context env in
+ let env0 = reset_with_named_context sign env in
+ Sign.fold_rel_context f rels ~init:env0
+
+let assums_of_rel_context sign =
+ Sign.fold_rel_context
+ (fun (na,c,t) l ->
+ match c with
+ Some _ -> l
+ | None -> (na, t)::l)
+ sign ~init:[]
+
+let lift_rel_context n sign =
+ let rec liftrec k = function
+ | (na,c,t)::sign ->
+ (na,option_app (liftn n k) c,type_app (liftn n k) t)
+ ::(liftrec (k-1) sign)
+ | [] -> []
+ in
+ liftrec (rel_context_length sign) sign
+
+let fold_named_context_both_sides f l ~init = list_fold_right_and_left f l init
+
+let rec mem_named_context id = function
+ | (id',_,_) :: _ when id=id' -> true
+ | _ :: sign -> mem_named_context id sign
+ | [] -> false
+
+let make_all_name_different env =
+ let avoid = ref (ids_of_named_context (named_context env)) in
+ process_rel_context
+ (fun (na,c,t) newenv ->
+ let id = next_name_away na !avoid in
+ avoid := id::!avoid;
+ push_rel (Name id,c,t) newenv)
+ env
+
+let global_vars env ids = Idset.elements (global_vars_set env ids)
+
+let global_vars_set_of_decl env = function
+ | (_,None,t) -> global_vars_set env t
+ | (_,Some c,t) ->
+ Idset.union (global_vars_set env t)
+ (global_vars_set env c)
+
+(* Remark: Anonymous var may be dependent in Evar's contexts *)
+let concrete_name is_goal_ccl l env_names n c =
+ if n = Anonymous & noccurn 1 c then
+ (Anonymous,l)
+ else
+ let fresh_id = next_name_not_occuring is_goal_ccl n l env_names c in
+ let idopt = if noccurn 1 c then Anonymous else Name fresh_id in
+ (idopt, fresh_id::l)
+
+let concrete_let_name is_goal_ccl l env_names n c =
+ let fresh_id = next_name_not_occuring is_goal_ccl n l env_names c in
+ (Name fresh_id, fresh_id::l)
+
+let rec rename_bound_var env l c =
+ match kind_of_term c with
+ | Prod (Name s,c1,c2) ->
+ if noccurn 1 c2 then
+ let env' = push_rel (Name s,None,c1) env in
+ mkProd (Name s, c1, rename_bound_var env' l c2)
+ else
+ let s' = next_ident_away s (global_vars env c2@l) in
+ let env' = push_rel (Name s',None,c1) env in
+ mkProd (Name s', c1, rename_bound_var env' (s'::l) c2)
+ | Prod (Anonymous,c1,c2) ->
+ let env' = push_rel (Anonymous,None,c1) env in
+ mkProd (Anonymous, c1, rename_bound_var env' l c2)
+ | Cast (c,t) -> mkCast (rename_bound_var env l c, t)
+ | x -> c
+
diff --git a/pretyping/termops.mli b/pretyping/termops.mli
new file mode 100644
index 00000000..dd9742ea
--- /dev/null
+++ b/pretyping/termops.mli
@@ -0,0 +1,186 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: termops.mli,v 1.21.2.1 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Util
+open Pp
+open Names
+open Term
+open Sign
+open Environ
+
+(* Universes *)
+(*val set_module : Names.dir_path -> unit*)
+val new_univ : unit -> Univ.universe
+val new_sort_in_family : sorts_family -> sorts
+
+(* iterators on terms *)
+val print_sort : sorts -> std_ppcmds
+val print_sort_family : sorts_family -> std_ppcmds
+val print_constr : constr -> std_ppcmds
+val prod_it : init:types -> (name * types) list -> types
+val lam_it : init:constr -> (name * types) list -> constr
+val rel_vect : int -> int -> constr array
+val rel_list : int -> int -> constr list
+val extended_rel_list : int -> rel_context -> constr list
+val extended_rel_vect : int -> rel_context -> constr array
+val push_rel_assum : name * types -> env -> env
+val push_rels_assum : (name * types) list -> env -> env
+val push_named_rec_types : name array * types array * 'a -> env -> env
+val lookup_rel_id : identifier -> rel_context -> int * types
+val mkProd_or_LetIn : rel_declaration -> types -> types
+val mkProd_wo_LetIn : rel_declaration -> types -> types
+val it_mkProd_wo_LetIn : init:types -> rel_context -> types
+val it_mkProd_or_LetIn : init:types -> rel_context -> types
+val it_mkLambda_or_LetIn : init:constr -> rel_context -> constr
+val it_named_context_quantifier :
+ (named_declaration -> 'a -> 'a) -> init:'a -> named_context -> 'a
+val it_mkNamedProd_or_LetIn : init:types -> named_context -> types
+val it_mkNamedLambda_or_LetIn : init:constr -> named_context -> constr
+
+(**********************************************************************)
+(* Generic iterators on constr *)
+
+val map_constr_with_named_binders :
+ (name -> 'a -> 'a) ->
+ ('a -> constr -> constr) -> 'a -> constr -> constr
+val map_constr_with_binders_left_to_right :
+ (rel_declaration -> 'a -> 'a) ->
+ ('a -> constr -> constr) ->
+ 'a -> constr -> constr
+val map_constr_with_full_binders :
+ (rel_declaration -> 'a -> 'a) ->
+ ('a -> constr -> constr) -> 'a -> constr -> constr
+
+(* [fold_constr_with_binders g f n acc c] folds [f n] on the immediate
+ subterms of [c] starting from [acc] and proceeding from left to
+ right according to the usual representation of the constructions as
+ [fold_constr] but it carries an extra data [n] (typically a lift
+ index) which is processed by [g] (which typically add 1 to [n]) at
+ each binder traversal; it is not recursive *)
+
+val fold_constr_with_binders :
+ ('a -> 'a) -> ('a -> 'b -> constr -> 'b) -> 'a -> 'b -> constr -> 'b
+
+val iter_constr_with_full_binders :
+ (rel_declaration -> 'a -> 'a) -> ('a -> constr -> unit) -> 'a ->
+ constr -> unit
+
+(**********************************************************************)
+
+val strip_head_cast : constr -> constr
+
+(* occur checks *)
+exception Occur
+val occur_meta : types -> bool
+val occur_existential : types -> bool
+val occur_const : constant -> types -> bool
+val occur_evar : existential_key -> types -> bool
+val occur_in_global : env -> identifier -> constr -> unit
+val occur_var : env -> identifier -> types -> bool
+val occur_var_in_decl :
+ env ->
+ identifier -> 'a * types option * types -> bool
+val occur_term : constr -> constr -> bool
+val free_rels : constr -> Intset.t
+
+(* Substitution of metavariables *)
+type metamap = (metavariable * constr) list
+val subst_meta : metamap -> constr -> constr
+
+(* [pop c] lifts by -1 the positive indexes in [c] *)
+val pop : constr -> constr
+
+(* bindings of an arbitrary large term. Uses equality modulo
+ reduction of let *)
+val dependent : constr -> constr -> bool
+val subst_term_gen :
+ (constr -> constr -> bool) -> constr -> constr -> constr
+val replace_term_gen :
+ (constr -> constr -> bool) ->
+ constr -> constr -> constr -> constr
+val subst_term : constr -> constr -> constr
+val replace_term : constr -> constr -> constr -> constr
+val subst_term_occ_gen :
+ int list -> int -> constr -> types -> int * types
+val subst_term_occ : int list -> constr -> types -> types
+val subst_term_occ_decl :
+ int list -> constr -> named_declaration -> named_declaration
+
+(* Alternative term equalities *)
+val eta_reduce_head : constr -> constr
+val eta_eq_constr : constr -> constr -> bool
+
+(* finding "intuitive" names to hypotheses *)
+val first_char : identifier -> string
+val lowercase_first_char : identifier -> string
+val sort_hdchar : sorts -> string
+val hdchar : env -> types -> string
+val id_of_name_using_hdchar :
+ env -> types -> name -> identifier
+val named_hd : env -> types -> name -> name
+val named_hd_type : env -> types -> name -> name
+val prod_name : env -> name * types * types -> constr
+val lambda_name : env -> name * types * constr -> constr
+val prod_create : env -> types * types -> constr
+val lambda_create : env -> types * constr -> constr
+val name_assumption : env -> rel_declaration -> rel_declaration
+val name_context : env -> rel_context -> rel_context
+
+val mkProd_or_LetIn_name : env -> types -> rel_declaration -> types
+val mkLambda_or_LetIn_name : env -> constr -> rel_declaration -> constr
+val it_mkProd_or_LetIn_name : env -> types -> rel_context -> types
+val it_mkLambda_or_LetIn_name : env -> constr -> rel_context -> constr
+
+(* name contexts *)
+type names_context = name list
+val add_name : name -> names_context -> names_context
+val lookup_name_of_rel : int -> names_context -> name
+val lookup_rel_of_name : identifier -> names_context -> int
+val empty_names_context : names_context
+val ids_of_rel_context : rel_context -> identifier list
+val ids_of_named_context : named_context -> identifier list
+val ids_of_context : env -> identifier list
+val names_of_rel_context : env -> names_context
+
+(* Set of local names *)
+val vars_of_env: env -> Idset.t
+val add_vname : Idset.t -> name -> Idset.t
+
+(* sets of free identifiers *)
+type used_idents = identifier list
+val occur_rel : int -> name list -> identifier -> bool
+val occur_id : name list -> identifier -> constr -> bool
+
+val next_global_ident_away :
+ (*allow section vars:*) bool -> identifier -> identifier list -> identifier
+val next_name_not_occuring :
+ bool -> name -> identifier list -> name list -> constr -> identifier
+val concrete_name :
+ bool -> identifier list -> name list -> name -> constr ->
+ name * identifier list
+val concrete_let_name :
+ bool -> identifier list -> name list -> name -> constr -> name * identifier list
+val rename_bound_var : env -> identifier list -> types -> types
+
+(* other signature iterators *)
+val process_rel_context : (rel_declaration -> env -> env) -> env -> env
+val assums_of_rel_context : rel_context -> (name * constr) list
+val lift_rel_context : int -> rel_context -> rel_context
+val fold_named_context_both_sides :
+ ('a -> named_declaration -> named_declaration list -> 'a) ->
+ named_context -> init:'a -> 'a
+val mem_named_context : identifier -> named_context -> bool
+val make_all_name_different : env -> env
+
+val global_vars : env -> constr -> identifier list
+val global_vars_set_of_decl : env -> named_declaration -> Idset.t
+
+(* Test if an identifier is the basename of a global reference *)
+val is_section_variable : identifier -> bool
diff --git a/pretyping/typing.ml b/pretyping/typing.ml
new file mode 100644
index 00000000..a84cd612
--- /dev/null
+++ b/pretyping/typing.ml
@@ -0,0 +1,174 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* $Id: typing.ml,v 1.32.6.2 2004/07/16 19:30:46 herbelin Exp $ *)
+
+open Util
+open Names
+open Term
+open Environ
+open Reductionops
+open Type_errors
+open Pretype_errors
+open Inductive
+open Typeops
+
+let vect_lift = Array.mapi lift
+let vect_lift_type = Array.mapi (fun i t -> type_app (lift i) t)
+
+type 'a mach_flags = {
+ fix : bool;
+ nocheck : bool }
+
+(* The typing machine without information, without universes but with
+ existential variables. *)
+
+let assumption_of_judgment env sigma j =
+ assumption_of_judgment env (j_nf_evar sigma j)
+
+let type_judgment env sigma j =
+ type_judgment env (j_nf_evar sigma j)
+
+
+let rec execute mf env sigma cstr =
+ match kind_of_term cstr with
+ | Meta n ->
+ error "execute: found a non-instanciated goal"
+
+ | Evar ev ->
+ let ty = Instantiate.existential_type sigma ev in
+ let jty = execute mf env sigma ty in
+ let jty = assumption_of_judgment env sigma jty in
+ { uj_val = cstr; uj_type = jty }
+
+ | Rel n ->
+ judge_of_relative env n
+
+ | Var id ->
+ judge_of_variable env id
+
+ | Const c ->
+ make_judge cstr (constant_type env c)
+
+ | Ind ind ->
+ make_judge cstr (type_of_inductive env ind)
+
+ | Construct cstruct ->
+ make_judge cstr (type_of_constructor env cstruct)
+
+ | Case (ci,p,c,lf) ->
+ let cj = execute mf env sigma c in
+ let pj = execute mf env sigma p in
+ let lfj = execute_array mf env sigma lf in
+ let (j,_) = judge_of_case env ci pj cj lfj in
+ j
+
+ | Fix ((vn,i as vni),recdef) ->
+ if (not mf.fix) && array_exists (fun n -> n < 0) vn then
+ error "General Fixpoints not allowed";
+ let (_,tys,_ as recdef') = execute_recdef mf env sigma recdef in
+ let fix = (vni,recdef') in
+ check_fix env fix;
+ make_judge (mkFix fix) tys.(i)
+
+ | CoFix (i,recdef) ->
+ let (_,tys,_ as recdef') = execute_recdef mf env sigma recdef in
+ let cofix = (i,recdef') in
+ check_cofix env cofix;
+ make_judge (mkCoFix cofix) tys.(i)
+
+ | Sort (Prop c) ->
+ judge_of_prop_contents c
+
+ | Sort (Type u) ->
+ judge_of_type u
+
+ | App (f,args) ->
+ let j = execute mf env sigma f in
+ let jl = execute_array mf env sigma args in
+ let (j,_) = judge_of_apply env j jl in
+ j
+
+ | Lambda (name,c1,c2) ->
+ let j = execute mf env sigma c1 in
+ let var = type_judgment env sigma j in
+ let env1 = push_rel (name,None,var.utj_val) env in
+ let j' = execute mf env1 sigma c2 in
+ judge_of_abstraction env1 name var j'
+
+ | Prod (name,c1,c2) ->
+ let j = execute mf env sigma c1 in
+ let varj = type_judgment env sigma j in
+ let env1 = push_rel (name,None,varj.utj_val) env in
+ let j' = execute mf env1 sigma c2 in
+ let varj' = type_judgment env1 sigma j' in
+ judge_of_product env name varj varj'
+
+ | LetIn (name,c1,c2,c3) ->
+ let j1 = execute mf env sigma c1 in
+ let j2 = execute mf env sigma c2 in
+ let j2 = type_judgment env sigma j2 in
+ let _ = judge_of_cast env j1 j2 in
+ let env1 = push_rel (name,Some j1.uj_val,j2.utj_val) env in
+ let j3 = execute mf env1 sigma c3 in
+ judge_of_letin env name j1 j2 j3
+
+ | Cast (c,t) ->
+ let cj = execute mf env sigma c in
+ let tj = execute mf env sigma t in
+ let tj = type_judgment env sigma tj in
+ let j, _ = judge_of_cast env cj tj in
+ j
+
+and execute_recdef mf env sigma (names,lar,vdef) =
+ let larj = execute_array mf env sigma lar in
+ let lara = Array.map (assumption_of_judgment env sigma) larj in
+ let env1 = push_rec_types (names,lara,vdef) env in
+ let vdefj = execute_array mf env1 sigma vdef in
+ let vdefv = Array.map j_val vdefj in
+ let _ = type_fixpoint env1 names lara vdefj in
+ (names,lara,vdefv)
+
+and execute_array mf env sigma v =
+ let jl = execute_list mf env sigma (Array.to_list v) in
+ Array.of_list jl
+
+and execute_list mf env sigma = function
+ | [] ->
+ []
+ | c::r ->
+ let j = execute mf env sigma c in
+ let jr = execute_list mf env sigma r in
+ j::jr
+
+
+let safe_machine env sigma constr =
+ let mf = { fix = false; nocheck = false } in
+ execute mf env sigma constr
+
+let unsafe_machine env sigma constr =
+ let mf = { fix = false; nocheck = true } in
+ execute mf env sigma constr
+
+(* Type of a constr *)
+
+let type_of env sigma c =
+ let j = safe_machine env sigma c in
+ (* No normalization: it breaks Pattern! *)
+ (*nf_betaiota*) (body_of_type j.uj_type)
+
+(* The typed type of a judgment. *)
+
+let execute_type env sigma constr =
+ let j = execute { fix=false; nocheck=true } env sigma constr in
+ assumption_of_judgment env sigma j
+
+let execute_rec_type env sigma constr =
+ let j = execute { fix=false; nocheck=false } env sigma constr in
+ assumption_of_judgment env sigma j
+
diff --git a/pretyping/typing.mli b/pretyping/typing.mli
new file mode 100644
index 00000000..4ea74dcd
--- /dev/null
+++ b/pretyping/typing.mli
@@ -0,0 +1,27 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: typing.mli,v 1.7.14.1 2004/07/16 19:30:47 herbelin Exp $ i*)
+
+(*i*)
+open Term
+open Environ
+open Evd
+(*i*)
+
+(* This module provides the typing machine with existential variables
+ (but without universes). *)
+
+val unsafe_machine : env -> evar_map -> constr -> unsafe_judgment
+
+val type_of : env -> evar_map -> constr -> constr
+
+val execute_type : env -> evar_map -> constr -> types
+
+val execute_rec_type : env -> evar_map -> constr -> types
+