diff options
| author | herbelin | 1999-11-26 21:19:41 +0000 |
|---|---|---|
| committer | herbelin | 1999-11-26 21:19:41 +0000 |
| commit | 18a9bacd66660b23af059658116db7b812d6db06 (patch) | |
| tree | db12259da18e58325063d107e0e61045fec7ea7c /pretyping | |
| parent | 1a2dc1bb8b78b07ea7620b466138f43df6a05aaa (diff) | |
Modification pour faire compiler pretyping.ml qui maintenant compile
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@156 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'pretyping')
| -rw-r--r-- | pretyping/coercion.mli | 19 | ||||
| -rwxr-xr-x | pretyping/multcase.ml | 2332 | ||||
| -rw-r--r-- | pretyping/pretype_errors.ml | 5 | ||||
| -rw-r--r-- | pretyping/pretype_errors.mli | 7 | ||||
| -rw-r--r-- | pretyping/pretyping.ml | 241 | ||||
| -rw-r--r-- | pretyping/pretyping.mli | 57 |
6 files changed, 2571 insertions, 90 deletions
diff --git a/pretyping/coercion.mli b/pretyping/coercion.mli index 6cc815e49f..2eeafa15b0 100644 --- a/pretyping/coercion.mli +++ b/pretyping/coercion.mli @@ -1,4 +1,6 @@ +(* $:Id$ *) + open Evd open Term open Sign @@ -6,15 +8,18 @@ open Environ open Evarutil -val inh_app_fun : 'a evar_defs -> 'b -> unsafe_judgment -> unsafe_judgment -val inh_tosort_force : 'a evar_defs -> 'b -> unsafe_judgment -> unsafe_judgment -val inh_tosort : 'a evar_defs -> 'b -> unsafe_judgment -> unsafe_judgment -val inh_ass_of_j : 'a evar_defs -> var_context -> +val inh_app_fun : + unsafe_env -> 'a evar_defs -> unsafe_judgment -> unsafe_judgment +val inh_tosort_force : + unsafe_env -> 'a evar_defs -> unsafe_judgment -> unsafe_judgment +val inh_tosort : + unsafe_env -> 'a evar_defs -> unsafe_judgment -> unsafe_judgment +val inh_ass_of_j : unsafe_env -> 'a evar_defs -> unsafe_judgment -> typed_type -val inh_coerce_to : 'a evar_defs -> var_context -> +val inh_coerce_to : unsafe_env -> 'a evar_defs -> constr -> unsafe_judgment -> unsafe_judgment -val inh_cast_rel : 'a evar_defs -> var_context -> +val inh_cast_rel : unsafe_env -> 'a evar_defs -> unsafe_judgment -> unsafe_judgment -> unsafe_judgment -val inh_apply_rel_list : bool -> 'a evar_defs -> var_context -> +val inh_apply_rel_list : bool -> unsafe_env -> 'a evar_defs -> unsafe_judgment list -> unsafe_judgment -> 'b * ('c * constr option) -> unsafe_judgment diff --git a/pretyping/multcase.ml b/pretyping/multcase.ml new file mode 100755 index 0000000000..54eecf3b56 --- /dev/null +++ b/pretyping/multcase.ml @@ -0,0 +1,2332 @@ +(****************************************************************************) +(* The Calculus of Inductive Constructions *) +(* *) +(* Projet Coq *) +(* *) +(* INRIA LRI-CNRS ENS-CNRS *) +(* Rocquencourt Orsay Lyon *) +(* *) +(* Coq V6.3 *) +(* July 1st 1999 *) +(* *) +(****************************************************************************) +(* multcase.ml *) +(****************************************************************************) + +(* This file is linked to the system through trad.ml in order to be able + * to type during macro expansion. The functions here receive the closure + * of pretype and some other functions from trad.ml. + *) + +open Std;; +open More_util;; +open Himsg;; +open Pp;; +open Vectops;; +open Generic;; +open Term;; +open Termenv;; +open Reduction;; +open Typing;; +open Names;; +open Multcase_astterm;; +open Astterm;; +open Indrec;; +open Tradevar;; +open Rawterm;; + + +(* == General purpose functions == *) + +(* J'ai remplace strip_outer_cast par whd_castapp. A revoir. PAPAGENO 01/1999 +let whd_cast = strip_outer_cast;; +***********) + +let mtevd = Evd.mt_evd ();; + +let whd_cast = whd_castapp;; + +let starts_with_underscore id = + let s=string_of_id id in (String.get s 0)='_';; + + +let makelist n elem = + let rec makerec n = + if n=0 then [] + else elem::(makerec (n-1)) + in makerec n +;; + +let rec map_append_vect f v = + let length = Array.length v in + let rec map_rec i = + if i>=length then [] + else (f v.(i))@ map_rec (i+1) + + in map_rec 0 +;; + + +(* behaves as lam_and_popl but receives an environment instead of a + * dbenvironment + *) +let elam_and_popl n env body l = + let ENVIRON(sign,dbenv)=env in + let ndbenv,a,l = lam_and_popl n dbenv body l + in ENVIRON(sign,ndbenv),a,l +;; + + +(* behaves as lam_and_popl_named but receives an environment instead of a + * dbenvironment + *) +let elam_and_popl_named n env body l = + let ENVIRON(sign,dbenv)=env in + let ndbenv,a,l = lam_and_popl_named n dbenv body l + in ENVIRON(sign,ndbenv),a,l +;; + + +(* General functions on inductive types *) + +(* yields the number of indexes of the inductive type ty *) +let nb_localargs {nparams=nparams;arity=arity} = + (fst (decomp_prod mtevd arity)) - nparams +;; + +let ctxt_of_ids ids = + Array.of_list (List.map (function id -> VAR id) ids) + +let mutconstruct_of_constructor (((sp,i),j),args) = + mkMutConstruct sp i j (ctxt_of_ids args) +let mutind_of_constructor (((sp,i),_),args) = mkMutInd sp i (ctxt_of_ids args) +let mutind_of_ind (sp,i,args) = mkMutInd sp i args + +let ith_constructor i {mind=(sp, tyi, cl)} = mkMutConstruct sp tyi i cl +;; + +(* determines whether is a predicate or not *) +let is_predicate ind_data = (nb_localargs ind_data > 0);; + +(* === Closures imported from trad.ml to perform typing === *) + +type 'a trad_functions = + { pretype : trad_constraint -> environment -> rawconstr -> judgement; + isevars : 'a Evd.evar_map ref + };; + +let mssg_hd_is_not_constructor cstr ind = + let pi = pTERM (mutind_of_ind ind) in + let pc = pTERM (mutconstruct_of_constructor cstr) in + let pt = pTERM (mutind_of_constructor cstr) in + [< 'sTR "Expecting a constructor of type "; pi; 'bRK(1,1) ; + 'sTR " but found the constructor " ; pc; 'bRK(1,1) ; + 'sTR " of type "; pt >] +;; + +let mssg_tomatch_of_unexpected_type cstr ty = + let pi = pTERM ty in + let pc = pTERM (mutconstruct_of_constructor cstr) in + let pt = pTERM (mutind_of_constructor cstr) in + [< 'sTR "The term to match is of type "; pi; 'bRK(1,1) ; + 'sTR " but it is matched against the constructor " ; pc; 'bRK(1,1) ; + 'sTR " of type "; pt >] +;; + +let mssg_wrong_num_arg_in_constr cstr n = + let pc = pTERM (mutconstruct_of_constructor cstr) in + [<'sTR "The constructor "; pc; + 'sTR " expects " ; 'iNT n ; 'sTR " arguments. ">] +;; + + +(* The type of patterns. + * Makes pattern-matching safer than on a constr, and we can do a few + * checks we won't have to do afterwards. + *) + +type 'a lifted = int * 'a + +type lfconstr = constr lifted + +let lift_lfconstr n (s,c) = (s+n,c) + +(* For pretty-printing. We keep the aliases. The ouput is not a well typed + * term: in patterns, constructors are not applied to their args. + *) +(* +let rec pconstr_of_pat = function + PatVar (_,Name id) -> VAR id + | PatVar _,Anonymous -> VAR (id_of_string "_") + | PatCstr (_,c,args) -> applist(c, List.map pconstr_of_pat args) + | PatAs (_,id,p) -> DOPN(XTRA("AS",[]),[|VAR id; pconstr_of_pat p|]) +;; +*) + +(* Partial check on patterns *) +let rec check_pat_arity c = + match c with + PatCstr (loc, ((_,i),_ as c), args) -> + let ity = mutind_of_constructor c in + let nparams = mis_nparams (mind_specif_of_mind ity) in + let tyconstr = type_mconstruct mtevd i ity in + let nb_args_constr = (nb_prod tyconstr) - nparams in + if List.length args <> nb_args_constr + then errorlabstrm "check_pat_arity" + (mssg_wrong_num_arg_in_constr c nb_args_constr) + | PatAs (_,_,p) -> check_pat_arity p + | PatVar (_,_) -> () +;; + +(* renaming different occurrences of _ in pattern (before checking linearity!) + *) +(* +let rec rename_patt acc patt = + match patt with + PatVar x -> + if starts_with_underscore x + then let nid = next_ident_away x acc in (nid::acc, PatVar nid) + else (acc, patt) + | PatCstr(c,args) -> + let (nacc,nargs) = rename_lpatt acc args in + (nacc,PatCstr(c,nargs)) + | PatAs(id,p) -> + let (nacc,np) = rename_patt acc p in + (nacc,PatAs(id,np)) + +and rename_lpatt vl lp = + List.fold_right + (fun patt (acc,nlpatt) -> + let (nacc,np) = rename_patt acc patt in (nacc, np::nlpatt)) + lp + (vl,[]) +;; +*) + +(* Usage of this function should be avoided, because it requires that the + * params are infered. + *) +let rec constr_of_pat = function + PatVar (_,Name id) -> VAR id + | PatVar (_,Anonymous) -> invalid_arg "constr_of_pat" + | PatCstr(_,c,args) -> + let ity = mutind_of_constructor c in + let mispec = mind_specif_of_mind ity in + let nparams = mis_nparams mispec in + let c = mutconstruct_of_constructor c in + applist(c, makelist nparams mkExistential @ List.map constr_of_pat args) + | PatAs(_,id,p) -> constr_of_pat p +;; + + +(* == Error messages == *) + +let mssg_ill_typed_branch (innermsg) = + errorlabstrm "compile_multcase" + [<'sTR "Expansion strategy failed to build a well typed case expression."; + 'cUT; 'sTR "There is a branch that mistmatches the expected type."; 'fNL; + hOV 1 [<'sTR "The risen type error on the result of expansion was:"; + 'sPC; innermsg >] + >];; + +let mssg_wrong_predicate_arity env pred nondep_arity dep_arity= + let pp = pTERMINENV(env,pred) in + [<'sTR "The elimination predicate " ; pp; 'cUT; + 'sTR "should be of arity " ; 'iNT nondep_arity ; + 'sTR " (for non dependent case) or " ; + 'iNT dep_arity ; 'sTR " (for dependent case).">] +;; + + +let warning_needs_dep_elim() = + warning +"This pattern matching may need dependent elimination to be compiled. +I will try, but if fails try again giving dependent elimination predicate." +;; + +let mssg_needs_inversion x t env = + let px = pTERMINENV(env,x) in + let pt = pTERMINENV(env,t) in + [< 'sTR "Sorry, I need inversion to compile pattern matching of term "; + px ; 'sTR " of type: "; pt>] +;; + +let mssg_may_need_inversion () = + [< 'sTR "This pattern-matching is not exhaustive.">] +;; + +let mssg_mistmatch_type patt ity env = + let pi = pTERMINENV(env,ity) in + let pp = pTERMINENV(env,patt) in + [< 'sTR "Constructor pattern: "; pp; 'bRK(1,1); + 'sTR " cannot match values of type "; pi >] +;; + + +(* == Errors concerning mlcase == *) + +let mssg_mlcase_infer_failure c env = + let pc = pTERMINENV(env,c) in + (hOV 3 [<'sTR "Cannot infer type of expression :";'wS 1; pc>]) +;; + +let mssg_mlcase_not_inductive c env = + let pc = pTERMINENV(env,c) in + (hOV 3 [<'sTR "ML Case on a non inductive type :";'wS 1; pc>]) +;; + + +(* eta-expands the term t *) + +let rec eta_expand0 sigma n c t = + match whd_betadeltaiota sigma t with + DOP2(Prod,a,DLAM(na,b)) -> + DOP2(Lambda,a,DLAM(na,eta_expand0 sigma (n+1) c b)) + | _ -> applist (lift n c, rel_list 0 n) +;; + +let rec eta_expand sigma c t = + match whd_betadeltaiota sigma c, whd_betadeltaiota sigma t with + | (DOP2(Lambda,ta,DLAM(na,cb)), DOP2(Prod,_,DLAM(_,tb))) -> + DOP2(Lambda,ta,DLAM(na,eta_expand sigma cb tb)) + | (c, t) -> eta_expand0 sigma 0 c t +;; + +let eta_reduce_if_rel c = + match eta_reduce_head c with + Rel n -> Rel n + | _ -> c;; + +(* ===================================== *) +(* DATA STRUCTURES *) +(* ===================================== *) +let push a s = a::s;; +let push_lifted a s = (insert_lifted a)::s;; +let pop = function (a::s) -> (a,s) | _ -> error "pop";; +let empty = function [] -> true | _ -> false;; +let top = function (a::s) -> a | _ -> error "pop";; + +(* Check *) +type 'a check = {past:'a list; + future:'a list};; + + +let empty_ck: 'a check = {past=[]; future=[]};; + +let to_past {past=p;future=f} = + if not (empty f) + then let (a,r)=pop f in {past=push a p; future=r} + else error "move_left:right is empty" +;; + + +(* dependencies: terms on which the type of patterns depends + patterns: list of patterns to analyse + rhs: right hand side of equations + Current pattern to analyse is placed in the top of patterns.future +*) + +type rhs = + {private_ids:identifier list; + user_ids:identifier list; + subst:(identifier * constr) list; + rhs_lift:int; + it:rawconstr} + +type row = {dependencies : constr lifted list; + patterns : pattern check; + rhs : rhs};; + + +let row_current r = top r.patterns.future;; +let pop_row_current ck = {past= ck.past; future= snd (pop ck.future)};; + + +(*---------------------------------------------------------------* + * Code for expansion of Cases macros * + *---------------------------------------------------------------*) + + +(* == functions for replacing variables except in patterns == *) +(* (replace_var id t c) replaces for t all those occurrences of (VAR id) in c + * that are not in patterns. It lifts t across binders. + * The restriction is to avoid restoring parameters in patterns while treating + * rhs. + *) +(* PB: (replace_var_nolhs (VAR x) T <<Cases y of (C x) => x end>>) + * will return <<Cases y of (C x) => T end>>, which is wrong! + *) +(* +let replace_var_nolhs var t x = + let rec substrec n = function + (VAR(x) as c) -> if c=var then lift n t else c + | DOPN(XTRA("EQN",cl),v) -> DOPN(XTRA("EQN",cl),Array.concat + [[|substrec n v.(0)|]; tl_vect v]) + | DOPN(oper,cl) -> DOPN(oper,Array.map (substrec n) cl) + | DOPL(oper,cl) -> DOPL(oper,List.map (substrec n) cl) + | DOP1(oper,c) -> DOP1(oper,substrec n c) + | DOP2(oper,c1,c2) -> DOP2(oper,substrec n c1,substrec n c2) + | DLAM(na,c) -> DLAM(na,substrec (n+1) c) + | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (n+1)) v) + | x -> x in + if eq_constr var t then x + else substrec 0 x +;; +*) +(* Version sur les pseudo-termes... comprendre d'abord s'il y a encore +besoin d'absolutize... *) +let lift_rawconstr n = + let rec lift k = function + | RRef (loc,RRel i) as x -> if i>k then RRef(loc,RRel(i+n)) else x + | RApp (loc,f,args) -> RApp (loc,lift k f,List.map (lift k) args) + | RBinder (loc,bk,na,ty,c) -> RBinder (loc,bk,na,lift k ty, lift (k+1) c) + | RCases (loc,tyopt,tml,pl) -> + RCases (loc,lift_option k tyopt,List.map (lift k) tml, + List.map (lift_pattern k) pl) + | ROldCase (loc,b,tyopt,tm,bv) -> + ROldCase (loc,b,lift_option k tyopt,lift k tm,Array.map (lift k) bv) + | RRec (loc,fk,idl,tyl,bv) -> + let m = Array.length idl in + RRec (loc,fk,idl,Array.map (lift k) tyl, Array.map (lift (k+m)) bv) + | (RSort _ | RHole _ | RRef _ ) as x -> x + + and lift_pattern k = function (idl,p,c) -> (idl,p,lift k c) + + and lift_option k = function None -> None | Some p -> Some (lift k p) + + in lift 0 +;; +(* *) +let replace_var_nolhs var t = + let rec reprec k = function + | RRef (loc,Var id) as c -> if id=var then lift_rawconstr k t else c + | RApp (loc,f,args) -> RApp (loc,reprec k f,List.map (reprec k) args) + | RBinder (loc,bk,n,ty,c) -> RBinder (loc,bk,n,reprec k ty, reprec (k+1) c) + | RCases (loc,tyopt,tml,pl) -> + RCases (loc,reprec_option k tyopt,List.map (reprec k) tml, + List.map (reprec_pattern k) pl) + | ROldCase (loc,b,tyopt,tm,bv) -> + ROldCase (loc,b,reprec_option k tyopt, reprec k tm, + Array.map (reprec k) bv) + | RRec (loc,fk,idl,tyl,bv) -> + let m = Array.length idl in + RRec (loc,fk,idl,Array.map (reprec k) tyl, Array.map (reprec (k+m)) bv) + | (RSort _ | RHole _ | RRef _ ) as x -> x + + and reprec_pattern k = function (idl,p,c) -> (idl,p,reprec k c) + + and reprec_option k = function None -> None | Some p -> Some (reprec k p) + + in reprec 0 +;; + +let subst_in_subst id t (id2,c) = + (id2,replace_vars [(id,make_substituend t)] c) + +let replace_var_nolhs id t rhs = + if List.mem id rhs.private_ids then + {rhs with + subst = List.map (subst_in_subst id t) rhs.subst; + private_ids = except id rhs.private_ids} + else if List.mem id rhs.user_ids then + {rhs with + subst = (id,t)::List.map (subst_in_subst id t) rhs.subst; + user_ids = except id rhs.user_ids} + else anomaly "Found a pattern variables neither private nor user supplied" +;; + + + + + + +(* replaces occurrences of [(VAR id1)..(VAR idn)] respectively by t in c *) +let replace_lvar_nolhs lid t c = + List.fold_right (fun var c -> replace_var_nolhs var t c) lid c +;; + +let global_vars_rawconstr = + let rec global lid = function + | RRef (loc,Var id) -> id::lid + | RApp (loc,f,args) -> List.fold_left global (global lid f) args + | RBinder (loc,bk,na,ty,c) -> global (global lid ty) c + | RCases (loc,tyopt,tml,pl) -> + global_option (List.fold_left global + (List.fold_left global_pattern lid pl) tml) tyopt + | ROldCase (loc,b,tyopt,tm,bv) -> + global_option (global (it_vect global lid bv) tm) tyopt + | RRec (loc,fk,_,tyl,bv) -> + it_vect global (it_vect global lid tyl) bv + | (RSort _ | RHole _ | RRef _ ) -> [] + + and global_pattern lid = function (idl,p,c) -> global lid c + + and global_option lid = function None -> [] | Some p -> global lid p + + in global [] +;; + +let rec global_vars_rawconstr env rhs = + rhs.user_ids@(ids_of_sign (get_globals env)) + +(* ====================================================== *) +(* Functions to absolutize alias names of as-patterns in *) +(* a term *) +(* ====================================================== *) +let rec whd_as = function + PatAs(_,_,p) -> whd_as p + | x -> x +;; + +(* Rem: avant, lid étant dans l'autre sens, et replace_lvar_nolhs + utilise un fold_right. Comme je ne vois aucune dépendance entre des + différentes vars dans le terme value à substituer, l'ordre devrait + être indifférent [HH] *) + +let rec replace_alias and_hdname lid value rhs = function + PatVar (_,Name id) -> + let lid' = if and_hdname then id::lid else lid in + replace_lvar_nolhs lid' value rhs + | PatVar (_,Anonymous) -> replace_lvar_nolhs lid value rhs + | PatAs (_,id,p) as patt -> replace_alias and_hdname (id::lid) value rhs p + | _ -> anomalylabstrm "absolutize_alias" + [<'sTR "pattern should be a variable or an as-pattern">] +;; + +(* (expand_alias_and_hdname t rhs patt = + * if patt=(VAR id) then rhs[(VAR id) <- t] + * if patt = (p as id) then (expand p t rhs)[(VAR id)<-t] + *) +let absolutize_alias_and_hdname = replace_alias true [];; + +(* (absolutize_alias t rhs patt = + * if patt = (p as id) then (expand p t rhs)[(VAR id)<-t] else rhs + *) +let absolutize_alias = replace_alias false [];; + +let pop_and_prepend_future lpatt chk = + let (_,fut) = pop chk.future in {past=chk.past; future= lpatt @ fut} +;; + +type matrix = row list ;; + +(* info_flow allos to tag "tomatch-patterns" during expansion: + * INH means that tomatch-pattern is given by the user + * SYNT means that tomatch-pattern arises from destructuring a constructor + * (i.e. comes during top-down analysis of patterns) + * INH_FIRST is used ONLY during dependent-Cases compilation. it tags the + * first tomatch-pattern + *) +type info_flow = INH | SYNT | INH_FIRST;; + + + +(* If the case is non-dependent, the algorithm of compilation generates + the predicate P of the analysis using la 0eme definition. When + the case is dependent it should use the same strategy than rec. + For that terms to match are tagged with INH or SYNT so decide + if pred should be inherited to branches or synthetised. + While left to right analysis + of patterns the predicate is inherited, while top-down analysis of + patterns predicate is synthetised, by doing anonymous abstractions when + the non-dependent case is applied to an object of dependent type. +*) + +type tomatch = IsInd of constr * mutind | MayBeNotInd of constr * constr + +let to_mutind c sigma t = + try IsInd (c,try_mutind_of sigma t) + with Induc -> MayBeNotInd (c,t) + +let term_tomatch = function + IsInd (c,_) -> c + | MayBeNotInd (c,_) -> c;; + +type general_data = + {case_dep : bool; + pred : constr lifted; + deptm : constr lifted list; + tomatch : (tomatch * info_flow) list; + mat : matrix };; + +type compilation_state = environment * general_data * constr list + +let gd_current gd = top gd.tomatch;; +let pop_current gd = snd (pop gd.tomatch);; + +let replace_gd_current cur gd = +let tm = pop_current gd +in {case_dep = gd.case_dep; pred=gd.pred; deptm=gd.deptm; + tomatch = cur:: tm; mat = gd.mat} +;; + +let replace_gd_pred pred gd = + {case_dep = gd.case_dep; + pred = insert_lifted pred; + deptm = gd.deptm; + tomatch = gd.tomatch; + mat = gd.mat} +;; + + +let prepend_tomatch ltm gd = + {case_dep = gd.case_dep; pred=gd.pred; deptm=gd.deptm; + tomatch = ltm@ gd.tomatch; mat = gd.mat} +;; + +let pop_and_prepend_tomatch ltm gd = +let _,tm= pop gd.tomatch +in {case_dep= gd.case_dep; pred= gd.pred; deptm = gd.deptm; + tomatch = ltm@tm; + mat = gd.mat} +;; + + +(* ========================================== *) +(* Lifiting operations for general data *) +(* ========================================== *) + +(* == lifting db-indexes greater equal a base index in gd == *) +(* Ops. lifting indexes under b bindings (i.e. we lift only db-indexes + * that are >= b + *) + +(* lifts n the the indexes >= b of row *) +let lift_row n r = + {dependencies = List.map (lift_lfconstr n) r.dependencies; + patterns = r.patterns; (* No Rel in patterns *) + rhs = {r.rhs with rhs_lift = r.rhs.rhs_lift + n}} +;; + +let lift_ind_data n md = + {fullmind=lift n md.fullmind; + mind=md.mind; + nparams=md.nparams; + nconstr=md.nconstr; + params=List.map (lift n) md.params; + realargs=List.map (lift n) md.realargs; + arity=md.arity} +;; + +let lift_tomatch n = function + IsInd(c,ind_data) -> IsInd (lift n c, lift_ind_data n ind_data) + | MayBeNotInd (c,t) -> MayBeNotInd (lift n c,lift n t) +;; + +let lift_gd n {case_dep=b; pred=p; deptm=l; tomatch=tm; mat=m} = + {case_dep=b; + pred = lift_lfconstr n p; + deptm = List.map (lift_lfconstr n) l; + tomatch = List.map (fun (tm,i) -> (lift_tomatch n tm,i)) tm; + mat = List.map (lift_row n) m} +;; + +(* == Ops lifting all db-indexes == *) + +(* pushes (na,t) to dbenv (that is a stack of (name,constr) and lifts + * tomach's dependencies, tomatch, pred and rhs in matrix + *) + +let push_and_liftn_gd n vl (env, gd) = + (List.fold_right (Mach.push_rel mtevd) vl env, lift_gd n gd) +;; + +let push_and_lift_gd v = push_and_liftn_gd 1 [v] + +(* if t not (x1:A1)(x2:A2)....(xn:An)t' then (push_and_lift_gdn n t (env,gd,l) + * raises an error else it gives ([x1,A1 ; x2,A2 ; ... ; xn,An]@env,t',gd') + * where gd' is gd lifted n steps and l' is l lifted n steps + *) + +let get_n_prod n t = + let rec pushrec l = function + (0, t) -> (l,t) + | (n, DOP2(Prod,t,DLAM(na,b))) -> pushrec ((na,t)::l) (n-1, b) + | (n, DOP2(Cast,t,_)) -> pushrec l (n, t) + | (_, _) -> error "get_n_prod: Not enough products" + in pushrec [] (n,t) +;; + +let push_and_lift_gdn n t envgd = + let (vl,_) = get_n_prod n t in + let (nenv,ngd) = push_and_liftn_gd n vl envgd in + (nenv,ngd) +;; + +let push_env_and_lift_gdn n dbenv_base dbenv gd a = + let rec pushrec base gd dbenv n = + if n=0 then base,gd + else + try (match dbenv with + (na, t):: x -> + let ndbenv,ngd = pushrec base gd x (n-1) in + push_and_lift_gd (na,t) (ndbenv, ngd) + | _ -> assert false) + with UserError _ -> error "push_env_and_lift_gd" + in + let (nbase,ngd) = pushrec dbenv_base gd (get_rels dbenv) n in + (ngd,lift_lfconstr n a) +;; + +(* == Ops. pushing patterns to tomatch and lifting == *) + +(* if t=(x1:P1)..(xn:Pn)Q behaves as push_and_lift_gd but if gd.patterns=patt + * then the resutling gd'.patterns = (Rel n)..(Rel 1)patt + *) + +let push_lpatt_and_liftl n t info (env,gd,l) = + let rec pushrec tl = function + (0, t, envgd) -> (tl,t,envgd) + | (n, DOP2(Prod,t,DLAM(na,b)), envgd) + -> pushrec (t::tl) (n-1, b, push_and_lift_gd (na,t) envgd) + | (n, DOP2(Cast,t,_), envgd) -> pushrec tl (n, t, envgd) + | (_, _, _) -> error "push_lpatt_and_liftl" + in let tl,body,(nenv,ngd) = pushrec [] (n,t,(env,gd)) in + let ntomatch = + map_i + (fun i t -> (to_mutind (Rel i) mtevd (lift n t), info)) 1 tl + in body, (nenv, + {ngd with tomatch=rev_append ntomatch ngd.tomatch}, + List.map (lift n) l) +;; + +(* =============================================================== *) + + +(* if tomatch=[Rel i1;...Rel in] of type + [(Ti1 p1_bar u1_bar);..(Tij pj_bar uj_bar)] then it yields + [u1_bar;...uj_bar] +*) +let find_depargs env tomatch = + let dep = function + (IsInd(c,{realargs=args}),_) -> args + | (MayBeNotInd (_,_),_) -> [] + in map_append dep tomatch +;; + +(* == to treat ml-case == *) + +let make_pre_mlcase c lf = + (DOPN(XTRA("MLCASE",[Ast.str "REC"]), Array.append [|c|] lf)) +;; + +let dummy_mark = (DOP0(XTRA ("SYNTH", [])));; + +let rec hd_of_prodlam = function + DOP2(Prod,_,DLAM(_,c)) -> hd_of_prodlam c + | DOP2(Lambda,t,DLAM(_,c)) -> hd_of_prodlam c + | DOP2(Cast,c,t) -> hd_of_prodlam t + | c -> c +;; + +let is_for_mlcase p = (hd_of_prodlam p)=dummy_mark;; + +let has_synth t = dependent dummy_mark t;; + +let rec dummy_lam n t = + if n=0 then t + else (DOP2(Lambda,dummy_mark ,DLAM(Anonymous, dummy_lam (n-1) t))) +;; + + +(* == Special functions to deal with mlcase on objects of dependent types == *) + +(* ================================================= *) +(* Exceptions and functions for Error messages *) +(* ================================================= *) + + +(* (CCError "function", env, gd, mssg) whre mssg=(string,Pp.std_ppcmds) + * is the inner risen error_mssg + *) +exception CCError of + string * type_judgement assumptions * general_data * (rawconstr option) + * (string * Pp.std_ppcmds);; + +(* +let mssg_build_leaf errenv errgd errrhs innermssg = + let s,pstream= innermssg in + let rhs = + (match errrhs with (Some rhs) -> rhs | + None -> invalid_arg "mssg_build_leaf") in + let prhs = pTERMINENV(errenv,rhs) in + let ermsg = + [< 'sTR "The term "; prhs; 'sTR " is not well typed."; 'fNL; + hOV 1 [<'sTR "The risen type error on the result of expansion was:"; + 'sPC; pstream >] + >] +in (errorlabstrm s ermsg) +;; +*) +(* Cela ne se justifie plus d'avoir une encapsulation du message *) +let mssg_build_leaf errenv errgd errrhs innermssg = + let s,pstream= innermssg in + errorlabstrm s [<'sTR "Error in Cases:"; 'sPC; pstream >] + +(* == functions for syntactic correctness test of patterns == *) + + +let patt_are_var = + List.for_all + (fun r -> match (whd_as (row_current r)) with + PatVar _ -> true + |_ -> false) +;; + +let check_pattern ity row = + let rec check_rec = function + PatVar (_,id) -> () + | PatCstr (loc,c,args) -> + if mutind_of_ind ity <> mutind_of_constructor c then + Ast.user_err_loc + (loc,"check_pattern",(mssg_hd_is_not_constructor c ity)) + | PatAs(_,_,p') -> check_rec p' + + in check_rec (row_current row) + +let check_patt_are_correct ity mat = List.iter (check_pattern ity) mat + +(*The only variables that patterns can share with the environment are + parameters of inducive definitions!. Thus patterns should also be + lifted when pushing inthe context. *) + + +(* == functions to deal with names in contexts == *) + +(* If cur=(Rel j) then + * if env = ENVIRON(sign,[na_h:Th]...[na_j:Tj]...[na_1:T1]) + * then it yields ENVIRON(sign,[na_h:Th]...[Name id:Tj]...[na_1:T1]) + *) +let change_name_rel env current id= + match current with + (Rel j) -> + if starts_with_underscore id + then env + else let ENVIRON(sign,db) = env in + ( match chop_list (j-1) db with + db1,((_,ty)::db2) -> (ENVIRON(sign,db1@(Name id,ty)::db2)) + | _ -> assert false) + | _ -> env +;; + + +(* == Function dealing with constraints in compilation of dep case == *) + +let xtra_tm = DOP0(XTRA("TMPATT",[]));; +let is_xtra_tm tm = match tm with DOP0(XTRA("TMPATT",[])) -> true |_ -> false;; + +(* represents the constraint cur=ci *) +let build_constraint cur ci = DOP2(XTRA("CONSTRAINT",[]),cur,ci);; + +let top_constraint gd = + match (extract_lifted gd.pred) with + DOP2(Prod,(DOP2(XTRA("CONSTRAINT",[]),cur,ci)),_) -> true + | _ -> false +;; + +let destruct_constraint gd = + match (extract_lifted gd.pred) with + DOP2(Prod,(DOP2(XTRA("CONSTRAINT",[]),cur,ci)),bd) -> cur,ci,(lift (-1) bd) + | _ -> anomalylabstrm "destruct_constraint" [<>] +;; + +let rec whd_constraint = function + DOP2(Prod,(DOP2(XTRA("CONSTRAINT",[]),_,_)),(DLAM(_,bd))) + -> whd_constraint (lift (-1) bd) + | DOP2(Lambda,(DOP2(XTRA("CONSTRAINT",[]),_,_)),(DLAM(_,bd))) + -> whd_constraint (lift (-1) bd) + | VAR(x) -> (VAR x) + | DOPN(oper,cl) -> DOPN(oper,Array.map whd_constraint cl) + | DOPL(oper,cl) -> DOPL(oper,List.map whd_constraint cl) + | DOP1(oper,c) -> DOP1(oper,whd_constraint c) + | DOP2(oper,c1,c2) -> DOP2(oper,whd_constraint c1,whd_constraint c2) + | DLAM(na,c) -> DLAM(na,whd_constraint c) + | DLAMV(na,v) -> DLAMV(na,Array.map whd_constraint v) + | x -> x +;; + +(* if next_pred = [d_bar:D_bar][h:(I~d_bar)]Q + * and bty = (y_bar:S_bar)(I~dep_ci) + * and ci_params = (ci p_bar) + * then it builds the next predicate containing the constraints in the correct + * environment: + * (y_bar:S_bar) + * (XTRA cur=(ci_param y_bar))->(next_pred dep_ci (ci_param dep_ci)) + *) + +(* PRE: gd.pred is a product correspondent to dependent elimination preidcate + * productized (i.e. (d_bar:D_bar)(y:(I d_bar))Q ) + * It returns a product of the form + * (s_bar:S_bar)Constraint->(whd_beta ([d_bar:D_bar][y:(I d_bar)]Q dep_ci ci)) + * if info=INH then any constraints are generated + *) +let insert_constraint next_env gd brty ((cur,info), ci_param) = + let k = nb_prod brty in + let dbenv0,body = decompose_prod_n k brty in + let cur0 = lift k cur in + let cip0 = lift k ci_param in + let npred0 = lift k (extract_lifted gd.pred) in + let dep_ci = args_app body in + let cip1 = applist (cip0,(rel_list 0 k)) in + + let npred1 = to_lambda (Array.length dep_ci) npred0 in + + let ndbenv,bodypred,nk = + if Array.length dep_ci=1 (* type of cur is non-dependent *) then + dbenv0, appvect (npred1, dep_ci),k + else + let app_pred = appvect (npred1, dep_ci) in + if info = SYNT then + let c = build_constraint cur0 cip1 in + (Anonymous,c)::dbenv0, (lift 1 app_pred), (k+1) + + else dbenv0,app_pred,k (* we avoid generating the constraint*) in + + (* we productize the constraint if some has been generated *) + prodn nk ndbenv (whd_beta bodypred) +;; + + +(********************************) +(* == compilation functions == *) +(********************************) + +(* nbargs_iconstr is the number of arguments of the constructor i that are not + * parameters. Current is the current value to substitute "as" binders in + * as-patterns + * About Expansion of as patterns: + * we absolutize alias names (x1..xn) in pattern in rhs by + * rhs [x1..xn <- gd.current] if the type of current is not dep. + * rhs [x1..xn <- (ci params lid)] otherwise + * (in first case we share in second we rebuild the term) + * Note: in the case of (VAR id) we use sharing whenver the type is non-dep + * or we reconstruct the term when its dependent. + * depcase tells if the current Case to compile is dependent or not (this is + * because during dependent compilation terms are always reconstructed and not + * shared) + * TODO: find a better criterion, or let the user choose... + *) +let submat depcase sigma env i ind_data params current mat = + let ity = mutind_of_ind ind_data.mind in + let k = List.length params in + let ci = ith_constructor i ind_data in + let nbargs_iconstr = nb_prod (type_mconstruct sigma i ity) - k in + + let expand_row r = + let build_new_row subpatts vars = + let lid = global_vars_rawconstr env r.rhs in + let new_ids = get_new_ids nbargs_iconstr (id_of_string "t") lid in + let lpatt,largs = + match subpatts with + | None -> + List.map (fun id -> PatVar (Ast.dummy_loc,Name id)) new_ids, + List.map (fun id -> VAR id) new_ids + | Some patts -> + List.map2 + (fun id pat -> PatAs (Ast.dummy_loc,id,pat)) new_ids patts, + List.map constr_of_pat patts in + let value = + if (is_predicate ind_data) or depcase + then applist (ci, params@largs) + else current in + { dependencies=r.dependencies; + patterns = pop_and_prepend_future lpatt r.patterns; + rhs = replace_lvar_nolhs vars value r.rhs } in + + (* C'est idiot de permettre plusieurs alias pour un même motif *) + let rec expandrec envopt aliasvar = function + | PatVar (_,name) -> + let vars = match name with Name id -> id ::aliasvar |_ -> aliasvar in + (envopt, [build_new_row None vars]) + | PatCstr(_,c,largs) when mutconstruct_of_constructor c = ci -> + (* Avant: il y aurait eu un problème si un des largs contenait + un "_". Un problème aussi pour inférer les params des + constructeurs sous-jacents, car on n'avait pas accès ici + aux types des sous-patterns. Ai donc remplacé le + "applist(c, params @ (List.map constr_of_pat largs))" par + un "applist (ci, params@(List.map (fun id -> VAR id) new_ids))" + comme dans le cas PatVar, mais en créant des alias pour les + sous-patterns. Au passage, ça uniformise le traitement maintenant + fait par "build_new_row" *) + (envopt,[build_new_row (Some largs) aliasvar]) + | PatCstr _ -> (None,[]) + | PatAs(_,id1,patt) -> + let nenvopt = match envopt with + | None -> Some (change_name_rel env current id1) + | Some _ -> envopt in + expandrec nenvopt (id1::aliasvar) patt in + + expandrec None [] (row_current r) in + + let lenv,llrows = List.split (List.map expand_row mat) in + let lrows = List.concat llrows in + let lsome= filter (fun op -> op <> None) lenv in + let rnenv = + if lsome = [] then env + else outSOME (List.hd lsome) + in rnenv, lrows +;; + + +type status = + | Match_Current of (constr * mutind * info_flow) (* "(", ")" needed... *) + | Any_Tomatch | All_Variables + | Any_Tomatch_Dep | All_Variables_Dep | Solve_Constraint ;; + +let not_of_empty_type = function + | IsInd (c,{nconstr=nconstr}),_ -> nconstr <> 0 + | MayBeNotInd (_,t),_ -> true + (* Ici, on pourrait tester si t=?n et si oui unifier avec False ?? *) +;; + +let gdstatus env gd = + if top_constraint gd then Solve_Constraint + else + match gd.tomatch with + [] -> if gd.case_dep then Any_Tomatch_Dep else Any_Tomatch + | (cj,info)::tl_tm -> + if gd.mat=[] then + if (List.for_all not_of_empty_type gd.tomatch) + then errorlabstrm "gdstatus" + [< 'sTR "One should match a term in an empty inductive type"; 'fNL; + 'sTR "to get an empty list of pattern" >] + else (* to treat empty types *) + match cj with + IsInd (current,ind_data) -> Match_Current (current,ind_data,info) + | MayBeNotInd (current,t) -> + if gd.case_dep then All_Variables_Dep else All_Variables + else + if (patt_are_var gd.mat) + then if gd.case_dep then All_Variables_Dep else All_Variables + else + match cj with + IsInd (current,ind_data) -> + if is_xtra_tm current then Match_Current (current,ind_data,info) + else + (check_patt_are_correct ind_data.mind gd.mat; + Match_Current (current,ind_data,info)) + | MayBeNotInd (current,t) -> + errorlabstrm "gdstatus" (error_case_not_inductive CCI env current t) +;; + + +(* If S is the type of x and I that of y, then + * solve_dep (x,S)(y,I) = + * if S=(I u1..uj..un) and T=(I w1..wj..wn) where I has j parameters then + * u1=w1 &...& uj=wj & (solve u_j+1 w_j+1)& ..& (solve u_j+n w_j+n) + * else if S=(Rel i) and T=(Rel j) + * else fail! + * Note: this succeds only if uj+1...ur are all variables, otherwise + * inversion is needed. + * WARNING!: here we compare using whd_cast is this enough or should we + * erase all cast before comparing?? + *) +let rec solve_dep sigma env (x,t) (y,s) = + let rec solve_args = function + [],[] -> [] + | (e1::l1), (e2::l2) -> + let e = whd_cast e1 in + (match e with + (Rel i) -> ((Rel i), e2)::(solve_args (l1,l2)) + | _ -> + if e1= whd_cast e2 then (solve_args (l1,l2)) + else errorlabstrm "solve_dep" (mssg_needs_inversion x t env)) + | _ -> anomaly "solve_dep" in + try + let (ityt,argst)= find_mrectype sigma t + and (itys,argss)= find_mrectype sigma (hd_of_prod s) in + if whd_cast ityt= whd_cast itys & (List.length argst = List.length argss) + then + let nparams = mind_nparams ityt in + let (paramt,largst) = chop_list nparams argst + and (params,largss) = chop_list nparams argss in + if for_all2 eq_constr paramt params + then solve_args (largst,largss) + else anomalylabstrm "solve_dep" + [<'sTR "mistake in the code building the branch!!" >] + else anomalylabstrm "solve_dep" + [<'sTR "mistake in the code building the branch (pb:parameters)!">] + with Induc -> anomalylabstrm "solve_dep" + [<'sTR "mistake in the code building the branch (pb: constructor)!">] +;; + +let apply_subst subst dep = + let rec subst_term subst c = + match subst with + [] -> c + | (Rel i, t)::s -> + if dependent (Rel i) c then + if i = 1 then subst1 t c + else + let lsubstituend = + (List.rev (Array.to_list (rel_vect 0 (i-1))))@[t] + in subst_term s (substl lsubstituend c) + else subst_term s c + | _ -> assert false in + let extr_subst_ins c = insert_lifted (subst_term subst (extract_lifted c)) + in List.map extr_subst_ins dep +;; + + +let solve_dependencies sigma env gd (current,ci)= + if gd.deptm = [] then gd.deptm + else + let (curv,curt) = destCast current in + let (civ,cit) = destCast current in + try + let subst= solve_dep sigma env (curv,curt) (civ,cit) + in apply_subst subst gd.deptm + with UserError(a,b)-> errorlabstrm "solve_dependencies" b +;; + + +let rec substitute_dependencies c = function + [], [] -> c + | (t::x), (var::y) -> + (match (extract_lifted var) with + (VAR id) as v -> + substitute_dependencies + (replace_vars [(id,make_substituend (extract_lifted t))] c) + (x,y) + | _ -> anomalylabstrm "substitute_dependencies" [<>] ) + | _,_ -> anomalylabstrm "substitute_dependencies" + [< 'sTR "Dep. tomatch mistmatch dependencies of patterns" >] +;; + + +(* depends .. env cur tm = true if the the type of some element of tm + * depends on cur and false otherwise + *) +(* I think that cur<>(Rel n) only during the first application of cc + * because later constructors in gd.tomatch are applied to variables + *) +let depends env cur tm = + let ENVIRON(sign,dbenv) = env in + match cur with + (Rel n) -> + let (gamma2,_)= chop_list (n-1) dbenv in + let _,abs,_ = lam_and_popl (n-1) gamma2 mkImplicit [] + in dependent (Rel 1) abs + | _ -> false +;; + + +let lift_ctxt k env = + let ENVIRON(sign,dbenv) = env in + let delta,_ = decompose_prod (lift k (prod_it mkImplicit dbenv)) in + ENVIRON(sign,delta) +;; + + +let split_ctxt j (ENVIRON(sign,db)) = + let db1,db2= chop_list j db in + (ENVIRON(sign,db1)), (ENVIRON(sign,db2)) +;; + +let prepend_db_ctxt (ENVIRON(sign1,db1)) (ENVIRON(sign2,db2)) = + ENVIRON(sign1, db1@db2) +;; + + + +(* substitute_ctxt ci ENVIRON(sign, ([n1:U1]..[nj:Uj]))i = + * substitutes ci by (Rel 1) in U1...Uj + *) +let subst1_ctxt ci env = + let ENVIRON(sign,dbenv) = env in + let delta,_ = decompose_prod (subst1 ci (prod_it mkImplicit dbenv)) in + ENVIRON(sign,delta) +;; + +(* yields env if current pattern of first row is not a dummy var, + * otherwise it undumize its identifier and renames the variable cur + * in context with the name of the current of the + * first row. + *) +let rename_cur_ctxt env cur gd = + if gd.mat =[] then env + else + let r = List.hd gd.mat in + let current = row_current r in + match current with + PatVar (_,Name id) when not (starts_with_underscore id) -> + change_name_rel env cur id + | _ -> env +;; + +(* supposes that if |env|=n then the prefix of branch_env coincides with env + * except for the name of db variables + *) +let common_prefix_ctxt env branch_env = + let (ENVIRON(sign,db))=env in + let (ENVIRON(_,branch_db)) = branch_env in + let j = List.length db in + let rndb,_= chop_list j (List.rev branch_db) + in (ENVIRON(sign, List.rev rndb)) +;; + +let nf_ise_dependent sigma c t = dependent c (nf_ise1 sigma t) + +let tm_depends current sigma ltm = + let rec dep_rec = function + [] -> false + | (IsInd(tm,{params=params;realargs=args}),_)::ltm -> + List.exists (nf_ise_dependent sigma current) params + or List.exists (nf_ise_dependent sigma current) args + or (dep_rec ltm) + | (MayBeNotInd (tm,t),_)::ltm -> + nf_ise_dependent sigma current t or (dep_rec ltm) + in dep_rec ltm +;; + + + +(* substitutes the current of the row by t in rhs. If the current of the row + * is an as-pattern, (p AS id) then it expands recursively al as in such + * patern by by (expand rhs p)[id<- t] + *) +(* t is the current tomatch (used for expanding as-patterns) *) +let subst_current value r = + let cur = row_current r in + let nrhs = absolutize_alias_and_hdname value r.rhs cur + in {dependencies = r.dependencies; + patterns = pop_row_current r.patterns; + rhs = nrhs} +;; + +(* t is the current tomatch (used for expanding as-patterns) *) +let shift_current_to_dep r = + let curpatt = row_current r in + let value = constr_of_pat (whd_as curpatt) in + {dependencies = push (insert_lifted value) r.dependencies; + patterns = pop_row_current r.patterns; + rhs = absolutize_alias value r.rhs curpatt} +;; + + +(* ========================================================================= + * the following functions determine the context of dependencies of a + * a vector of terms. They are useful to build abstractions wrt to dependencies + * =========================================================================*) +(* the type of c is (T p1..pn u1..um) (s.t. p1..pn are parameters of T + * and T:(x1:P1)...(xn:Pn)(y1:B1)..(ym:Bm)s) then + * [push_params env (c,(p1..pn,u1..um),_,_,_)] = + * (env@[B1;..;Bm;(T (lift m p1)..(lift m pn) (Rel m)..(Rel 1))], + * [u1;..um; c]) + * in order to build later [y1:B1]..[ym:Bm](T p1'..pm' y1..ym) + * (where pi' = lift m pi) + *) + +let push_params sigma env (c,ind_data,_) = + let {mind=ity;params=params; + realargs=args;nparams=nparams;arity=arity}= ind_data in + let lam_arity = to_lambda nparams arity in + let arity0 = whd_beta (applist (lam_arity, params)) in + let env0,s = splay_prod mtevd (* to castify here *) arity0 in + let env0' = List.map (fun (na,t) -> (na,make_type t (Mach.sort_of sigma env t))) env0 in + let m = nb_prod arity0 in + let params0 = List.map (lift m) params in + let args0 = rel_list 0 m in + let t = make_type (applist (mutind_of_ind ity, params0@args0)) (destSort s) in + let env1 = (Anonymous,t)::env0' in + let dbenv0 = + List.map (fun (na,t) -> Environ.named_hd (body_of_type t) na,t) env1 in + let nind_data = {ind_data with params=params0;realargs=args0} + in (List.fold_right add_rel dbenv0 env, nind_data, args@[c]);; + + +(* the type of current is (T p1..pn u1..um) (s.t. p1..pn are parameters of T + * and T:(x1:P1)...(xn:Pn)(y1:B1)..(ym:Bm)s) then + * (tyenv_of_term tj) = [B1;..;Bm] + * in order to build later [y1:B1]..[ym:Bm]someterm + *) + +let abstract_arity res = function + IsInd (current,{params=params;nparams=nparams;arity=arity}) -> + let lam_arity = to_lambda nparams arity in + let arity0 = whd_beta (applist (lam_arity, params)) in + let env0,_ = splay_prod mtevd arity0 in + let k = List.length env0 in + k, lamn k env0 (lift k res) + | MayBeNotInd (_,_) -> 0,res +;; + + +(* =============================================== *) +(* for mlcase *) +(* =============================================== *) +(* +let rec abst = function + [] -> dummy_mark + | (tj::ltm) -> + let res = abst ltm in + let envty = tyenv_of_term tj in + let _,nres,_ = lam_and_popl (List.length envty) envty res [] + in nres + +in abst ltmj +;; +*) + +(* if ltmj=[j1;...jn] then this builds the abstraction + * [d1_bar:D1_bar] ...[dn_bar:Dn_bar](lift m pred) + * where di_bar are the dependencies of the type ji._TYPE and m is the sum + * of the lengths of d1_bar ... d1_n. + * The abstractions are not binding, because the predicate is properly lift + *) +let abstract_pred_lterms (pred,ltm) = + let rec abst = function + [] -> pred + | (tj::ltm) -> snd (abstract_arity (abst ltm) tj) + in abst ltm;; + +let info_abstract_pred_lterms (pred,ltm) = + let rec abst linfo = function + [] -> linfo,pred + | (tj::ltm) -> + let linfo,res = abst linfo ltm in + let k,nres = abstract_arity res tj in + let info = if k=0 then SYNT else INH + in (info::linfo),nres + in abst [] ltm;; + + +(* if the type of cur is : (I p_bar d_bar) where d_bar are d_bar are + * dependencies, then this function builds (pred d_bar) + * Precondition: pred has at least the same number of abstractions as d_bars + * length + *) +let apply_to_dep env pred = function + IsInd (c,ind_data) -> + let {realargs=args} = ind_data in + let k = nb_localargs ind_data in + if k=0 then pred + else + let tyargs = args@[c] in + let (ldep,_) = chop_list k tyargs + in whd_beta (applist (pred, ldep)) + | MayBeNotInd (c,t) -> pred +;; + +(* if dummy_pred = [x1:Implicit]..[xk:Implicit]...[xk+j:Implicit]P + * and ipred = [y1:T1]..[yk:Tk]T + * the result is [y1:T1]..[yk:Tk][xk+1:Implicit]...[xk+j:Implicit](lift j T) + + *** CADUC ? *** +let replace_dummy_abstractions dummy_pred ipred = + let k = nb_lam ipred in + let j = (nb_lam dummy_pred) - k in + let (env,body) = decompose_lam ipred in + let (_,ndpred,_) = push_and_liftl k [] dummy_pred [] in + let dummy_env = decompose_lam ndpred in + lam_it env (lam_it dummy_env (lift j body));; + *) + +(* == == *) + + + +(* analogue strategy as Christine's MLCASE *) +let find_implicit_pred sigma ith_branch_builder env (current,ind_data,_) = + let {fullmind=ct;nconstr=nconstr} = ind_data in + let isrec = false in + let rec findtype i = + if i > nconstr then + errorlabstrm "find_implicit_pred" + (mssg_mlcase_infer_failure (Rel 80) env) + else + try + (let expti = Indrec.branch_scheme sigma isrec i ct in + let _,bri= ith_branch_builder i in + let fi = bri._TYPE in + let efit = nf_ise1 sigma fi in + let pred = + pred_case_ml_onebranch env sigma isrec + (current,ct) (i,bri._VAL,efit) in + if has_ise pred or (has_synth pred) then error"isevar" else pred) + with UserError _ -> findtype (i+1) in + try findtype 1 + with Induc -> + error "find_implicit_pred" (mssg_mlcase_not_inductive (Rel 80) env) +;; + +(* =============================================== *) +(* Strategies for building elimination predicates *) +(* =============================================== *) +(* we build new predicate p for elimination + * by 0-splitting (we use inheritance or synthesis) + *) +let build_nondep_predicate env (current,ind_data,_) gd = + let _,tl_tm = pop gd.tomatch in + let n = nb_localargs ind_data in + +(* gd.pred has the form [deptm_1]..[deptm_r]P (as given by the user, this is + * an invariant of the algorithm) + * then p = [deptm_1] ([demptm_2]...[deptm_r]P val_deptm_2...val_dpetm_r) + * next_pred = [deptm_1]..[deptm_r]P + *) + if not gd.case_dep then +(* this computations is done now in build_nondep_branch + let abs = to_lambda nparams arityind in + let narity = whd_beta (applist (abs, params)) in + let next_pred = if info=SYNT then lambda_ize n narity (extract_lifted gd.pred) else extract_lifted gd.pred in +*) + let next_pred = extract_lifted gd.pred in + let (env0,pred0,_) = push_lam_and_liftl n [] next_pred [] in + let depargs= List.map (lift n) (find_depargs env tl_tm) in + let p = + if depargs=[] (*or n=0*) + then lamn n env0 pred0 + else lamn n env0 (whd_beta (applist (pred0,depargs))) + in (p,next_pred) + else + let pp = pTERMINENV(env, (extract_lifted gd.pred)) in + errorlabstrm "build_nondep_predicate" + [<'sTR "Predicate "; pp; + 'sTR " is not correct for non-dependent elimination.">] +;; + + +(* TODO: Display in the message the nested dependent pattern found *) +let mssg_nested_dep_patt env mat = +[< 'sTR "Compilation of Dependent Cases fails when there are";'cUT; + 'sTR "nested patterns (in constructor form) of dependent types."; 'cUT; + 'sTR "Try to transform your expression in a sequence of Dependent Cases"; + 'cUT ; 'sTR "with simple patterns.">] +;; + +(* +(* ity is closed *) (* devrait être déplacé en tête *) +let rec to_lambda_pred isevars ind_data n env prod = + if n=0 then prod + else match prod with + (DOP2(Prod,ty,DLAM(na,bd))) -> + mkLambda na ty + (to_lambda_pred isevars ind_data (n-1) +(* (Mach.push_rel !isevars (na,ty) env) bd)*) + (add_rel (na,outcast_type ty) env) bd) + | DOP2(Cast,c,_) -> to_lambda_pred isevars ind_data n env c + | _ -> error "to_lambda_unif" +;; +*) + +let build_dep_predicate isevars env (current,ind_data,info) gd = + if gd.case_dep then + let n = nb_localargs ind_data in + + if n=0 then (* the predicate is already dependent *) + let npred = + to_lambda 1 (extract_lifted gd.pred) + in npred,npred + else + if info=SYNT then + errorlabstrm "build_dep_predicate" (mssg_nested_dep_patt env gd.mat) + else + let npred = + to_lambda (n+1) (extract_lifted gd.pred) + in npred,npred + + else anomalylabstrm "build_dep_predicate" + [<'sTR "build_dep_predicate was called with gd.case_dep=false ">] +;; + +(* =================================== *) +(* Principal functions *) +(* =================================== *) + +let my_norec_branch_scheme sigma i mind = + let typc = type_inst_construct sigma i mind in + let rec crec typc = + match whd_betadeltaiota sigma typc with + DOP2(Prod,c,DLAM(name,t)) -> DOP2(Prod,c,DLAM(name,crec t)) + | (DOPN(AppL,v)) -> appvect (mkExistential, tl_vect v) + | _ -> mkExistential + in crec typc +;; + +let find_type_case_branches sigma env (current,ind_data,_) p = + let {fullmind=ct;mind=ity;params=params;realargs=args} = ind_data in + if not (is_for_mlcase p) then + + (* En attendant mieux ... *) + let pt = Mach.newtype_of sigma env p in + + let evalpt = nf_ise1 sigma pt in + let (_,bty,_)= type_case_branches env sigma ct evalpt p current + in bty + else + let build_branch i = my_norec_branch_scheme sigma i ct in + let lbr = List.map build_branch (interval 1 ind_data.nconstr) + in Array.of_list lbr +;; + +(* if ityparam :(d_bar:D_bar)s + * then we abstract the dependencies and the object building the non-binding + * abstraction [d_bar:D_bar][_:(I param d_bar)]body_br + *) + +(**************************************************************************) + +(* returns env,gd',args' where: + * if ltmj= e1...en then + * we prepend (e1,INH_FIRST)(e2:INH)..(en,INH) to gd.tomatch (gd') and + * if not gd.case_dep then env'=env and args'=[] + *) +let push_tomatch env gd ltm = + if not gd.case_dep then + env, prepend_tomatch (List.map (fun tm -> (tm,INH)) ltm) gd,[] + else + let rec push_rec gd args = function + [] -> (gd,args) + | (IsInd (c,ind_data) as tm)::l -> + let {realargs=args} = ind_data in + let tyargs = args@[c] in + let ngd,resargs = push_rec gd args l in + (prepend_tomatch [(tm,INH)] ngd, (tyargs@resargs)) + | (MayBeNotInd _)::l -> + errorlabstrm "push_tomatch" + [< 'sTR "Cases on terms of non inductive type is incompatible"; + 'fNL; 'sTR "with dependent case analysis" >] + in + let ngd,nargs = push_rec gd [] (List.tl ltm) in + let fst_tm = (List.hd ltm) ,INH_FIRST in + (env, prepend_tomatch [fst_tm] ngd, nargs) +;; + +(* ---------------------------------------------------------*) + + + + +type dependency_option = DEP | NONDEP;; + +(* if ityparam :(d_bar:D_bar)s + * then we abstract the dependencies and the object building the non-binding + * abstraction [d_bar:D_bar]body_br + *) +let abstract_dep_generalized_args ind_data env brj = + let {mind=ity;params=params;nparams=nparams;arity=arity}=ind_data in + let lam_arity = to_lambda nparams arity in + let arity0 = whd_beta (applist (lam_arity, params)) in + let m = nb_localargs ind_data in + let params0 = List.map (lift m) params in + let nity = applist (mutind_of_ind ity, params0@(rel_list 0 m)) in + let arityenv,_ = splay_prod mtevd arity0 in + {_VAL = + lamn m arityenv (Environ.lambda_name (Anonymous,nity,lift (m+1) brj._VAL)); + _TYPE = + prodn m arityenv (Environ.prod_name (Anonymous,nity,lift (m+1) brj._TYPE)); + _KIND = brj._KIND} +;; + + +(* *) +let check_if_may_need_dep_elim sigma current gd = + let _,tl_tm= pop gd.tomatch in + if (isRel current) & (tm_depends current sigma tl_tm) + then warning_needs_dep_elim();; + +let rec cc trad env gd = + match (gdstatus env gd) with + Match_Current (current,ind_data,info as cji) -> + if not gd.case_dep then + (check_if_may_need_dep_elim !(trad.isevars) current gd; + match_current trad env cji gd) + else + match_current_dep trad env cji gd + | All_Variables -> substitute_rhs trad env gd + | Any_Tomatch -> build_leaf trad env gd + + (* for compiling dependent elimination *) + | All_Variables_Dep -> substitute_rhs_dep trad env gd + | Any_Tomatch_Dep -> build_leaf_dep trad env gd + | Solve_Constraint -> solve_constraint trad env gd + + +and solve_constraint trad env gd = + let cur,ci,npred= destruct_constraint gd in + let ngd = {case_dep = gd.case_dep; + pred = insert_lifted npred; + deptm = solve_dependencies !(trad.isevars) env gd (cur,ci); + tomatch = gd.tomatch; + mat = gd.mat} + in cc trad env ngd + + +and build_dep_branch trad env gd bty (current,ind_data,info) i = + let sigma = !(trad.isevars) in + let {mind=ity;params=params;realargs=args;nparams=nparams} = ind_data in + let n = (List.length args)+1 in + let _,ty = decomp_n_prod sigma nparams (type_mconstruct sigma i (mutind_of_ind ity)) in + let l,_ = splay_prod sigma ty in + let lpatt = List.map (fun (na,ty) -> (to_mutind xtra_tm sigma ty,SYNT)) l in + let ngd = pop_and_prepend_tomatch lpatt gd in + let ci_param = applist (ith_constructor i ind_data, params) in + + let rnnext_env0,next_mat = submat ngd.case_dep sigma env i + ind_data params current ngd.mat in + let next_predicate = insert_constraint env ngd bty.(i-1) + ((current,info),ci_param) in + let next_gd = {ngd with + pred = insert_lifted next_predicate; + mat = next_mat} in + let brenv,body_br = cc trad rnnext_env0 next_gd in + let branch = + if empty next_gd.tomatch + then body_br (* all the generalisations done in the elimination predicate + * have been consumed *) + else let (_,nextinfo),_ = pop next_gd.tomatch in + if nextinfo=SYNT then body_br (* there's no generalisation to consume *) + else (* consume generalisations in the elim pred. through abstractions *) + match (gdstatus rnnext_env0 next_gd) with + Match_Current _ | All_Variables | All_Variables_Dep -> body_br + | _ -> (* we abstract the generalized argument tomatch of + * elimination predicate [d_bar:D_bar][_:(I param d_bar)]body_br + *) + abstract_dep_generalized_args ind_data rnnext_env0 body_br + in + let rnnext_env = common_prefix_ctxt env brenv in + rnnext_env, + {_VAL=eta_reduce_if_rel branch._VAL;_TYPE=branch._TYPE;_KIND=branch._KIND} + +(************************************************************** + * to deal with multiple patterns of dependent families (ex. Nacira)!! + +and build_nondep_branch sigma env gd next_pred bty (current,ind_data,info) i= + let (ity,(params,args),nparams,arityind,nconstr) = ind_data in + let n = nb_localargs ind_data in + let k = nb_prod (type_mconstruct sigma i ity) - nparams in + let body,(next_env,ngd,curlp) = + push_lpatt_and_liftl k bty.(i-1) SYNT + (env, + {case_dep= gd.case_dep; + pred= insert_lifted next_pred; + deptm = gd.deptm; + tomatch = snd (pop gd.tomatch); + mat = gd.mat}, + (current::params)) in + let (cur::lp) = curlp in + let lifted_params = Array.of_list lp in + let ci = applist (ith_constructor i ind_data, lp@(rel_list 0 k)) in + + let rnnext_env0,next_mat=submat ngd.case_dep sigma next_env i + ind_data lp cur ngd.mat in + + let ninfo,npred = + if n=0 then (SYNT, ngd.pred) (* as we treat only non-dep. elimination *) + else let dep_ci = args_app body in + if Array.length dep_ci=0 then (info,ngd.pred) else + let brpred = whd_beta (appvect (extract_lifted ngd.pred, dep_ci)) in + let ciargs_patt = List.map fst (fst (chop_list k ngd.tomatch)) in + (*we put pred. under same format that should be given by user + * and set info to be INH, to indicate that dependecies have been + * generalized *) + let pred0 = abstract_pred_lterms next_env (brpred, ciargs_patt) + in (INH,(insert_lifted pred0)) in + + (* we change info of next current as current my pass from SYNT to INH + * whenver dependencies are generalized in elimination predicate *) + let ntomatch = + if empty ngd.tomatch then ngd.tomatch + else let ((next_cur ,_),nltm)= pop ngd.tomatch + in push (next_cur, ninfo) nltm in + let next_gd = + {case_dep = ngd.case_dep; + pred = npred; + deptm = solve_dependencies !(trad.isevars) next_env ngd (cur, ci); + tomatch = ntomatch ; + mat = next_mat} in + let brenv,body_br = cc trad rnnext_env0 next_gd in + let rnnext_env = common_prefix_ctxt next_env brenv in + let _,branch,_ = lam_and_popl_named k (get_rels rnnext_env) body_br [] + in rnnext_env,(eta_reduce_if_rel branch) + +******************************************************) + +(* build__nondep_branch ensures the invariant that elimination predicate in + * gd is always under the same form the user is expected to give it. + * Thus, whenever an argument is destructed, for each + * synthesed argument, the corresponding predicate is computed assuring + * that the invariant. + * Whenever we match an object u of type (I param t_bar),where I is a dependent + * family of arity (x_bar:D_bar)s, in order to compile we + * 1) replace the current element in gd by (Rel 1) of type (I param x_bar) + * pushing to the environment env the new declarations + * [x_bar : D_bar][_:(I param x_bar)] + * 2) compile new gd in the environment env[x_bar : D_bar][_:(I param x_bar)] + * using the type (I param x_bar) to solve dependencies + * 3) pop the declarations [x_bar : D_bar][_:(I param x_bar)] from the + * environment by abstracting the result of compilation. We obtain a + * term ABST. Then apply the abstraction ABST to t_bar and u. + * The result is whd_beta (ABST t_bar u) + *) + +and build_nondep_branch trad env gd next_pred bty + (current,ind_data,info as cji) i = + let {mind=ity;params=params;nparams=nparams} = ind_data in + let n = nb_localargs ind_data in + let k = nb_prod (type_mconstruct !(trad.isevars) i (mutind_of_ind ity)) - nparams in + + (* if current is not rel, then we replace by rel so to solve dependencies *) + let (nenv,ncurargs,ncur,ncurgd,npred,nbty) = + if isRel current + then (env, [], current, gd, (insert_lifted next_pred), bty.(i-1)) + else + (* we push current and dependencies to environment *) + let (relenv,nind_data,relargs) = push_params !(trad.isevars) env cji in + + (* we lift predicate and type branch w.r.t. to pushed arguments *) + let nrelargs = List.length relargs in + let (curgd,lpred) = lift_gd nrelargs gd, lift_lfconstr nrelargs (insert_lifted next_pred) + in (relenv, relargs, (Rel 1), + (replace_gd_current(IsInd(Rel 1,nind_data),info) curgd), + lpred, lift nrelargs bty.(i-1)) in + + let body,(next_env,ngd,curlp) = + push_lpatt_and_liftl k nbty SYNT + (nenv, + {case_dep= ncurgd.case_dep; + pred= npred; + deptm = ncurgd.deptm; + tomatch = snd (pop ncurgd.tomatch); + mat = ncurgd.mat}, + ncur::params) in + + match curlp with + [] -> assert false + | (cur::lp) -> + let ci = applist (ith_constructor i ind_data, lp@(rel_list 0 k)) in + + let rnnext_env0,next_mat=submat ngd.case_dep !(trad.isevars) next_env i + ind_data lp cur ngd.mat in + + if next_mat = [] then + (* there is no row in the matrix corresponding to the ith constructor *) + errorlabstrm "build_nondep_branch" (mssg_may_need_inversion()) + else + + let (linfo,npred) = + let dep_ci = args_app body in + let brpred = if (n=0 or Array.length dep_ci=0) then + (* elmination predicate of ngd has correct number + * of abstractions *) + extract_lifted ngd.pred + else whd_beta (appvect (extract_lifted ngd.pred, dep_ci)) in + let ciargs_patt = List.map fst (fst (chop_list k ngd.tomatch)) in + (*we put pred. under same format that should be given by user + * and set info to be INH, to indicate that dependecies have been + * generalized *) + let linfo,pred0 = info_abstract_pred_lterms (brpred, ciargs_patt) + in + (linfo,(insert_lifted pred0)) + in + + (* we change info of next current as current my pass from SYNT to INH + * whenver dependencies are generalized in elimination predicate *) + let ntomatch = + let synt_tomatch, inh_tomatch = chop_list k ngd.tomatch in + let nsynt_tomatch = List.map2 (fun info (tm,_) -> (tm,info)) + linfo synt_tomatch + in nsynt_tomatch @ inh_tomatch in + + let next_gd = + {case_dep = ngd.case_dep; + pred = npred; + deptm = solve_dependencies !(trad.isevars) next_env ngd (cur, ci); + tomatch = ntomatch ; + mat = next_mat} + in + + let final_env, final_branch = + let brenv,body_br = cc trad rnnext_env0 next_gd in + let rnnext_env = common_prefix_ctxt next_env brenv in + let branchenv,localenv = chop_list k (get_rels rnnext_env) in + let localenv = List.map (fun (na,t) -> (na,incast_type t)) localenv in + (* Avant ici, on nommait les Anonymous *) + let branchval = lam_it body_br._VAL localenv in + let branchtyp = prod_it body_br._TYPE localenv in + ENVIRON(get_globals rnnext_env, branchenv), + {_VAL=branchval;_TYPE=branchtyp;_KIND=body_br._KIND} + + in + + (* we restablish initial current by abstracting and applying *) + let p = List.length ncurargs in + let abstenv,localenv = chop_list p (get_rels final_env) in + let localenv = List.map (fun (na,t) -> (na,incast_type t)) localenv in + (* Avant ici, on nommait les Anonymous *) + let abst = lam_it final_branch._VAL localenv in + let typ = + substn_many (Array.map make_substituend (Array.of_list ncurargs)) 0 + final_branch._TYPE in + let app = whd_beta (applist (abst, ncurargs)) in + ENVIRON(get_globals final_env, abstenv), + {_VAL = eta_reduce_if_rel app; + _TYPE = typ; + _KIND = final_branch._KIND} + +and match_current trad env (current,ind_data,info as cji) gd = + let {mind=ity;nparams=nparams;realargs=realargs;arity=arity;nconstr=nconstr} = ind_data in + let _,tl_tm = pop gd.tomatch in + + (* we build new predicate p for elimination *) + let (p,next_pred) = + build_nondep_predicate env cji gd in + + (* we build the branches *) + let bty = find_type_case_branches !(trad.isevars) env cji p in + + let build_ith_branch gd = build_nondep_branch trad env gd + next_pred bty cji in + + let build_case ()= + let newenv,v = + match List.map (build_ith_branch gd) (interval 1 nconstr) with + [] -> (* nconstr=0 *) + env, + mkMutCaseA (ci_of_mind (mutind_of_ind ity)) + (eta_reduce_if_rel p) current [||] + + | (bre1,f)::lenv_f as brl -> + let lf = Array.map Machops.j_val + (Array.of_list (f::(List.map snd lenv_f))) in + let rec check_conv i = + if i = nconstr then () else + if not (Evarconv.the_conv_x_leq trad.isevars env lf.(i) bty.(i)) + then + let c = nf_ise1 !(trad.isevars) current + and lfi = nf_betaiota (nf_ise1 !(trad.isevars) lf.(i)) in + error_ill_formed_branch CCI env c i lfi (nf_betaiota bty.(i)) + else check_conv (i+1) + in + check_conv 0; + (common_prefix_ctxt env bre1, + mkMutCaseA (ci_of_mind (mutind_of_ind ity)) (eta_reduce_if_rel p) + current lf) in + newenv, + {_VAL = v; + _TYPE = whd_beta (applist (p,realargs)); + _KIND = sort_of_arity (Evd.mt_evd ()) arity} + + in +(* + let build_mlcase () = + if nconstr=0 + then errorlabstrm "match_current" [< 'sTR "cannot treat ml-case">] + else + let n = nb_localargs ind_data in + let np= extract_lifted gd.pred in + let k = nb_lam np in + let (_,npred) = decompose_lam np in + let next_gd = {case_dep= gd.case_dep; + pred= insert_lifted npred; + deptm = gd.deptm; + tomatch = gd.tomatch; + mat = gd.mat} + in + try (* we try to find out the predicate and recall match_current *) + (let ipred = find_implicit_pred !(trad.isevars) + (build_ith_branch next_gd) + env cji in + (* we abstract with the rest of tomatch *) + let env0,bodyp = decompose_lam_n n ipred in + (*we put pred. under same format that should be given by user*) + let ipred0 = abstract_pred_lterms (bodyp, List.map fst tl_tm) in + let nipred = lamn n env0 ipred0 in + let explicit_gd = {gd with pred= insert_lifted nipred} + + in match_current trad env cji explicit_gd) + + with UserError(_,s) -> errorlabstrm "build_mlcase" + [<'sTR "Not enough information to solve implicit Case" >] + + in if is_for_mlcase p then build_mlcase () + else *) build_case () + + +and match_current_dep trad env (current,ind_data,info as cji) gd = + let sigma = !(trad.isevars) in + let {mind=ity;params=params;realargs=args;nconstr=nconstr;arity=arity}=ind_data in + + let nenv,ncurrent,ngd0= + if info=SYNT then (* we try to guess the type of current *) + if nb_prod (extract_lifted gd.pred) >0 then + (* we replace current implicit by (Rel 1) *) + let nenv,ngd = push_and_lift_gdn 1 (extract_lifted gd.pred) (env,gd) in + let ngd0 = replace_gd_current + (IsInd(Rel 1,lift_ind_data 1 ind_data),info) ngd + in nenv,(Rel 1),ngd0 + else anomalylabstrm "match_current_dep" + [<'sTR "sth. wrong with gd.predicate">] + else env,current,gd (* i.e. current is typable in current env *) + in + + (* we build new predicate p for elimination *) + let (p,next_pred) = build_dep_predicate trad.isevars nenv cji ngd0 in + + let np=whd_constraint p in + + (* we build the branches *) + let bty = find_type_case_branches !(trad.isevars) nenv cji np in + + let build_ith_branch env gd = build_dep_branch trad env gd bty cji in + + let ngd1 = replace_gd_pred (to_prod (nb_lam next_pred) next_pred) ngd0 in + + let build_dep_case () = + let nenv,rescase,casetyp = + if info=SYNT then + (*= builds [d_bar:D_bar][h:(I~d_bar)]<..>Cases current of lf end =*) + + let lf = List.map (fun i -> Machops.j_val + (snd (build_ith_branch nenv ngd1 i))) + (interval 1 nconstr) in + let case_exp = + mkMutCaseA (ci_of_mind (mutind_of_ind ity)) (eta_reduce_if_rel np) + current (Array.of_list lf) in + let _,rescase,_ = elam_and_popl_named 1 nenv case_exp [] in + let casetyp = whd_beta (applist (np,args)) in + nenv,rescase,casetyp + else + if info = INH_FIRST then + (*= Consumes and initial tomatch so builds <..>Cases current of lf end =*) + let lf = List.map (fun i -> Machops.j_val + (snd (build_ith_branch nenv ngd1 i))) + (interval 1 nconstr) in + let rescase = mkMutCaseA (ci_of_mind (mutind_of_ind ity)) + (eta_reduce_if_rel np) current (Array.of_list lf) in + let casetyp = whd_beta (applist (np,args)) in + nenv,rescase,casetyp + + else (* we treat an INH value *) + (* Consumes and initial tomatch abstracting that was generalized + * [m:T] <..>Cases current of lf end *) + let n = (List.length args)+1 in + let nenv1,ngd2 = push_and_lift_gdn n (extract_lifted gd.pred) + (nenv, ngd1) in + let np1 = lift n np in + let lf = List.map (fun i -> Machops.j_val + (snd (build_ith_branch nenv1 ngd2 i))) + (interval 1 nconstr) in + (* Now we replace the initial INH tomatch value (given by the user) + * by (Rel 1) so to link it to the product. The instantiation of the + * this (Rel 1) by initial value will be done by the application + *) + let case_exp = + mkMutCaseA (ci_of_mind (mutind_of_ind ity)) np1 (Rel 1) (Array.of_list lf) in + let nenv2,rescase,_ = elam_and_popl_named n nenv1 case_exp [] in + let casetyp = whd_beta (applist (np,args@[(Rel 1)])) in + nenv2,rescase,casetyp + + in + nenv, + {_VAL = rescase; + _TYPE = casetyp; + _KIND = sort_of_arity (Evd.mt_evd ()) arity} + in build_dep_case () + + +and bare_substitute_rhs trad tm_is_dependent env gd = + let (cur,info),tm = pop gd.tomatch in + let nenv = rename_cur_ctxt env (term_tomatch cur) gd in + let npred = + if gd.case_dep then gd.pred + else (* le prochain argument n'est pas filtrable (i.e. parce que les + * motifs sont tous des variables ou parce qu'il n'y a plus de + * motifs), alors npred est gd.pred *) + let tmp_gd ={case_dep = gd.case_dep; pred = gd.pred; deptm = gd.deptm; + tomatch = tm; + mat = List.map (subst_current (term_tomatch cur)) gd.mat} in + let pred0 = extract_lifted gd.pred in + let pred1 = apply_to_dep env pred0 cur + in insert_lifted pred1 in + + let ngd = if tm_is_dependent then + {case_dep = gd.case_dep; + pred = npred; + deptm = push_lifted (term_tomatch cur) gd.deptm; + tomatch = tm; + mat = List.map shift_current_to_dep gd.mat} + else {case_dep = gd.case_dep; + pred = npred; + deptm = gd.deptm; + tomatch = tm; + mat = List.map (subst_current (term_tomatch cur)) gd.mat} + in let brenv,res = cc trad nenv ngd + in (common_prefix_ctxt nenv brenv), res + + +(* to preserve the invariant that elimination predicate is under the same + * form we ask to the user, berfore substitution we compute the correct + * elimination predicat whenver the argument is not inherited (i.e. info=SYNT) + *) +and substitute_rhs trad env gd = + let (curj,info),tm = pop gd.tomatch in + let nenv = rename_cur_ctxt env (term_tomatch curj) gd in + let npred = + match info with + SYNT -> (* we abstract dependencies in elimination predicate, to maintain + * the invariant, that gd.pred has always the correct number of + * dependencies *) + (*we put pred. under same format that should be given by user*) + (try let npred = abstract_pred_lterms ((extract_lifted gd.pred),[curj]) + in insert_lifted npred + with _ -> gd.pred ) + + | _ -> gd.pred in + + let ngd = {gd with pred= npred} in + let tm_is_dependent = depends env (term_tomatch curj) tm + in bare_substitute_rhs trad tm_is_dependent env ngd + + +and substitute_rhs_dep trad env gd = + let (curj,info),_ = pop gd.tomatch in + let ([_,ty as v], npred) = get_n_prod 1 (extract_lifted gd.pred) in + let nenv,ngd = push_and_lift_gd v (env,gd) in + let ncur = (Rel 1) in + let (_,ntm) = pop ngd.tomatch in + let next_gd = {case_dep= gd.case_dep; + pred = insert_lifted npred; + deptm = ngd.deptm; + tomatch = [(to_mutind ncur !(trad.isevars) ty,info)]@ntm; + mat= ngd.mat} in + let tm_is_dependent = dependent ncur npred in + let nenv0,body= bare_substitute_rhs trad tm_is_dependent nenv next_gd in + let (na,ty),nenv1 = uncons_rel_env nenv0 in + let nbodyval = Environ.lambda_name (na,incast_type ty,body._VAL) in + let nbodytyp = Environ.prod_name (na,incast_type ty,body._TYPE) in + let (nbodyval,nbodytyp) = + if info=INH_FIRST then + (applist(nbodyval,[term_tomatch curj]), + subst1 (term_tomatch curj) body._TYPE) + else (nbodyval,nbodytyp) in + (nenv1, {_VAL=nbodyval;_TYPE=nbodytyp;_KIND=body._KIND}) + +and build_leaf trad env gd = + match gd.mat with + | [] -> errorlabstrm "build_leaf" (mssg_may_need_inversion()) + | _::_::_ -> errorlabstrm "build_leaf" [<'sTR "Some clauses are redondant" >] + | [row] -> + let rhs = row.rhs in + if rhs.user_ids <> [] then + anomaly "Some user pattern variables has not been substituted"; + if rhs.private_ids <> [] then + anomaly "Some private pattern variables has not been substituted"; + let j = + try trad.pretype (mk_tycon (extract_lifted gd.pred)) env rhs.it + with UserError(s,stream) -> + raise (CCError("build_leaf",env,gd,(Some rhs.it),(s,stream))) in + let subst = List.map (fun (id,c) -> (id,make_substituend c)) rhs.subst in + let judge = + {_VAL = substitute_dependencies (replace_vars subst j._VAL) + (gd.deptm, row.dependencies); + _TYPE = substitute_dependencies (replace_vars subst j._TYPE) + (gd.deptm, row.dependencies); + _KIND = j._KIND} in + env,judge + +and build_leaf_dep trad env gd = build_leaf trad env gd +;; + + +(* Devrait être inutile et pris en compte par pretype +let check_coercibility isevars env ty indty = + if not (Evarconv.the_conv_x isevars env ty indty) + then errorlabstrm "productize" + [< 'sTR "The type "; pTERMINENV (env,ty); + 'sTR " in the Cases annotation predicate"; 'sPC; + 'sTR "is not convertible to the inductive type"; 'sPC; + pTERM indty >];; + +(* productize [x1:A1]..[xn:An]u builds (x1:A1)..(xn:An)u and uses + the types of tomatch to make some type inference *) +let check_pred_correctness isevars env tomatchl pred = + let cook n = function + | IsInd(c,({mind=ity;params=params;realargs=args;arity=arity} as ind_data)) + -> (applist (mutind_of_ind ity,(List.map (lift n) params) + @(rel_list 0 (nb_localargs ind_data))), + lift n (whd_beta (applist (arity,params)))) + | MayBeNotInd (_,_) -> anomaly "Should have been catched in case_dependent" + in + let rec checkrec n pred = function + | [] -> pred + | tm::ltm -> + let (ty1,arity) = cook n tm in + let rec follow n (arity,pred) = + match (whd_betadeltaiota mtevd arity, + whd_betadeltaiota !isevars pred) with + DOP2(Prod,ty2,DLAM(_,bd2)),DOP2(Lambda,ty,DLAM(na,bd)) -> + check_coercibility isevars env ty2 ty; + follow (n+1) (bd2,bd) + | _ , DOP2(Lambda,ty,DLAM(na,bd)) -> + check_coercibility isevars env ty1 ty; + checkrec (n+1) bd ltm + in follow n (arity,pred) + in checkrec 0 pred tomatchl +;; +*) +let build_expected_arity isdep tomatchl sort = + let cook n = function + | IsInd(c,({mind=ity;params=params;realargs=args;arity=arity} as ind_data)) + -> (applist (mutind_of_ind ity,(List.map (lift n) params) + @(rel_list 0 (nb_localargs ind_data))), + lift n (whd_beta (applist (arity,params)))) + | MayBeNotInd (_,_) -> anomaly "Should have been catched in case_dependent" + in + let rec buildrec n = function + | [] -> sort + | tm::ltm -> + let (ty1,arity) = cook n tm in + let rec follow n arity = + match whd_betadeltaiota mtevd arity with + DOP2(Prod,ty2,DLAM(na,bd2)) -> + DOP2(Prod,ty2,DLAM(na,follow (n+1) bd2)) + | _ -> + if isdep then + DOP2(Prod,ty1,DLAM(Anonymous,buildrec (n+1) ltm)) + else buildrec n ltm + in follow n arity + in buildrec 0 tomatchl + +let rec productize lam = + match strip_outer_cast lam with + DOP2(Lambda,ty,DLAM(n,bd)) -> mkProd n ty (productize bd) + | x -> x +;; + +(* determines wether the multiple case is dependent or not. For that + * the predicate given by the user is eta-expanded. If the result + * of expansion is pred, then : + * if pred=[x1:T1]...[xn:Tn]P and tomatchj=[|[e1:S1]...[ej:Sj]] then + * if n= SUM {i=1 to j} nb_prod (arity Sj) + * then case_dependent= false + * else if n= j+(SUM (i=1 to j) nb_prod(arity Sj)) + * then case_dependent=true + * else error! (can not treat mixed dependent and non dependent case + *) +let case_dependent env sigma predj tomatchj = + let nb_dep_ity = function + IsInd (_,ind_data) -> nb_localargs ind_data + | MayBeNotInd (c,t) -> errorlabstrm "case_dependent" + (error_case_not_inductive CCI env c t) + in + let etapred = eta_expand sigma predj._VAL predj._TYPE in + let n = nb_lam etapred in + let _,sort = decomp_prod sigma predj._TYPE in + let ndepv = List.map nb_dep_ity tomatchj in + let sum = List.fold_right (fun i j -> i+j) ndepv 0 in + if n=sum then (false,build_expected_arity true tomatchj sort) + else if n=sum+ List.length tomatchj + then (true,build_expected_arity true tomatchj sort) + else errorlabstrm "case_dependent" + (mssg_wrong_predicate_arity env etapred sum (sum+ List.length tomatchj)) +;; + + +(* builds the matrix of equations testing that each row has n patterns + * and linearizing the _ patterns. + *) +(* +let matx_of_eqns sigma env eqns n = + let build_row = function + | (ids,lpatt,rhs) -> + List.iter check_pat_arity lpatt; + let (_,rlpatt) = rename_lpatt [] lpatt in + let _ = check_linearity env rlpatt lhs in + if List.length rlpatt = n + then { dependencies = []; + patterns = + { past = []; + future = + List.map insert_lfpattern rlpatt}; + rhs = insert_lifted rhs} + else errorlabstrm "matx_of_eqns" (mssg_number_of_patterns env lhs n) + | _ -> errorlabstrm "expand_mastx_patterns" + [<'sTR "empty list of patterns">] + + in List.map build_row eqns +;; +*) +(* Syntactic correctness has already been done in astterm *) +let matx_of_eqns sigma env eqns n = + let build_row (ids,lpatt,rhs) = + List.iter check_pat_arity lpatt; + { dependencies = []; + patterns = { past = []; future = lpatt}; + rhs = {private_ids=[];subst=[];user_ids=ids;rhs_lift=0;it=rhs}} + + in List.map build_row eqns +;; + + +let initial_gd cd npred matx = + { case_dep=cd; + pred=insert_lifted npred; + deptm = []; + tomatch = []; + mat = matx } +;; + + +(*--------------------------------------------------------------------------* + * 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(_,c,_) :: _ -> Some c + | PatAs(_,_,p)::l -> find_row_ind (p::l) +;; + +let find_pretype mat = + let lpatt = List.map (fun r -> List.hd r.patterns.future) mat in + match find_row_ind lpatt with + Some c -> mutind_of_constructor c + | None -> anomalylabstrm "find_pretype" + [<'sTR "Expecting a patt. in constructor form and found empty list">] +;; + +(* Split type ty as the application of an inductive type to arguments. + * If ty is not an inductive type, we look if we can infer if from the + * constructor names in the first row of mat. We define evars that will + * stand for the params & args of this inductive type. Works fine for + * the params, but we cannot get information from the branches to find + * the value of the arguments... + *) +(* +let evar_find_mrectype isevars env mat ty = + try find_mrectype !isevars ty + with Induc -> + (inh_coerce_to_ind isevars env ty (find_pretype mat); + find_mrectype !isevars ty) +;; +*) + +(* Same as above, but 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 transpose mat = + List.fold_right (List.map2 (fun p c -> p::c)) mat + (if mat = [] then [] else List.map (fun _ -> []) (List.hd mat)) +;; + +let inh_coerce_to_ind isevars env ty tyi = + let (ntys,_) = splay_prod !isevars (mind_arity tyi) in + let evarl = + List.map + (fun (_,ty) -> + let s = Mach.sort_of mtevd env ty in + fst (new_isevar isevars env (mkCast ty (mkSort s)) CCI)) ntys in + let expected_typ = applist (tyi,evarl) in + (* devrait être indifférent d'exiger leq ou pas puisque pour + un inductif cela doit être égal *) + if Evarconv.the_conv_x_leq isevars env expected_typ ty then ty + else raise Induc +;; + +let coerce_row trad env row tomatch = + let j = trad.pretype mt_tycon env tomatch in + match find_row_ind row with + Some cstr -> + (let tyi = mutind_of_constructor cstr in + try + let indtyp = inh_coerce_to_ind trad.isevars env j._TYPE tyi in + IsInd (j._VAL,try_mutind_of !(trad.isevars) j._TYPE) + with Induc -> + errorlabstrm "coerce_row" + (mssg_tomatch_of_unexpected_type cstr j._TYPE)) + | None -> + try IsInd (j._VAL,try_mutind_of !(trad.isevars) j._TYPE) + with Induc -> MayBeNotInd (j._VAL,j._TYPE) +;; + +let coerce_to_indtype trad env matx tomatchl = + let pats = List.map (fun r -> r.patterns.future) matx in + List.map2 (coerce_row trad env) (transpose pats) tomatchl +;; + +(* (mach_)compile_multcase: + * The multcase that are in rhs are rawconstr + * when we arrive at the leaves we call + * trad.pretype that will call compile recursively. + * compile (<pred>Case e1..en end of ...)= ([x1...xn]t' e1...en) + * where t' is the result of the translation. + * INVARIANT for NON-DEP COMPILATION: predicate in gd is always under the same + * form we ask the user to write <..>. + * Thus, during the algorithm, whenever the argument to match is inherited + * (i.e. info<>SYNT) the elimination predicate in gd should have the correct + * number of abstractions. Whenever the argument to match is synthesed we have + * to abstract all the dependencies in the elimination predicate, before + * processing the tomatch argument. The invariant is thus preserved in the + * functions build_nondep_branch y substitute_rhs. + * Note: this function is used by trad.ml + *) + +let compile_multcase_fail trad vtcon env (predopt, tomatchl, eqns) = + + (* We build the matrix of patterns and right-hand-side *) + let matx = matx_of_eqns !(trad.isevars) env eqns (List.length tomatchl) in + + (* We build the vector of terms to match consistently with the *) + (* constructors found in patterns *) + let tomatchj = coerce_to_indtype trad env matx tomatchl in + + (* We build the elimination predicate and check its consistency with *) + (* the type of arguments to match *) + let cd,npred = + match predopt with + | None -> + let finalres = + match vtcon with + | (_,(_,Some p)) -> p + | _ -> let ty = mkCast dummy_sort dummy_sort in + let (c,_) = new_isevar trad.isevars env ty CCI in c + in (false,abstract_pred_lterms (finalres,tomatchj)) + | Some pred -> + (* First call to exemeta to know if it is dependent *) + let predj1 = trad.pretype mt_tycon env pred in + let cdep,arity = case_dependent env !(trad.isevars) predj1 tomatchj in + (* We got the expected arity of pred and relaunch pretype with it *) + let predj = trad.pretype (mk_tycon arity) env pred in + let etapred = eta_expand !(trad.isevars) predj._VAL predj._TYPE in + if cdep then (cdep, productize etapred) + else (cdep,etapred) in + + let gdi = initial_gd cd npred matx in + + (* we push the terms to match to gd *) + let env1,gd,args = push_tomatch env gdi tomatchj in + + (* Now we compile, abstract and reapply the terms tomatch *) + let brenv,body = cc trad env1 gd in + let rnenv1 = common_prefix_ctxt env1 brenv in + let k = List.length (get_rels env1) - List.length (get_rels env) in + let env2,abst,_ = elam_and_popl k rnenv1 body._VAL [] in + let typ = body._TYPE in (* DEVRAIT ETRE INCORRECT *) + let res = if args=[] then abst + else whd_beta (applist (abst, args)) in +(* + let rest = Mach.newtype_of !(trad.isevars) env2 res in + let resl = Mach.newtype_of !(trad.isevars) env2 rest in +*) + {_VAL=res;_TYPE=typ;_KIND=body._KIND} +;; + +let compile_multcase (pretype,isevars) vtcon env macro = + let trad = {pretype=(fun vtyc env -> pretype vtyc env); + isevars = isevars} in + try compile_multcase_fail trad vtcon env macro + with UserError("Ill-formed branches", s) -> mssg_ill_typed_branch (s) + | CCError ("build_leaf", errenv, errgd,errrhs,innermssg) -> + mssg_build_leaf errenv errgd errrhs innermssg +;; diff --git a/pretyping/pretype_errors.ml b/pretyping/pretype_errors.ml index ea958976bd..8892eaf7fa 100644 --- a/pretyping/pretype_errors.ml +++ b/pretyping/pretype_errors.ml @@ -1,6 +1,9 @@ -let error_cant_find_case_type loc env expr = +let error_cant_find_case_type_loc loc env expr = raise (PretypeError (loc,CCI,context env,CantFindCaseType expr)) let error_ill_formed_branch k env c i actty expty = raise (TypeError (k, context env, IllFormedBranch (c,i,actty,expty))) + +let error_number_branches_loc loc k env c ct expn = + raise (PretypeError (loc, k, context env, NumberBranches (c,ct,expn))) diff --git a/pretyping/pretype_errors.mli b/pretyping/pretype_errors.mli index 2356154989..c8f6dc463b 100644 --- a/pretyping/pretype_errors.mli +++ b/pretyping/pretype_errors.mli @@ -15,8 +15,9 @@ exception PreTypeError of loc * path_kind * context * type_error val error_cant_find_case_type_loc : loc -> unsafe_env -> constr -> 'a -val error_number_branches_loc : - loc -> unsafe_env -> constr -> constr -> int -> 'b - val error_ill_formed_branch_loc : loc -> path_kind -> unsafe_env -> constr -> int -> constr -> constr -> 'b + +val error_number_branches_loc : + loc -> path_kind -> unsafe_env -> constr -> constr -> int -> 'b + diff --git a/pretyping/pretyping.ml b/pretyping/pretyping.ml index 19065bebb3..1e6245a471 100644 --- a/pretyping/pretyping.ml +++ b/pretyping/pretyping.ml @@ -21,6 +21,124 @@ open Rawterm open Evarconv open Coercion + +(***********************************************************************) +(* This concerns Cases *) +open Inductive +open Instantiate + +(* Pour le vieux "match" que Program utilise encore, vieille histoire ... *) + +(* Awful special reduction function which skips abstraction on Xtra in + order to be safe for Program ... *) + +let stacklamxtra recfun = + let rec lamrec sigma p_0 p_1 = match p_0,p_1 with + | (stack, (DOP2(Lambda,DOP1(XTRA "COMMENT",_),DLAM(_,c)) as t)) -> + recfun stack (substl sigma t) + | ((h::t), (DOP2(Lambda,_,DLAM(_,c)))) -> lamrec (h::sigma) t c + | (stack, t) -> recfun stack (substl sigma t) + in + lamrec + +let rec whrec x stack = + match x with + | DOP2(Lambda,DOP1(XTRA "COMMENT",c),DLAM(name,t)) -> + let t' = applist (whrec t (List.map (lift 1) stack)) in + DOP2(Lambda,DOP1(XTRA "COMMENT",c),DLAM(name,t')),[] + | DOP2(Lambda,c1,DLAM(name,c2)) -> + (match stack with + | [] -> (DOP2(Lambda,c1,DLAM(name,whd_betaxtra c2)),[]) + | a1::rest -> stacklamxtra (fun l x -> whrec x l) [a1] rest c2) + | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) + | DOP2(Cast,c,_) -> whrec c stack + | x -> x,stack + +and whd_betaxtra x = applist(whrec x []) + +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 prod_create env (a,b) = + mkProd (named_hd env a Anonymous) a b +let lambda_name env (n,a,b) = + mkLambda (named_hd env a n) a b +let lambda_create env (a,b) = + mkLambda (named_hd env a Anonymous) a b +let it_prod_name env = + List.fold_left (fun c (n,t) -> prod_name env (n,t,c)) +let it_lambda_name env = + List.fold_left (fun c (n,t) -> lambda_name env (n,t,c)) + +let transform_rec loc env sigma cl (ct,pt) = + let (mI,largs as mind) = find_minductype env sigma ct in + let p = cl.(0) + and c = cl.(1) + and lf = Array.sub cl 2 ((Array.length cl) - 2) in + let mispec = lookup_mind_specif mI env in + let recargs = mis_recarg mispec in + let expn = Array.length recargs in + if Array.length lf <> expn then + error_number_branches_loc loc CCI env c ct expn; + if is_recursive [mispec.mis_tyi] recargs then + let (dep,_) = find_case_dep_nparams env sigma (c,p) mind pt in + let ntypes = mis_nconstr mispec + and tyi = mispec.mis_tyi + and nparams = mis_nparams mispec in + let depFvec = Array.create ntypes (None : (bool * constr) option) in + let _ = Array.set depFvec mispec.mis_tyi (Some(dep,Rel 1)) in + let (pargs,realargs) = list_chop nparams largs in + let vargs = Array.of_list pargs in + let (_,typeconstrvec) = mis_type_mconstructs mispec in + (* build now the fixpoint *) + let realar = + hnf_prod_appvect env sigma "make_branch" (mis_arity mispec) vargs in + let lnames,_ = splay_prod env sigma realar in + let nar = List.length lnames in + let branches = + array_map3 + (fun f t reca -> + whd_betaxtra + (Indrec.make_rec_branch_arg env sigma + ((Array.map (lift (nar+2)) vargs),depFvec,nar+1) + f t reca)) + (Array.map (lift (nar+2)) lf) typeconstrvec recargs + in + let deffix = + it_lambda_name env + (lambda_create env + (appvect (mI,Array.append (Array.map (lift (nar+1)) vargs) + (rel_vect 0 nar)), + mkMutCaseA (ci_of_mind mI) + (lift (nar+2) p) (Rel 1) branches)) + (lift_context 1 lnames) + in + if noccurn 1 deffix then + whd_beta env sigma (applist (pop deffix,realargs@[c])) + else + let typPfix = + it_prod_name env + (prod_create env + (appvect (mI,(Array.append + (Array.map (lift nar) vargs) + (rel_vect 0 nar))), + (if dep then + applist (whd_beta_stack env sigma + (lift (nar+1) p) (rel_list 0 (nar+1))) + else + applist (whd_beta_stack env sigma + (lift (nar+1) p) (rel_list 1 nar))))) + lnames + in + let fix = DOPN(Fix([|nar|],0), + [|typPfix; + DLAMV(Name(id_of_string "F"),[|deffix|])|]) + in + applist (fix,realargs@[c]) + else + mkMutCaseA (ci_of_mind mI) p c lf + +(***********************************************************************) let ctxt_of_ids ids = Array.of_list (List.map (function id -> VAR id) ids) @@ -33,6 +151,14 @@ let j_nf_ise env sigma {uj_val=v;uj_type=t;uj_kind=k} = let jv_nf_ise env sigma = Array.map (j_nf_ise env sigma) +(* 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 has_ise env sigma t = + try let _ = whd_ise env sigma t in true + with UserError _ -> false + let evar_type_fixpoint env isevars lna lar vdefj = let lt = Array.length vdefj in if Array.length lar = lt then @@ -58,7 +184,7 @@ let let_path = make_path ["Core"] (id_of_string "let") CCI let wrong_number_of_cases_message loc env isevars (c,ct) expn = let c = nf_ise1 env !isevars c and ct = nf_ise1 env !isevars ct in - error_number_branches_loc loc env c ct expn + error_number_branches_loc loc CCI env c ct expn let check_branches_message loc env isevars (c,ct) (explft,lft) = let n = Array.length explft and expn = Array.length lft in @@ -105,8 +231,9 @@ let pretype_ref loc isevars env = function | RConst (sp,ids) -> let cstr = mkConst sp (ctxt_of_ids ids) in make_judge cstr (type_of_constant env !isevars cstr) + +| RAbst sp -> failwith "Pretype: abst doit disparaître" (* -| RAbst sp -> if sp = let_path then (match Array.to_list cl with [m;DLAM(na,b)] -> @@ -115,7 +242,7 @@ let pretype_ref loc isevars env = function let mj = inh_ass_of_j isevars env mj in let mb = body_of_type mj in let bj = - pretype mt_tycon isevars (add_rel (na,mj) env) b in + pretype mt_tycon (push_rel (na,mj) env) isevars b in {uj_val = DOPN(Abst sp,[|mb;DLAM(na,bj.uj_val)|]); uj_type = sAPP (DLAM(na,bj.uj_type)) mb; uj_kind = pop bj.uj_kind } @@ -221,24 +348,23 @@ match cstr with (* Où teste-t-on que le résultat doit satisfaire tycon ? *) let assum = inh_ass_of_j env isevars j in let var = (name,assum) in let j' = - pretype (abs_rng_tycon isevars vtcon) isevars - (add_rel var env) c2 in - abs_rel !isevars name assum j' + pretype (abs_rng_tycon isevars vtcon) (push_rel var env) isevars c2 in + fst (abs_rel env !isevars name assum j') | RBinder(loc,BProd,name,c1,c2) -> let j = pretype def_vty_con env isevars c1 in let assum = inh_ass_of_j env isevars j in let var = (name,assum) in - let j' = pretype def_vty_con isevars (add_rel var env) c2 in + let j' = pretype def_vty_con (push_rel var env) isevars c2 in let j'' = inh_tosort env isevars j' in - gen_rel !isevars CCI env name assum j'' + fst (gen_rel env !isevars name assum j'') | ROldCase (loc,isrec,po,c,lf) -> let cj = pretype mt_tycon env isevars c in let (mind,_) = - try find_mrectype !isevars cj.uj_type + try find_mrectype env !isevars cj.uj_type with Induc -> error_case_not_inductive CCI env - (nf_ise1 !isevars cj.uj_val) (nf_ise1 !isevars cj.uj_type) in + (nf_ise1 env !isevars cj.uj_val) (nf_ise1 env !isevars cj.uj_type) in let pj = match po with | Some p -> pretype mt_tycon env isevars p | None -> @@ -251,24 +377,25 @@ match cstr with (* Où teste-t-on que le résultat doit satisfaire tycon ? *) with UserError _ -> (* get type information from type of branches *) let rec findtype i = if i > Array.length lf - then error_cant_find_case_type loc env cj.uj_val + then error_cant_find_case_type_loc loc env cj.uj_val else try - let expti = Indrec.branch_scheme !isevars isrec i cj.uj_type in + let expti = Indrec.branch_scheme env !isevars isrec i cj.uj_type in let fj = pretype (mk_tycon expti) env isevars lf.(i-1) in - let efjt = nf_ise1 !isevars fj.uj_type in + let efjt = nf_ise1 env !isevars fj.uj_type in let pred = Indrec.pred_case_ml_onebranch env !isevars isrec (cj.uj_val,cj.uj_type) (i,fj.uj_val,efjt) in - if has_ise pred then findtype (i+1) + if has_ise env !isevars pred then findtype (i+1) else - let pty = Mach.newtype_of env !isevars pred in - {uj_val=pred;uj_type=pty;uj_kind=Mach.newtype_of env !isevars pty} + let pty = Retyping.get_type_of env !isevars pred in + let k = Retyping.get_type_of env !isevars pty in + {uj_val=pred;uj_type=pty;uj_kind=k} with UserError _ -> findtype (i+1) in findtype 1 in - let evalct = nf_ise1 !isevars cj.uj_type - and evalPt = nf_ise1 !isevars pj.uj_type in + let evalct = nf_ise1 env !isevars cj.uj_type + and evalPt = nf_ise1 env !isevars pj.uj_type in let (mind,bty,rsty) = Indrec.type_rec_branches isrec env !isevars evalct evalPt pj.uj_val cj.uj_val in @@ -277,38 +404,38 @@ match cstr with (* Où teste-t-on que le résultat doit satisfaire tycon ? *) (Array.length bty) else let lfj = - map2_vect + array_map2 (fun tyc f -> pretype (mk_tycon tyc) env isevars f) bty lf in + let lfv = (Array.map (fun j -> j.uj_val) lfj) in let lft = (Array.map (fun j -> j.uj_type) lfj) in check_branches_message loc env isevars (cj.uj_val,evalct) (bty,lft); let v = if isrec then - let rEC = Array.append [|(j_val pj); (j_val cj)|] - (Array.map j_val lfj) in - Indrec.transform_rec loc env !isevars rEC (evalct,evalPt) + let rEC = Array.append [|pj.uj_val; cj.uj_val|] lfv in + transform_rec loc env !isevars rEC (evalct,evalPt) else let ci = ci_of_mind mind in - mkMutCaseA ci (j_val pj) (j_val cj) (Array.map j_val lfj) in + mkMutCaseA ci pj.uj_val cj.uj_val (Array.map (fun j-> j.uj_val) lfj) in - {uj_val = v; + {uj_val = v; uj_type = rsty; - uj_kind = sort_of_arity !isevars evalPt} + uj_kind = snd (splay_prod env !isevars evalPt)} | RCases (loc,prinfo,po,tml,eqns) -> Multcase.compile_multcase - ((fun vtyc -> pretype vtyc isevars),isevars) + ((fun vtyc env -> pretype vtyc env isevars),isevars) vtcon env (po,tml,eqns) -(* -| DOP2(Cast,c,t) -> + +| RCast(loc,c,t) -> let tj = pretype def_vty_con env isevars t in let tj = inh_tosort_force env isevars tj in let cj = - pretype (mk_tycon2 vtcon (assumption_of_judgement env !isevars tj).body) + pretype (mk_tycon2 vtcon (assumption_of_judgment env !isevars tj).body) env isevars c in inh_cast_rel env isevars cj tj -*) + (* Maintenant, tout s'exécute... - | _ -> error_cant_execute CCI env (nf_ise1 !isevars cstr) + | _ -> error_cant_execute CCI env (nf_ise1 env !isevars cstr) *) @@ -323,14 +450,22 @@ let unsafe_fmachine vtcon nocheck isevars metamap env constr = * true -> raise an error message * false -> convert them into new Metas (casted with their type) *) -let process_evars fail_evar sigma = - (if fail_evar then whd_ise sigma else whd_ise1_metas sigma) - - -let j_apply f j = - { uj_val=strong (under_outer_cast f) j.uj_val; - uj_type=strong f j.uj_type; - uj_kind=strong f j.uj_kind} +let process_evars fail_evar env sigma = + (if fail_evar then + try whd_ise env sigma + with Uninstantiated_evar n -> + errorlabstrm "whd_ise" + [< 'sTR"There is an unknown subterm I cannot solve" >] + else whd_ise1_metas env sigma) + + +let j_apply f env sigma j = + let under_outer_cast f env sigma = function + | DOP2 (Cast,b,t) -> DOP2 (Cast,f env sigma b,f env sigma t) + | c -> f env sigma c in + { uj_val=strong (under_outer_cast f) env sigma j.uj_val; + uj_type=strong f env sigma j.uj_type; + uj_kind=strong f env sigma j.uj_kind} (* TODO: comment faire remonter l'information si le typage a resolu des variables du sigma original. il faudrait que la fonction de typage @@ -339,22 +474,44 @@ let j_apply f j = let ise_resolve fail_evar sigma metamap env c = let isevars = ref sigma in let j = unsafe_fmachine mt_tycon false isevars metamap env c in - j_apply (process_evars fail_evar !isevars) j + j_apply (process_evars fail_evar) env !isevars j let ise_resolve_type fail_evar sigma metamap env c = let isevars = ref sigma in let j = unsafe_fmachine def_vty_con false isevars metamap env c in let tj = inh_ass_of_j env isevars j in - type_app (strong (process_evars fail_evar !isevars)) tj + typed_app (strong (process_evars fail_evar) env !isevars) tj let ise_resolve_nocheck sigma metamap env c = let isevars = ref sigma in let j = unsafe_fmachine mt_tycon true isevars metamap env c in - j_apply (process_evars true !isevars) j + j_apply (process_evars true) env !isevars j let ise_resolve1 is_ass sigma env c = if is_ass then body_of_type (ise_resolve_type true sigma [] env c) else (ise_resolve true sigma [] env c).uj_val + +(* Keeping universe constraints *) +(* +let fconstruct_type_with_univ_sp sigma sign sp c = + with_universes + (Mach.fexecute_type sigma sign) (sp,initial_universes,c) + + +let fconstruct_with_univ_sp sigma sign sp c = + with_universes + (Mach.fexecute sigma sign) (sp,initial_universes,c) + + +let infconstruct_type_with_univ_sp sigma (sign,fsign) sp c = + with_universes + (Mach.infexecute_type sigma (sign,fsign)) (sp,initial_universes,c) + + +let infconstruct_with_univ_sp sigma (sign,fsign) sp c = + with_universes + (Mach.infexecute sigma (sign,fsign)) (sp,initial_universes,c) +*) diff --git a/pretyping/pretyping.mli b/pretyping/pretyping.mli index 7b95e2dcc6..5dabb016fc 100644 --- a/pretyping/pretyping.mli +++ b/pretyping/pretyping.mli @@ -8,49 +8,32 @@ open Term open Environ open Evd open Rawterm +open Evarutil (*i*) -val type_of_com : context -> Coqast.t -> typed_type - -val constr_of_com_casted : 'c evar_map -> context -> Coqast.t -> constr -> - constr - -val constr_of_com1 : bool -> 'c evar_map -> context -> Coqast.t -> constr -val constr_of_com : 'c evar_map -> context -> Coqast.t -> constr -val constr_of_com_sort : 'c evar_map -> context -> Coqast.t -> constr - -val fconstr_of_com1 : bool -> 'c evar_map -> context -> Coqast.t -> constr -val fconstr_of_com : 'c evar_map -> context -> Coqast.t -> constr -val fconstr_of_com_sort : 'c evar_map -> context -> Coqast.t -> constr - - (* Typing with Trad, and re-checking with Mach *) (*i -val fconstruct :'c evar_map -> context -> Coqast.t -> judgement -val fconstruct_type : - 'c evar_map -> context -> Coqast.t -> type_judgement - val infconstruct_type : - 'c evar_map -> (context * context) -> - Coqast.t -> type_judgement * information + 'c evar_map -> (unsafe_env * unsafe_env) -> + Coqast.t -> typed_type * information val infconstruct : - 'c evar_map -> (context * context) -> - Coqast.t -> judgement * information + 'c evar_map -> (unsafe_env * unsafe_env) -> + Coqast.t -> unsafe_judgment * information (* Typing, re-checking with universes constraints *) val fconstruct_with_univ : - 'c evar_map -> context -> Coqast.t -> judgement -val fconstruct_with_univ_sp : 'c evar_map -> context - -> section_path -> constr -> Impuniv.universes * judgement -val fconstruct_type_with_univ_sp : 'c evar_map -> context - -> section_path -> constr -> Impuniv.universes * type_judgement + 'c evar_map -> unsafe_env -> Coqast.t -> unsafe_judgment +val fconstruct_with_univ_sp : 'c evar_map -> unsafe_env + -> section_path -> constr -> Impuniv.universes * unsafe_judgment +val fconstruct_type_with_univ_sp : 'c evar_map -> unsafe_env + -> section_path -> constr -> Impuniv.universes * typed_type val infconstruct_with_univ_sp : - 'c evar_map -> (context * context) - -> section_path -> constr -> Impuniv.universes * (judgement * information) + 'c evar_map -> (unsafe_env * unsafe_env) + -> section_path -> constr -> Impuniv.universes * (unsafe_judgment * information) val infconstruct_type_with_univ_sp : - 'c evar_map -> (context * context) + 'c evar_map -> (unsafe_env * unsafe_env) -> section_path -> constr - -> Impuniv.universes * (type_judgement * information) + -> Impuniv.universes * (typed_type * information) i*) (* Low level typing functions, for terms with de Bruijn indices and Metas *) @@ -58,23 +41,23 @@ i*) (* Raw calls to the inference machine of Trad: boolean says if we must fail * on unresolved evars, or replace them by Metas *) val ise_resolve : bool -> 'c evar_map -> (int * constr) list -> - context -> rawconstr -> unsafe_judgment + unsafe_env -> rawconstr -> unsafe_judgment val ise_resolve_type : bool -> 'c evar_map -> (int * constr) list -> - context -> rawconstr -> typed_type + unsafe_env -> rawconstr -> typed_type (* Call ise_resolve with empty metamap and fail_evar=true. The boolean says * if we must coerce to a type *) -val ise_resolve1 : bool -> 'c evar_map -> context -> rawconstr -> constr +val ise_resolve1 : bool -> 'c evar_map -> unsafe_env -> rawconstr -> constr (* progmach.ml tries to type ill-typed terms: does not perform the conversion * test in application. *) val ise_resolve_nocheck : 'c evar_map -> (int * constr) list -> - context -> rawconstr -> unsafe_judgment + unsafe_env -> rawconstr -> unsafe_judgment (* Internal of Trad... * Unused outside Trad, but useful for debugging *) -val pretype : bool * (constr option * constr option) -> 'c evar_map ref - -> context -> rawconstr -> unsafe_judgment +val pretype : bool * (constr option * constr option) + -> unsafe_env -> 'c evar_defs -> rawconstr -> unsafe_judgment |
