diff options
| author | herbelin | 2000-03-08 21:13:45 +0000 |
|---|---|---|
| committer | herbelin | 2000-03-08 21:13:45 +0000 |
| commit | 3d62a6ff0b7f79430da8af6773bf444b3e8cf3ce (patch) | |
| tree | 20a798816543dce407b5610b5b96ecc247bda1d7 | |
| parent | 7c3c494d795255c74b3deeae458802036d031eee (diff) | |
Un nouveau moteur pour Cases (phase 1)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@302 85f007b7-540e-0410-9357-904b9bb8a0f7
| -rw-r--r-- | pretyping/cases.ml | 2515 | ||||
| -rw-r--r-- | pretyping/cases.mli | 4 |
2 files changed, 760 insertions, 1759 deletions
diff --git a/pretyping/cases.ml b/pretyping/cases.ml index b44077234d..ad02ce58bf 100644 --- a/pretyping/cases.ml +++ b/pretyping/cases.ml @@ -1,23 +1,22 @@ -(* $Id$ *) - -open Pp open Util open Names -open Sign open Generic open Term open Inductive +open Environ +open Sign open Reduction -open Type_errors open Typeops -open Environ +open Type_errors + open Rawterm open Retyping -open Evarutil open Pretype_errors +open Evarutil (*********************************************************************) +(* A) Typing old cases *) (* This was previously in Indrec but creates existential holes *) let mkExistential isevars env = @@ -57,1760 +56,709 @@ let branch_scheme env isevars isrec i (mind,args as appmind) = norec_branch_scheme env isevars typc (************************************************************************) +(* Pattern-matching compilation (Cases) *) +(************************************************************************) -exception CasesError of env * type_error - -(* == General purpose functions == *) - -let starts_with_underscore id = - let s=string_of_id id in (String.get s 0)='_' - -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 - +(************************************************************************) +(* Configuration, errors and warnings *) +let substitute_alias = ref false -(* behaves as lam_and_popl_named but receives an environment instead of a - * dbenvironment - *) -let lam_and_pop_named env body acc_ids = - match env with - | [] -> error "lam_and_pop" - | (na,t)::tlenv -> - let id = match na with - | Anonymous -> next_ident_away (id_of_string "a") acc_ids - | Name id -> id - in - (tlenv,DOP2(Lambda,body_of_type t,DLAM((Name id),body)), - (id::acc_ids)) - -let lam_and_popl_named n env t = - let rec poprec = function - | (0, (env,b,_)) -> (env,b) - | (n, ([],_,_)) -> error "lam_and_popl" - | (n, (env,b,acc_ids)) -> poprec (n-1, lam_and_pop_named env b acc_ids) - in - poprec (n,(env,t,[])) +open Pp -let elam_and_popl_named n env body = - let ENVIRON(sign,dbenv)=env in - let ndbenv,a = lam_and_popl_named n dbenv body - in ENVIRON(sign,ndbenv),a +let error_bad_pattern_loc a = failwith "TODO1" - -let lambda_name env (n,a,b) = - mkLambda (named_hd env a n) a b -let prod_name env (n,a,b) = - mkProd (named_hd env a n) a b +let mssg_may_need_inversion () = + [< 'sTR "This pattern-matching is not exhaustive.">] +let mssg_this_case_cannot_occur () = + "This pattern-matching is not exhaustive." -(* General functions on inductive types *) +(* Utils *) let ctxt_of_ids ids = Array.of_list (List.map (function id -> VAR id) ids) - let constructor_of_rawconstructor (cstr_sp,ids) = (cstr_sp,ctxt_of_ids ids) - -let mutconstruct_of_rawconstructor c = - mkMutConstruct (constructor_of_rawconstructor c) let inductive_of_rawconstructor c = inductive_of_constructor (constructor_of_rawconstructor c) -let ith_constructor i mind = - mkMutConstruct (ith_constructor_of_inductive mind i) - -(* determines whether is a predicate or not *) -let is_predicate ind_data = (ind_data.nrealargs > 0) - -(* === Closures imported from trad.ml to perform typing === *) - -type 'a trad_functions = - { pretype : trad_constraint -> env -> rawconstr -> unsafe_judgment; - isevars : 'a evar_defs - } - -type 'a lifted = int * 'a - -type lfconstr = constr lifted - -let lift_lfconstr n (s,c) = (s+n,c) - -(* Partial check on patterns *) -let check_pat_arity env = function - | PatCstr (loc, (cstr_sp,ids as c), args, name) -> - let ity = inductive_of_rawconstructor c in - let nparams = mis_nparams (lookup_mind_specif ity env) in - let tyconstr = - type_of_constructor env Evd.empty (cstr_sp,ctxt_of_ids ids) in - let nb_args_constr = (nb_prod tyconstr) - nparams in - if List.length args <> nb_args_constr - then error_wrong_numarg_constructor_loc loc CCI cstr_sp nb_args_constr - | PatVar (_,_) -> () - -(* Usage of this function should be avoided, because it requires that the - * params are infered. - *) -let rec constr_of_pat isevars env = function - PatVar (_,Name id) -> VAR id - | PatVar (_,Anonymous) -> VAR (id_of_string "_") - (* invalid_arg "constr_of_pat"*) - | PatCstr(_,c,args,name) -> - let ity = inductive_of_rawconstructor c in - let mispec = Global.lookup_mind_specif ity in - let nparams = mis_nparams mispec in - let c = mutconstruct_of_rawconstructor c in - let exl = - list_tabulate - (fun _ -> - fst (new_isevar isevars env (mkCast dummy_sort dummy_sort) CCI)) - nparams in - applist(c, exl @ List.map (constr_of_pat isevars env) args) - - - -(* == Error messages == *) - -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_may_need_inversion () = - [< 'sTR "This pattern-matching is not exhaustive.">] - -(* eta-expands the term t *) - -let rec eta_expand0 env sigma n c t = - match whd_betadeltaiota env sigma t with - DOP2(Prod,a,DLAM(na,b)) -> - DOP2(Lambda,a,DLAM(na,eta_expand0 env sigma (n+1) c b)) - | _ -> applist (lift n c, rel_list 0 n) - - -let rec eta_expand env sigma c t = - match whd_betadeltaiota env sigma c, whd_betadeltaiota env sigma t with - | (DOP2(Lambda,ta,DLAM(na,cb)), DOP2(Prod,_,DLAM(_,tb))) -> - DOP2(Lambda,ta,DLAM(na,eta_expand env sigma cb tb)) - | (c, t) -> eta_expand0 env 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" - -(* 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 -*) - -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 list; - rhs : rhs} - -let row_current r = List.hd r.patterns -let pop_row_current patts = List.tl patts - - -(*---------------------------------------------------------------* - * 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. - *) - -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 = list_except id rhs.private_ids} - else if List.mem id rhs.user_ids & not (List.mem_assoc id rhs.subst) then - {rhs with subst = (id,t)::List.map (subst_in_subst id t) rhs.subst} - else anomaly ("Found a pattern variables neither private nor user supplied: " - ^(string_of_id id)) - - - - - - - -(* 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 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 *) -(* ====================================================== *) - - -(* 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 absolutize_hdname value rhs = function - | PatVar (_,Name id) -> replace_var_nolhs id value rhs - | PatVar (_,Anonymous) -> rhs - | _ -> anomalylabstrm "absolutize_alias" - [<'sTR "pattern should be a variable or an as-pattern">] - - -let pop_and_prepend_future lpatt patts = lpatt@(pop_row_current patts) - -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 * inductive_summary - | MayBeNotInd of constr * constr - -let to_mutind env sigma c t = - try IsInd (c,try_mutind_of env 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 } - -let gd_current gd = List.hd gd.tomatch -let pop_current gd = List.tl 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 = List.tl 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; - nrealargs=md.nrealargs; - 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 - *) +(* Environment management *) let push_rel_type sigma (na,t) env = push_rel (na,make_typed t (get_sort_of env sigma t)) env let push_rels vars env = List.fold_left (fun env nvar -> push_rel_type Evd.empty nvar env) env vars -let push_and_liftn_gd n vl (env, gd) = - (List.fold_right (push_rel_type Evd.empty) 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) - +(**********************************************************************) +(* Structures used in compiling pattern-matching *) +type 'a lifted = int * 'a -(* == Ops. pushing patterns to tomatch and lifting == *) +let insert_lifted a = (0,a);; -(* 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 - *) +(* INVARIANT: -let push_lpatt n t info (env,gd) = - 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" - in let tl,body,(nenv,ngd) = pushrec [] (n,t,(env,gd)) in - let ntomatch = - list_map_i - (fun i t -> (to_mutind env Evd.empty (Rel i) (liftn (n-i+1) n t), info)) 1 tl - in body, (nenv, - {ngd with tomatch=List.rev_append ntomatch ngd.tomatch}) + The pattern variables of it are the disjoint union of [user_ids] + and the domain of [subst]. Non global VAR in the codomain of [subst] are + in private_ids. + The non pattern variables of it + the global VAR in the codomain of + [subst] are in others_ids +*) +type rhs = + { rhs_env : env; + other_ids : identifier list; + private_ids: identifier list; + user_ids : identifier list; + subst : (identifier * constr) list; + rhs_lift : int; + it : rawconstr } -(* =============================================================== *) +type pattern_source = DefaultPat of int | RegularPat +type equation = + { dependencies : constr lifted list; + patterns : pattern list; + rhs : rhs; + tag : pattern_source } -(* 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 list_map_append dep tomatch +type matrix = equation list +type tomatch_type = + | IsInd of inductive_summary + | NotInd of constr -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 - | DOPN(Evar _,_) -> true - | _ -> false +type dependency_in_rhs = DepInRhs | NotDepInRhs +type dependency_on_previous = DepOnPrevious | NotDepOnPrevious +type dependency_status = dependency_on_previous * dependency_in_rhs -let is_for_mlcase p = hd_of_prodlam p +type pushed_attributes = (constr * tomatch_type) * dependency_in_rhs +type topush_attributes = (name * tomatch_type) * dependency_status -(* == functions for syntactic correctness test of patterns == *) +type tomatch_status = + | Pushed of pushed_attributes lifted + | ToPush of topush_attributes -let patt_are_var = - List.for_all - (fun r -> match row_current r with PatVar _ -> true |_ -> false) +type tomatch_stack = tomatch_status list +type predicate_signature = + | PrLetIn of (constr list * constr option) * predicate_signature + | PrProd of (bool * name * tomatch_type) * predicate_signature + | PrCcl of constr -let check_pattern (ind_sp,_ as ind) row = - match row_current row with - PatVar (_,id) -> () - | PatCstr (loc,(cstr_sp,ids),args,name) -> - if inductive_path_of_constructor_path cstr_sp <> ind_sp then - error_bad_constructor_loc loc CCI (cstr_sp,ctxt_of_ids ids) ind +(* A pattern-matching problem has the following form: -let check_patt_are_correct ity mat = List.iter (check_pattern ity) mat + env, isevars |- <pred> Cases tomatch of mat end -(*The only variables that patterns can share with the environment are - parameters of inductive definitions!. Thus patterns should also be - lifted when pushing inthe context. *) + where tomatch is some sequence (t1 ... tn) + and mat is some matrix + (p11 ... p1n -> rhs1) + ( ... ) + (pm1 ... pmn -> rhsm) -(* == Function dealing with constraints in compilation of dep case == *) + Terms to match: there are 3 kinds of terms to match -let xtra_tm = DOP0(XTRA("TMPATT")) -let is_xtra_tm tm = match tm with DOP0(XTRA("TMPATT")) -> true |_ -> false + - initials terms are arbitrary terms given by user and typed in [env] + - to-push inherited terms are subterms, actually variables, obtained + from the top-down analysis of pattern, they are typed in [env] + enriched by the previous inherited terms to match and are still to be + pushed in env + - pushed inherited terms are variables refering to a variable in [env] -(* represents the constraint cur=ci *) -let build_constraint cur ci = DOP2(XTRA("CONSTRAINT"),cur,ci) + A variable inherited from a subpattern is not immediately pushed in + [env] because of possible dependencies from previous variables to match -let top_constraint gd = - match (extract_lifted gd.pred) with - DOP2(Prod,(DOP2(XTRA("CONSTRAINT"),cur,ci)),_) -> true - | _ -> false + Right-hand-sides: + They consist of a raw term to type in an environment specific to the + clause they belong to: the names of declarations are those of the + variables present in the patterns. Therefore, they come with their + own [rhs_env] (actually it is the same as [env] except for the names + of variables). -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" [<>] +*) +type 'a pattern_matching_problem = + { env : env; + isevars : 'a evar_defs; + pred : predicate_signature option; + tomatch : tomatch_stack; + mat : matrix; + typing_function: trad_constraint -> env -> rawconstr -> unsafe_judgment } +(************************************************************************) +(* Utils *) -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 +let to_mutind env sigma t = + try IsInd (try_mutind_of env sigma t) + with Induc -> NotInd t +let type_of_tomatch_type = function + IsInd ind_data -> ind_data.fullmind + | NotInd t -> t -(* 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)) - *) +let current_pattern eqn = + match eqn.patterns with + | pat::_ -> pat + | [] -> anomaly "Empty list of patterns" -(* 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 next_env (* Hum *) Evd.empty 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 ith_constructor_of_inductive (ind_sp,args) i = (ind_sp,i),args - -(* Le type d'un constructeur est syntaxiquement de conclusion I(...), pas *) -(* de réduction à faire *) -let constructor_numargs ind_data i = - let (ind_sp,args) = ind_data.mind in - nb_prod (type_of_constructor (Global.env()) Evd.empty ((ind_sp,i),args)) - - ind_data.nparams - -type constructor_info = - {cstr_sp : constructor_path; - ctxt : constr array; - nargs : int; - args : (name * constr) list; - concl_realargs : constr list} - -(* let realargs_of_constructor_concl ... *) - -(* On identifie ici toutes les variables/alias intervenant dans les [args] - des clauses filtrant le constructeur [cstr_sp] qui nous intéresse *) -(* -let alias_of_pattern = function +let alias_of_pat = function | PatVar (_,name) -> name | PatCstr(_,_,_,name) -> name -let merge_names na p (l,rhs) = - match na,alias_of_pattern p with - | Name id, Anonymous -> na::l - tester si na n'existe pas déjà ailleurs dans rhs - | Anonymous, na -> na::l, rhs - | Name id1, Name id2 -> id1::l, replace_lvar_nolhs id2 (VAR id1) rhs - -let get_names_for_constructor_arg cstr_sp mat = - let egalize_names l row = - match row_current row with - | PatCstr(_,(cstr',_),largs,name) when cstr' = cstr_sp -> - List.fold_right2 merge_names l largs ([],row.rhs) - | PatVar _ | PatCstr _ -> (l,row) in - let anonymous_list = list_tabulate (fun _ -> Anonymous) n in - List.fold_left egalize_names anonymous_list mat -*) +let remove_current_pattern eqn = + match eqn.patterns with + | _::pats -> { eqn with patterns = pats } + | [] -> anomaly "Empty list of patterns" + +let liftn_ind_data n depth md = + let mind' = + let (ind_sp,ctxt) = md.mind in + (ind_sp, Array.map (liftn n depth) ctxt) in + { fullmind = liftn n depth md.fullmind; + mind = mind'; + nparams = md.nparams; + nrealargs = md.nrealargs; + nconstr = md.nconstr; + params = List.map (liftn n depth) md.params; + realargs = List.map (liftn n depth) md.realargs; + make_arity = md.make_arity; + make_constrs = md.make_constrs } + +let liftn_tomatch_type n depth = function + | IsInd ind_data -> IsInd (liftn_ind_data n depth ind_data) + | NotInd t -> NotInd (liftn n depth t) + +let lift_tomatch_type n = liftn_tomatch_type n 1 + +let lift_tomatch n ((current,typ),info) = + ((lift n current,lift_tomatch_type n typ),info) + +let substn_many_ind_data cv depth md = + let mind' = + let (ind_sp,ctxt) = md.mind in + (ind_sp, Array.map (substn_many cv depth) ctxt) in + { fullmind = substn_many cv depth md.fullmind; + mind = mind'; + nparams = md.nparams; + nrealargs = md.nrealargs; + nconstr = md.nconstr; + params = List.map (substn_many cv depth) md.params; + realargs = List.map (substn_many cv depth) md.realargs; + make_arity = md.make_arity; + make_constrs = md.make_constrs } + +let substn_many_tomatch v depth = function + | IsInd ind_data -> IsInd (substn_many_ind_data v depth ind_data) + | NotInd t -> NotInd (substn_many v depth t) + +let subst_tomatch (depth,c) = substn_many_tomatch [|make_substituend c|] depth + +(**********************************************************************) +(* Well-formedness tests *) +(* Partial check on patterns *) -let mychange_name_rel env current id = - match current with - (Rel j) -> - if starts_with_underscore id - then env - else change_name_rel env j id - | _ -> env - -let submat depcase isevars env i ind_data params current mat = -(* Futur... - let concl_realargs = realargs_of_constructor_concl ind_data i in - let constraints = matching concl_realargs ind_data.realargs in +let check_constructor loc ((_,j as cstr_sp,ids),args) mind cstrs = + (* Check it is constructor of the right type *) + if inductive_path_of_constructor_path cstr_sp <> fst mind + then error_bad_constructor_loc loc CCI (cstr_sp,ctxt_of_ids ids) mind; + (* Check the constructor has the right number of args *) + let nb_args_constr = cstrs.(j-1).cs_nargs in + if List.length args <> nb_args_constr + then error_wrong_numarg_constructor_loc loc CCI cstr_sp nb_args_constr + +let check_all_variables typ mat = + List.iter + (fun eqn -> match current_pattern eqn with + | PatVar (_,id) -> () + | PatCstr (loc,_,_,_) -> error_bad_pattern_loc loc CCI typ) + mat + +(**********************************************************************) +(* Functions to deal with matrix factorization *) +let occur_rawconstr id = + let rec occur = function + | RRef (loc,RVar id) -> true + | RApp (loc,f,args) -> (occur f) or (List.exists occur args) + | RBinder (loc,bk,na,ty,c) -> (occur ty) or ((na <> Name id) & (occur c)) + | RCases (loc,prinfo,tyopt,tml,pl) -> + (occur_option tyopt) or (List.exists occur tml) + or (List.exists occur_pattern pl) + | ROldCase (loc,b,tyopt,tm,bv) -> + (occur_option tyopt) or (occur tm) or (array_exists occur bv) + | RRec (loc,fk,idl,tyl,bv) -> + (array_exists occur tyl) or + (not (array_exists (fun id2 -> id=id2) idl) & array_exists occur bv) + | RCast (loc,c,t) -> (occur c) or (occur t) + | (RSort _ | RHole _ | RRef _ ) -> false + + and occur_pattern (idl,p,c) = not (List.mem id idl) & (occur c) + + and occur_option = function None -> false | Some p -> occur p + + in occur + +let occur_in_rhs na rhs = + match na with + | Anonymous -> false + | Name id -> occur_rawconstr id rhs.it + +let is_dep_patt eqn pat = occur_in_rhs (alias_of_pat pat) eqn.rhs + +let dependencies_in_rhs eqns = + let deps = List.map (fun (tms,eqn) -> List.map (is_dep_patt eqn) tms) eqns in + let columns = matrix_transpose deps in + List.map (List.for_all ((=) true)) columns + +(* Introduction of an argument of the current constructor must be + delayed (flag DepOnPrevious) if it depends in the rhs and depends + on a previous variable of inductive type, or on a previous variable + already dependent *) + +let rec is_dep_on_previous n t = function + | ((_,IsInd _),_)::_ when dependent (Rel n) t -> DepOnPrevious + | ((_,NotInd _),(DepOnPrevious,DepInRhs))::_ + when dependent (Rel n) t -> DepOnPrevious + | _::rest -> is_dep_on_previous (n+1) t rest + | [] -> NotDepOnPrevious + +let find_dependencies t prevlist is_dep_in_rhs = + if is_dep_in_rhs then (is_dep_on_previous 1 t prevlist,DepInRhs) + else (NotDepOnPrevious,NotDepInRhs) + +(******) + +(* A Pushed term to match has just been substituted by some + constructor t = (ci x1...xn) and the terms x1 ... xn have been added to + match + + - all terms to match and to push (dependent on t by definition) + must have (Rel depth) substituted by t and Rel's>depth lifted by n + - all pushed terms to match (non dependent on t by definition) must + be lifted by n + + We start with depth=1 + + We delay lift for Pushed but not for ToPush (trop complexe !) *) - let nbargs_iconstr = constructor_numargs ind_data i in - let ci = ith_constructor i ind_data.mind in - - let expand_row r = - let build_new_row subpatts name = - let lid = global_vars_rawconstr (context 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 (dummy_loc,Name id)) new_ids, - List.map (fun id -> VAR id) new_ids - | Some patts -> - patts, - List.map (constr_of_pat isevars env) patts in - let value = - if (is_predicate ind_data) or depcase - then applist (ci, params@largs) - else current in - let vars = match name with Anonymous -> [] | Name id -> [id] in - { dependencies=r.dependencies; - patterns = pop_and_prepend_future lpatt r.patterns; - rhs = replace_lvar_nolhs vars value r.rhs } in - - match row_current r with - | PatVar (_,name) -> - let envopt = match name with - | Anonymous -> None - | Name id -> Some (mychange_name_rel env current id) in - (envopt, [build_new_row None name]) - | PatCstr(_,c,largs,alias) when mutconstruct_of_rawconstructor 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" *) - let envopt = match alias with - | Anonymous -> None - | Name id -> Some (mychange_name_rel env current id) in - (envopt,[build_new_row (Some largs) alias]) - | PatCstr _ -> (None,[]) in - - let lenv,llrows = List.split (List.map expand_row mat) in - let lrows = List.concat llrows in - let lsome = List.filter (fun op -> op <> None) lenv in - let rnenv = - if lsome = [] then env - else out_some (List.hd lsome) - in rnenv, lrows - - -type status = - | Match_Current of (constr * inductive_summary * 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) - - -(* J'ai remplace strip_outer_cast par whd_castapp. A revoir. PAPAGENO 01/1999 -let whd_cast = strip_outer_cast -***********) - -let whd_cast = whd_castapp - -(* 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) = warning "solve_dep not implemented";[] -(* - let rec solve_args = function - [],[] -> [] - | (e1::l1), (e2::l2) -> - (match whd_cast e1 with - | (Rel i) -> ((Rel i), e2)::(solve_args (l1,l2)) - | _ -> - if e1 = whd_cast e2 then (solve_args (l1,l2)) - else error_needs_inversion CCI env x t) - | _ -> anomaly "solve_dep" in - try - let (ityt,argst)= find_mrectype env sigma t - and (itys,argss)= find_mrectype env 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) = list_chop nparams argst - and (params,largss) = list_chop 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 ci 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,_) = list_chop (n-1) dbenv in - let abs = lamn (n-1) (List.map (fun (na,t) -> na,body_of_type t) gamma2) mkImplicit - in dependent (Rel 1) abs - | _ -> false +let rec lift_subst_tomatch n (depth,ci as binder) = function + | [] -> [] + (* By definition ToPush terms depend on the previous substituted tm *) + (* and they contribute to the environment (hence [depth+1]) *) + | ToPush ((na,t),info)::rest -> + let t' = liftn_tomatch_type n (depth+1) t in + let t'' = subst_tomatch binder t' in + ToPush ((na,t''), info)::(lift_subst_tomatch n (depth+1,ci) rest) -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= list_chop 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) -> - mychange_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,_= list_chop j (List.rev branch_db) - in (ENVIRON(sign, List.rev rndb)) + (* By definition Pushed terms do not depend on previous terms to match *) + (* and are already pushed in the environment; *) + (* if all is correct, [c] has no variables < depth *) + | Pushed (lift,tm)::rest -> + Pushed (n+lift, tm)::(lift_subst_tomatch n binder rest) +let subst_in_subst id t (id2,c) = + (id2,replace_vars [(id,make_substituend t)] c) -let nf_ise_dependent sigma c t = dependent c (nf_ise1 sigma t) +let replace_id_in_rhs 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 = list_except id rhs.private_ids} + else if List.mem id rhs.user_ids & not (List.mem_assoc id rhs.subst) then + {rhs with subst = (id,t)::List.map (subst_in_subst id t) rhs.subst} + else anomaly ("Found a pattern variables neither private nor user supplied: " + ^(string_of_id id)) -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 +let replace_name_in_rhs name c rhs = + match name with + | Anonymous -> rhs + | Name id -> replace_id_in_rhs id c rhs +(* if [current] has type [I(p1...pn u1...um)] and we consider the case + of constructor [ci] of type [I(p1...pn u'1...u'm)], then the + default variable [name] is expected to have which type? + Rem: [current] is [(Rel i)] except perhaps for initial terms to match *) +let rec pop_next_tomatchs acc = function + | ToPush((na,t),(NotDepOnPrevious,_ as deps))::l -> + pop_next_tomatchs (((na,t),deps)::acc) l + | ((ToPush(_,(DepOnPrevious,_)) | Pushed _)::_ | []) as l -> (acc,l) +let expand_defaults pats current (name,eqn) = + { eqn with + patterns = pats @ eqn.patterns; + rhs = replace_name_in_rhs name current eqn.rhs } -(* 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 = - {dependencies = r.dependencies; - patterns = pop_row_current r.patterns; - rhs = absolutize_hdname value r.rhs (row_current r)} - - -(* t is the current tomatch (used for expanding as-patterns) *) -let shift_current_dep value r = - {dependencies = push (insert_lifted value) r.dependencies; - patterns = pop_row_current r.patterns; - rhs = absolutize_hdname value r.rhs (row_current r)} - - - -(* ========================================================================= - * 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) - *) +(************************************************************************) +(* Some heuristics to get names for variables pushed in pb environment *) -let arity_to_sign env ind_data = - let {params=params;arity=arity} = ind_data in - let arity0 = prod_applist arity params in - let sign,s = splay_prod env Evd.empty arity0 in - sign - -let abstracted_inductive sigma env ind_data = - let {mind=ity;params=params;nrealargs=m} = ind_data in - let asign = arity_to_sign env ind_data in - let sign = List.map (fun (na,t) -> (named_hd (Global.env()) t na,t)) asign in - - let params0 = List.map (lift m) params in - let args0 = rel_list 0 m in - let t = applist (mkMutInd ity, params0@args0) in - let na = named_hd (Global.env()) t Anonymous in - (na,t)::sign, {ind_data with params=params0;realargs=args0} - -(* 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 merge_names get_name = + List.map2 (fun obj na -> match na with + | Anonymous -> get_name obj + | _ -> na) -let abstract_arity env res = function - IsInd (current,ind_data) -> - let sign = arity_to_sign env ind_data in - (ind_data.nrealargs, lam_it (lift ind_data.nrealargs res) sign) - | MayBeNotInd (_,_) -> 0,res - - - -(* =============================================== *) -(* for mlcase *) -(* =============================================== *) - -(* 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.uj_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 env (pred,ltm) = - let rec abst = function - [] -> pred - | (tj::ltm) -> snd (abstract_arity env (abst ltm) tj) - in abst ltm - -let info_abstract_pred_lterms env (pred,ltm) = - let rec abst linfo = function - [] -> linfo,pred - | (tj::ltm) -> - let linfo,res = abst linfo ltm in - let k,nres = abstract_arity env 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 sigma pred = function - | IsInd (c,ind_data) -> whd_beta env sigma (applist (pred,ind_data.realargs)) - | MayBeNotInd (c,t) -> pred - -(* == Special functions to deal with mlcase on objects of dependent types == *) - -(* analogue strategy as Christine's MLCASE *) -let find_implicit_pred isevars ith_branch_builder env (current,ind_data,_) = - let {nconstr=nconstr;mind=mind;params=params;realargs=realargs} = ind_data in - let isrec = false in - let rec findtype i = - if i > nconstr then raise (CasesError (env, CantFindCaseType current)) - else - try - (let expti = branch_scheme env isevars isrec i (mind,params) in - let _,bri= ith_branch_builder i in - let fi = bri.uj_type in - let efit = nf_ise1 !isevars fi in - let pred = - Indrec.pred_case_ml_onebranch env !isevars isrec - (current,(mind,params,realargs)) (i,bri.uj_val,efit) in - if has_ise !isevars pred then error"isevar" else pred) - with UserError _ -> findtype (i+1) - in findtype 1 - -(* =============================================== *) -(* Strategies for building elimination predicates *) -(* =============================================== *) -(* we build new predicate p for elimination - * by 0-splitting (we use inheritance or synthesis) - *) +let get_names env sign eqns = + let names1 = list_tabulate (fun _ -> Anonymous) (List.length sign) in + (* If any, we prefer names used in pats, from top to bottom *) + let names2 = + List.fold_right + (fun (pats,eqn) names -> merge_names alias_of_pat pats names) + eqns names1 in + (* Otherwise, we take names from the parameters of the constructor *) + let names3 = merge_names (fun (na,t) -> named_hd env t na) sign names2 in + (* Then we rename the base names to avoid conflicts *) + let allvars = + List.fold_left (fun l (_,eqn) -> list_union l eqn.rhs.other_ids) [] eqns in + let names4,_ = + List.fold_left + (fun (l,avoid) na -> + let id = next_name_away na avoid in + ((Name id)::l,id::avoid)) ([],allvars) names3 in + List.rev names4 -(* 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.">] +(************************************************************************) +(* Recovering names for variables pushed to the rhs' environment *) +let rec recover_pat_names = function + | (_,t)::sign,p::pats -> (alias_of_pat p,t)::(recover_pat_names (sign,pats)) + | [],_ -> [] + | _,[] -> anomaly "Cases.recover_pat_names: Not enough patterns" -let build_predicate isevars env (current,ind_data,info) gd = - let tl_tm = List.tl gd.tomatch in - let n = ind_data.nrealargs in +let push_rels_eqn sign eqn = + let sign' = recover_pat_names (List.rev sign, eqn.patterns) in + {eqn with + rhs = {eqn.rhs with + rhs_env = push_rels sign' eqn.rhs.rhs_env} } -(* 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 = lamn n env0 (whd_beta env Evd.empty (applist (pred0,depargs))) - in (p,next_pred) - - else begin - if n<>0 & info=SYNT then - errorlabstrm "build_dep_predicate" (mssg_nested_dep_patt env gd.mat); - let npred = to_lambda (n+1) (extract_lifted gd.pred) - in npred,npred - end - +let prepend_pattern tms eqn = {eqn with patterns = tms@eqn.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 substitute_rhs current pb = + if !substitute_alias then { pb with subst = current::pb.subst } else pb *) - - - -(* =================================== *) -(* Principal functions *) -(* =================================== *) -let type_one_branch dep env sigma ind_data p im = - let i = im + 1 in - let {mind=ity;params=params;nparams=nparams} = ind_data in - let ct = - type_of_constructor env sigma (ith_constructor_of_inductive ity i) in - let rec typrec n c = - match whd_betadeltaiota env sigma c with - | DOP2(Prod,a1,DLAM(x,a2)) -> DOP2(Prod,a1,DLAM(x,typrec (n+1) a2)) - | x -> let lAV = destAppL(ensure_appl x) in - let (_,vargs) = array_chop (nparams+1) lAV in - let c1 = appvect (lift n p,vargs) in - if dep then - let co = ith_constructor i ind_data.mind in - applist - (c1,[applist(co,((List.map (lift n) params)@(rel_list 0 n)))]) - else c1 - in - typrec 0 (hnf_prod_applist env sigma "type_case" ct params) - -let find_type_case_branches sigma env dep ind_data p = - let {nconstr=nconstr;mind=ity;params=params} = ind_data in - Array.init nconstr (type_one_branch dep env sigma ind_data p) - -(* -let my_norec_branch_scheme env sigma i ind_data = - let typc = type_inst_construct env sigma i (mutind_to_ind mind) in - let rec typrec n typc = - match whd_betadeltaiota env sigma typc with - DOP2(Prod,c,DLAM(name,t)) -> DOP2(Prod,c,DLAM(name,typrec (n+1) t)) - | x -> let lAV = destAppL(ensure_appl x) in - let (_,vargs) = array_chop (nparams+1) lAV in - appvect (lift n p,vargs) - in - typrec 0 (hnf_prod_applist env sigma "type_case" t globargs) - -let find_type_case_branches isevars 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 = get_type_of env !isevars p in - - let evalpt = nf_ise1 !isevars pt in - let (_,bty,_)= type_case_branches env !isevars ct evalpt p current - in bty +let pop_pattern eqn = { eqn with patterns = List.tl eqn.patterns } + +(**********************************************************************) +(* Functions to deal with elimination predicate *) + +(* Infering the predicate *) +let prepare_unif_pb typ cs = + let n = cs.cs_nargs in + let (sign,p) = decompose_prod_n n typ in + + (* We may need to invert ci if its parameters occur in p *) + let p' = + if noccur_bet 1 n p then lift (-n) p + else failwith "TODO4-1" in + let ci = applist + (mkMutConstruct cs.cs_cstr, cs.cs_params@(rel_list (-n) n)) in + + (* This is the problem: finding P s.t. cs_args |- (P realargs ci) = p' *) + (Array.map (lift (-n)) cs.cs_concl_realargs, ci, p') + +let infer_predicate typs cstrs ind_data = + let eqns = array_map2 prepare_unif_pb typs cstrs in + + (* First strategy: no dependencies at all *) + let (cclargs,_,typn) = eqns.(ind_data.nconstr -1) in + if array_for_all (fun (_,_,typ) -> eq_constr typn typ) eqns + then + let (sign,_) = ind_data.make_arity ind_data.mind ind_data.params in + let pred = lam_it (lift (List.length sign) typn) sign in + (false,pred) (* true = dependent -- par défaut *) else - let build_branch i = my_norec_branch_scheme env isevars 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 - *) - -(**************************************************************************) + failwith "TODO4-2" + +(* Propagation of user-provided predicate through compilation steps *) + +let lift_predicate n pred = + let rec liftrec k = function + | PrCcl ccl -> PrCcl (liftn n k ccl) + | PrProd ((dep,na,t),pred) -> + PrProd ((dep,na,liftn_tomatch_type n k t), liftrec (k+1) pred) + | PrLetIn ((args,copt),pred) -> + let args' = List.map (liftn n k) args in + let copt' = option_app (liftn n k) copt in + PrLetIn ((args',copt'), liftrec (k+1) pred) in + liftrec 1 pred + +let subst_predicate (args,copt) pred = + let sigma = match copt with + | None -> Array.map make_substituend (Array.of_list args) + | Some c -> Array.map make_substituend (Array.of_list (args@[c])) in + let rec substrec k = function + | PrCcl ccl -> PrCcl (substn_many sigma k ccl) + | PrProd ((dep,na,t),pred) -> + PrProd ((dep,na,substn_many_tomatch sigma k t), substrec (k+1) pred) + | PrLetIn ((args,copt),pred) -> + let args' = List.map (substn_many sigma k) args in + let copt' = option_app (substn_many sigma k) copt in + PrLetIn ((args',copt'), substrec (k+1) pred) in + substrec 0 pred + +let specialize_predicate_var = function + | PrProd _ | PrCcl _ -> + anomaly "specialize_predicate_var: a pattern-variable must be pushed" + | PrLetIn (tm,pred) -> subst_predicate tm pred + +let rec weaken_predicate n pred = + if n=0 then pred else match pred with + | PrLetIn _ | PrCcl _ -> + anomaly "weaken_predicate: only product can be weakened" + | PrProd ((dep,_,IsInd ind_data),pred) -> + (* To make it more uniform, we apply realargs but they not occur! *) + let tm = (ind_data.realargs,if dep then Some (Rel n) else None) in + PrLetIn (tm, weaken_predicate (n-1) + (lift_predicate ind_data.nrealargs pred)) + | PrProd ((dep,_,NotInd t),pred) -> + let tm = ([],if dep then Some (Rel n) else None) in + PrLetIn (tm, weaken_predicate (n-1) pred) + +let rec extract_predicate = function + | PrProd ((_,na,t),pred) -> + mkProd na (type_of_tomatch_type t) (extract_predicate pred) + | PrLetIn ((args,Some c),pred) -> substl (args@[c]) (extract_predicate pred) + | PrLetIn ((args,None),pred) -> substl args (extract_predicate pred) + | PrCcl ccl -> ccl + +let abstract_predicate ind_data = function + | PrProd _ | PrCcl _ -> anomaly "abstract_predicate: must be some LetIn" + | PrLetIn ((_,copt),pred) -> + let asign,_ = ind_data.make_arity ind_data.mind ind_data.params in + let sign = + List.map (fun (na,t) -> (named_hd (Global.env()) t na,t)) asign in + let dep = copt<> None in + let sign' = + if dep then + let ind = build_dependent_inductive ind_data in + let na = named_hd (Global.env()) ind Anonymous in + (na,ind)::sign + else sign in + (dep, lam_it (extract_predicate pred) sign') + +let specialize_predicate_match tomatchs cs = function + | PrProd _ | PrCcl _ -> + anomaly "specialize_predicate_match: a matched pattern must be pushed" + | PrLetIn ((args,copt),pred) -> + let argsi = Array.to_list cs.cs_concl_realargs in + let copti = option_app (fun _ -> build_dependent_constructor cs) copt in + let pred' = subst_predicate (argsi, copti) pred in + let pred'' = lift_predicate cs.cs_nargs pred' in + let dep = (copt <> None) in + List.fold_right + (* Ne perd-on pas des cas en ne posant pas true à la place de dep ? *) + (fun ((na,t),_) p -> PrProd ((dep,na,t),p)) tomatchs pred'' + +let find_predicate p typs cstrs current ind_data = + let (dep,pred) = + match p with + | Some p -> abstract_predicate ind_data p + | None -> infer_predicate typs cstrs ind_data in + let typ = applist (pred, ind_data.realargs) in + if dep then (pred, applist (typ, [current]), dummy_sort) + else (pred, typ, dummy_sort) -(* 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,[] +(************************************************************************) +(* Sorting equation by constructor *) + +type inversion_problem = + (* the discriminating arg in some Ind and its order in Ind *) + | Incompatible of int * (int * int) + | Constraints of (int * constr) list + +let solve_constraints constr_info ind_data = + (* TODO *) + Constraints [] + +let group_equations mind cstrs mat = + let brs = Array.create (Array.length cstrs) [] in + let dflt = ref [] in + let _ = + List.fold_left (* To be sure it's from bottom to top *) + (fun () eqn -> + let rest = remove_current_pattern eqn in + match current_pattern eqn with + | PatVar (_,name) -> dflt := (name,rest) :: !dflt + | PatCstr(loc,((ind_sp,i),ids as cstr),largs,alias) -> + check_constructor loc (cstr,largs) mind cstrs; + brs.(i-1) <- (largs,rest) :: brs.(i-1)) () mat in + (brs,!dflt) + +let pattern_status defaults eqns = + if eqns <> [] then RegularPat 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) - - -(* ---------------------------------------------------------*) - - + let min = + List.fold_right + (fun (_,eqn) n -> match eqn with + | {tag = DefaultPat i} when i<n -> i + | _ -> n) + defaults 0 in + DefaultPat min +(************************************************************************) +(* Here start the pattern-matching compiling algorithm *) -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 sigma env ind_data brj = - let m = ind_data.nrealargs in - let sign,_ = abstracted_inductive sigma env ind_data in - {uj_val = lam_it (lift (m+1) brj.uj_val) sign; - uj_type = prod_it (lift (m+1) brj.uj_type) sign; - uj_kind = brj.uj_kind} - - - -(* *) -let check_if_may_need_dep_elim sigma current gd = - let tl_tm = List.tl 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 env sigma nparams - (type_of_constructor env sigma - (ith_constructor_of_inductive ity i)) in - let l,_ = splay_prod env sigma ty in - let lpatt = List.map (fun (na,ty) -> (to_mutind env sigma xtra_tm ty,SYNT)) l in - let ngd = pop_and_prepend_tomatch lpatt gd in - let ci_param = applist (ith_constructor i ind_data.mind, params) in - - let rnnext_env0,next_mat = submat ngd.case_dep trad.isevars 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 next_gd.tomatch = [] - then body_br (* all the generalisations done in the elimination predicate - * have been consumed *) - else let (_,nextinfo) = List.hd 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 - !(trad.isevars) rnnext_env0 ind_data body_br - in - let rnnext_env = common_prefix_ctxt (context env) brenv in - rnnext_env, - {uj_val=eta_reduce_if_rel branch.uj_val;uj_type=branch.uj_type;uj_kind=branch.uj_kind} - -(* 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;nrealargs=n} = ind_data in - let k = constructor_numargs ind_data i 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 sign,nind_data = abstracted_inductive !(trad.isevars) env ind_data in - let env1 = push_rels sign env in - let relargs = ind_data.realargs@[current] in - let nrelargs = n+1 in - (* we lift predicate and type branch w.r.t. to pushed arguments *) - let curgd = lift_gd nrelargs gd in - let lpred = lift_lfconstr nrelargs (insert_lifted next_pred) in - (env1, 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) = - push_lpatt k nbty SYNT - (nenv, - {case_dep= ncurgd.case_dep; - pred= npred; - deptm = ncurgd.deptm; - tomatch = List.tl ncurgd.tomatch; - mat = ncurgd.mat}) in - let nncur = lift k ncur in - let lp = List.map (lift k) params in - let ci = applist (ith_constructor i ind_data.mind, lp@(rel_list 0 k)) in - - let rnnext_env0,next_mat=submat ngd.case_dep trad.isevars next_env i - ind_data lp nncur 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 env !(trad.isevars) (appvect (extract_lifted ngd.pred, dep_ci)) in - let ciargs_patt = List.map fst (fst (list_chop 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 env (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 = list_chop 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 (nncur, 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 (context next_env) brenv in - let branchenv,localenv = list_chop k (get_rels rnnext_env) in - let branchenv = List.map (fun (na,t) -> (na,incast_type t)) branchenv in - (* Avant ici, on nommait les Anonymous *) - let branchval = lam_it body_br.uj_val branchenv in - let branchtyp = prod_it body_br.uj_type branchenv in - ENVIRON(get_globals rnnext_env, localenv), - {uj_val=branchval;uj_type=branchtyp;uj_kind=body_br.uj_kind} - - in - - (* we restablish initial current by abstracting and applying *) - let p = List.length ncurargs in - let _,localenv = list_chop p (get_rels final_env) in - (* Avant ici, on nommait les Anonymous *) - let app = substl ncurargs final_branch.uj_val in - let typ = substl ncurargs final_branch.uj_type in - ENVIRON(get_globals final_env, localenv), - {uj_val = eta_reduce_if_rel app; - uj_type = typ; - uj_kind = final_branch.uj_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 = List.tl gd.tomatch in - - (* we build new predicate p for elimination *) - let (p,next_pred) = - build_predicate !(trad.isevars) env cji gd in - - (* we build the branches *) - let bty = find_type_case_branches !(trad.isevars) env false ind_data 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 *) - (context env), - mkMutCaseA (ci_of_mind (mkMutInd ity)) - (eta_reduce_if_rel p) current [||] - - | (bre1,f)::lenv_f as brl -> - let lfj = Array.of_list (List.map snd brl) in - let lf = Array.map (fun j -> j.uj_val) lfj in - let lft = Array.map (fun j -> j.uj_type) lfj in - let rec check_conv i = - if i = nconstr then () else - if not (Evarconv.the_conv_x_leq env trad.isevars lft.(i) bty.(i)) - then - let c = nf_ise1 !(trad.isevars) current - and lfi = nf_betaiota env !(trad.isevars) (nf_ise1 !(trad.isevars) lft.(i)) in - error_ill_formed_branch CCI env c i lfi (nf_betaiota env !(trad.isevars) bty.(i)) - else check_conv (i+1) - in - check_conv 0; - (common_prefix_ctxt (context env) bre1, - mkMutCaseA (ci_of_mind (mkMutInd ity)) - (eta_reduce_if_rel (nf_ise1 !(trad.isevars) p)) - current lf) in - newenv, - {uj_val = v; - uj_type = whd_beta env !(trad.isevars) (applist (p,realargs)); - uj_kind = sort_of_arity env Evd.empty 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_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 true ind_data 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 -> - (snd (build_ith_branch nenv ngd1 i)).uj_val) - (interval 1 nconstr) in - let case_exp = - mkMutCaseA (ci_of_mind (mkMutInd ity)) (eta_reduce_if_rel np) - current (Array.of_list lf) in - let (na,ty),_ = uncons_rel_env (context nenv) in - let rescase = lambda_name env (na,body_of_type ty,case_exp) in - let casetyp = whd_beta nenv !(trad.isevars) (applist (np,args)) in - (context 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 -> - (snd (build_ith_branch nenv ngd1 i)).uj_val) - (interval 1 nconstr) in - let rescase = mkMutCaseA (ci_of_mind (mkMutInd ity)) - (eta_reduce_if_rel np) current (Array.of_list lf) in - let casetyp = whd_beta nenv !(trad.isevars) (applist (np,args)) in - (context 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 -> - (snd (build_ith_branch nenv1 ngd2 i)).uj_val) - (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 (mkMutInd ity)) np1 (Rel 1) (Array.of_list lf) in - let nenv2,rescase = elam_and_popl_named n (context nenv1) case_exp in - let casetyp = whd_beta nenv1 !(trad.isevars) (applist (np,args@[(Rel 1)])) in - nenv2,rescase,casetyp - - in - nenv, - {uj_val = rescase; - uj_type = casetyp; - uj_kind = sort_of_arity env Evd.empty 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 !(trad.isevars) pred0 cur - in insert_lifted pred1 in - -(* Je ne comprends pas à quoi sert la distinction dep ou pas car il n'y a ici - que des variables *) - 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_dep (term_tomatch cur)) 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 (context 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 env ((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 (context 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) = List.hd gd.tomatch in - let (ty,v,npred) = - match get_n_prod 1 (extract_lifted gd.pred) with - ([_,ty as v], npred) -> (ty,v,npred) - | _ -> assert false in - let nenv,ngd = push_and_lift_gd v (env,gd) in - let ncur = (Rel 1) in - let ntm = List.tl ngd.tomatch in - let next_gd = {case_dep= gd.case_dep; - pred = insert_lifted npred; - deptm = ngd.deptm; - tomatch = [(to_mutind env !(trad.isevars) ncur 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 = lambda_name env (na,incast_type ty,body.uj_val) in - let nbodytyp = prod_name env (na,incast_type ty,body.uj_type) in - let (nbodyval,nbodytyp) = - if info=INH_FIRST then - (applist(nbodyval,[term_tomatch curj]), - subst1 (term_tomatch curj) body.uj_type) - else (nbodyval,nbodytyp) in - (nenv1, {uj_val=nbodyval;uj_type=nbodytyp;uj_kind=body.uj_kind}) - -and build_leaf trad env gd = - match gd.mat with +(* No more patterns: typing the right-hand-side of equations *) +let build_leaf pb = + match pb.mat with | [] -> errorlabstrm "build_leaf" (mssg_may_need_inversion()) | _::_::_ -> errorlabstrm "build_leaf" [<'sTR "Some clauses are redondant" >] | [row] -> let rhs = row.rhs in +(* if List.length rhs.user_ids <> List.length rhs.subst then - anomaly "Some user pattern variables has not been substituted"; + anomaly "Some user pattern variable has not been substituted"; +*) if rhs.private_ids <> [] then - anomaly "Some private pattern variables has not been substituted"; - let j = trad.pretype (mk_tycon (extract_lifted gd.pred)) env rhs.it in - - let subst = List.map (fun id -> (id,make_substituend (List.assoc id rhs.subst))) rhs.user_ids in - let judge = - {uj_val = substitute_dependencies (replace_vars subst j.uj_val) - (gd.deptm, row.dependencies); - uj_type = substitute_dependencies (replace_vars subst j.uj_type) - (gd.deptm, row.dependencies); - uj_kind = j.uj_kind} in - (context 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 (mkMutInd ity,(List.map (lift n) params) - @(rel_list 0 ind_data.nrealargs)), - lift n (whd_beta env !isevars (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 Evd.empty 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 + anomaly "Some private pattern variable has not been substituted"; + let tycon = match pb.pred with + | None -> empty_tycon + | Some (PrCcl typ) -> mk_tycon typ + | Some _ -> anomaly "not all parameters of pred have been consumed" in + let j = pb.typing_function tycon rhs.rhs_env rhs.it in + let subst = (*List.map (fun id -> (id,make_substituend (List.assoc id rhs.subst))) rhs.user_ids *)[] in + {uj_val = replace_vars subst j.uj_val; + uj_type = replace_vars subst j.uj_type; + uj_kind = j.uj_kind} + +(* Building the sub-problem when all patterns are variables *) +let shift_problem pb = + (* rhs have alr. the right env: we just have to pop a pattern & cook pred *) + {pb with + pred = option_app specialize_predicate_var pb.pred; + mat = List.map pop_pattern pb.mat } + +(* Building the sub-pattern-matching problem for a given branch *) +let build_branch pb defaults current eqns const_info = + let names = get_names pb.env const_info.cs_args eqns in + let newpats = + if !substitute_alias then + List.map (fun na -> PatVar (dummy_loc,na)) names + else + List.map (fun _ -> PatVar (dummy_loc,Anonymous)) names in + let submatdef = List.map (expand_defaults newpats current) defaults in + let submat = List.map (fun (tms,eqn) -> prepend_pattern tms eqn) eqns in + if submat = [] & submatdef = [] then error "Non exhaustive"; + let typs = List.map2 (fun (_,t) na -> (na,t)) const_info.cs_args names in + let tomatchs = + List.fold_left2 + (fun l (na,t) dep_in_rhs -> + ((na,to_mutind pb.env !(pb.isevars) t), + (find_dependencies t l dep_in_rhs))::l) + [] typs (dependencies_in_rhs eqns) in + let topushs = List.map (fun x -> ToPush x) tomatchs in + (* The dependent term to subst in the types of the remaining UnPushed + terms is relative to the current context enriched by topushs *) + let ci = + applist + (mkMutConstruct const_info.cs_cstr, + (List.map (lift const_info.cs_nargs) const_info.cs_params) + @(rel_list 0 const_info.cs_nargs)) in + + (* We replace [(Rel 1)] by its expansion [ci] *) + let updated_old_tomatch = + lift_subst_tomatch const_info.cs_nargs (1,ci) pb.tomatch in + { pb with + tomatch = topushs@updated_old_tomatch; + mat = submat@submatdef; + pred = option_app (specialize_predicate_match tomatchs const_info) pb.pred } + +(********************************************************************** + INVARIANT: + + pb = { env, subst, tomatch, mat, ...} + tomatch = list of Pushed (c:T) or ToPush (na:T) or Initial (c:T) + + "Pushed" terms and types are relative to env + "ToPush" types are relative to env enriched by the previous terms to match + + Concretely, each term "c" or type "T" comes with a delayed lift + index, but it works as if the lifting were effective. *) -let build_expected_arity isdep env sigma tomatchl sort = - let cook n = function - | IsInd(c,({mind=ity;params=params;realargs=args;arity=arity} as ind_data)) - -> (applist (mkMutInd ity,(List.map (lift n) params) - @(rel_list 0 ind_data.nrealargs)), - lift n (whd_beta env sigma (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 env sigma 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 loc predj tomatchj = - let nb_dep_ity = function - IsInd (_,ind_data) -> ind_data.nrealargs - | MayBeNotInd (c,t) -> errorlabstrm "case_dependent" - (error_case_not_inductive CCI env c t) - in - let etapred = eta_expand env sigma predj.uj_val predj.uj_type in - let n = nb_lam etapred in - let _,sort = decomp_prod env sigma predj.uj_type in - let ndepv = List.map nb_dep_ity tomatchj in - let sum = List.fold_right (fun i j -> i+j) ndepv 0 in - let depsum = sum + List.length tomatchj in - if n = sum then (false,build_expected_arity true env sigma tomatchj sort) - else if n = depsum - then (true,build_expected_arity true env sigma tomatchj sort) - else error_wrong_predicate_arity_loc loc CCI env etapred sum depsum +(**********************************************************************) +(* Main compiling descent *) +let rec compile pb = + match pb.tomatch with + | (Pushed cur)::rest -> match_current { pb with tomatch = rest } cur + | (ToPush next)::rest -> compile_further pb next rest + | [] -> build_leaf pb + +and match_current pb (n,tm) = + let ((current,typ),info) = lift_tomatch n tm in + match typ with + | NotInd typ -> + check_all_variables typ pb.mat; + compile (shift_problem pb) + | IsInd ind_data -> + let cstrs = ind_data.make_constrs ind_data.mind ind_data.params in + let eqns,defaults = group_equations ind_data.mind cstrs pb.mat in + if array_for_all ((=) []) eqns + then compile (shift_problem pb) + else + let constraints = Array.map (solve_constraints ind_data) cstrs in + let pbs = + array_map2 (build_branch pb defaults current) eqns cstrs in + let tags = Array.map (pattern_status defaults) eqns in + let brs = Array.map compile pbs in + let brvals = Array.map (fun j -> j.uj_val) brs in + let brtyps = Array.map (fun j -> j.uj_type) brs in + let (pred,typ,s) = + find_predicate pb.pred brtyps cstrs current ind_data in + { uj_val = mkMutCaseA (ci_of_mind (mkMutInd ind_data.mind (*,tags*))) + (*eta_reduce_if_rel*) pred current brvals; + uj_type = typ; + uj_kind = s } + +and compile_further pb firstnext rest = + (* We pop as much as possible tomatch not dependent one of the other *) + let nexts,future = pop_next_tomatchs [firstnext] rest in + (* the next pattern to match is at the end of [nexts], it has ref (Rel n) + where n is the length of nexts *) + let sign = List.map (fun ((na,t),_) -> (na,type_of_tomatch_type t)) nexts in + let currents = + list_map_i + (fun i ((na,t),(_,rhsdep)) -> + Pushed (insert_lifted ((Rel i, lift_tomatch_type i t), rhsdep))) + 1 nexts in + let pb' = { pb with + env = push_rels sign pb.env; + tomatch = List.rev_append currents future; + pred= option_app (weaken_predicate (List.length sign)) pb.pred; + mat = List.map (push_rels_eqn sign) pb.mat } in + let j = compile pb' in + { uj_val = lam_it j.uj_val sign; + uj_type = prod_it j.uj_type sign; + uj_kind = j.uj_kind } + + +(* pour les alias des initiaux, enrichir les env de ce qu'il faut et +substituer après par les initiaux *) +(**************************************************************************) +(* Preparation of the pattern-matching problem *) (* builds the matrix of equations testing that each row has n patterns * and linearizing the _ patterns. * 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 env) lpatt; - { dependencies = []; - patterns = 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 } - - +let matx_of_eqns env eqns = + let build_eqn (ids,lpatt,rhs) = + let rhs = + { rhs_env = env; + other_ids = ids@(ids_of_sign (get_globals (context env))); + private_ids = []; + user_ids = ids; + subst = []; + rhs_lift = 0; + it = rhs } + in { dependencies = []; + patterns = lpatt; + tag = RegularPat; + rhs = rhs } + in List.map build_eqn eqns (*--------------------------------------------------------------------------* * A few functions to infer the inductive type from the patterns instead of * @@ -1832,10 +780,6 @@ let rec find_row_ind = function * 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)) - exception NotCoercible let inh_coerce_to_ind isevars env ty tyi = @@ -1854,99 +798,156 @@ let inh_coerce_to_ind isevars env ty tyi = else raise NotCoercible -let coerce_row trad env row tomatch = - let j = trad.pretype mt_tycon env tomatch in - match find_row_ind row with - Some (cloc,(cstr,_ as c)) -> - (let tyi = inductive_of_rawconstructor c in - try - let indtyp = inh_coerce_to_ind trad.isevars env j.uj_type tyi in - IsInd (j.uj_val,try_mutind_of env !(trad.isevars) j.uj_type) +let coerce_row typing_fun isevars env row tomatch = + let j = typing_fun empty_tycon env tomatch in + let t = + match find_row_ind row with + Some (cloc,(cstr,_ as c)) -> + (let tyi = inductive_of_rawconstructor c in + try + let indtyp = inh_coerce_to_ind isevars env j.uj_type tyi in + IsInd (try_mutind_of env !isevars j.uj_type) with NotCoercible -> (* 2 cas : pas le bon inductive ou pas un inductif du tout *) try - let ind_data = try_mutind_of env !(trad.isevars) j.uj_type in + let ind_data = try_mutind_of env !isevars j.uj_type in error_bad_constructor_loc cloc CCI (constructor_of_rawconstructor c) ind_data.mind with Induc -> error_case_not_inductive_loc (loc_of_rawconstr tomatch) CCI env j.uj_val j.uj_type) - | None -> - try IsInd (j.uj_val,try_mutind_of env !(trad.isevars) j.uj_type) - with Induc -> MayBeNotInd (j.uj_val,j.uj_type) - + | None -> + try IsInd (try_mutind_of env !isevars j.uj_type) + with Induc -> NotInd (j.uj_type) + in (j.uj_val,t) -let coerce_to_indtype trad env matx tomatchl = +let coerce_to_indtype typing_fun isevars env matx tomatchl = let pats = List.map (fun r -> r.patterns) 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 + List.map2 + (coerce_row typing_fun isevars env) + (matrix_transpose pats) tomatchl + +(***********************************************************************) +(* preparing the elimination predicate if any *) + +let build_expected_arity isdep tomatchl sort = + let cook n = function + | _,IsInd ind_data -> + (build_dependent_inductive ind_data, + fst (ind_data.make_arity ind_data.mind ind_data.params)) + | _,NotInd _ -> anomaly "Should have been catched in case_dependent" + in + let rec buildrec n = function + | [] -> sort + | tm::ltm -> + let (ty1,aritysign) = cook n tm in + let rec follow n = function + | (na,ty2)::sign -> DOP2(Prod,lift n ty2,DLAM(na,follow (n+1) sign)) + | _ -> + if isdep then DOP2(Prod,ty1,DLAM(Anonymous,buildrec (n+1) ltm)) + else buildrec n ltm + in follow n (List.rev aritysign) + in buildrec 0 tomatchl + +let build_initial_predicate isdep pred tomatchl = + let cook n = function + | _,IsInd ind_data -> + let args = List.map (lift n) ind_data.realargs in + if isdep then + let ty = lift n (build_dependent_inductive ind_data) in + (ind_data.nrealargs+1, (args,Some ty)) + else + (ind_data.nrealargs, (args,None)) + | _,NotInd _ -> anomaly "Should have been catched in case_dependent" + in + let rec buildrec n pred = function + | [] -> PrCcl pred + | tm::ltm -> + let (nargs,args) = cook n tm in + PrLetIn (args,buildrec (n+nargs) (snd(decompose_lam_n nargs pred)) ltm) + in buildrec 0 pred tomatchl + +let rec eta_expand0 env sigma n c t = + match whd_betadeltaiota env sigma t with + DOP2(Prod,a,DLAM(na,b)) -> + DOP2(Lambda,a,DLAM(na,eta_expand0 env sigma (n+1) c b)) + | _ -> applist (lift n c, rel_list 0 n) + + +let rec eta_expand env sigma c t = + match whd_betadeltaiota env sigma c, whd_betadeltaiota env sigma t with + | (DOP2(Lambda,ta,DLAM(na,cb)), DOP2(Prod,_,DLAM(_,tb))) -> + DOP2(Lambda,ta,DLAM(na,eta_expand env sigma cb tb)) + | (c, t) -> eta_expand0 env sigma 0 c t + +(* 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 loc predj tomatchs = + let nb_dep_ity = function + (_,IsInd ind_data) -> ind_data.nrealargs + | (c,NotInd t) -> + errorlabstrm "case_dependent" (error_case_not_inductive CCI env c t) + in + let etapred = eta_expand env sigma predj.uj_val predj.uj_type in + let n = nb_lam etapred in + let _,sort = decomp_prod env sigma predj.uj_type in + let ndepv = List.map nb_dep_ity tomatchs in + let sum = List.fold_right (fun i j -> i+j) ndepv 0 in + let depsum = sum + List.length tomatchs in + if n = sum then (false,build_expected_arity true tomatchs sort) + else if n = depsum + then (true,build_expected_arity true tomatchs sort) + else error_wrong_predicate_arity_loc loc CCI env etapred sum depsum -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 env (finalres,tomatchj)) - | Some pred -> - let loc = loc_of_rawconstr pred in - (* 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) loc 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 env !(trad.isevars) predj.uj_val predj.uj_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 (context env1) brenv in - let k = List.length (get_rels (context env1)) - List.length (get_rels (context env)) in - let abst = (* lamn k rnenv1 *) body.uj_val in - let typ = body.uj_type in (* DEVRAIT ETRE INCORRECT *) - let res = whd_beta env !(trad.isevars) (applist (abst, args)) in - - {uj_val=res;uj_type=typ;uj_kind=body.uj_kind} - - -let compile_multcase (pretype,isevars) vtcon env loc macro = - let trad = {pretype=(fun vtyc env -> pretype vtyc env); isevars = isevars} in - try compile_multcase_fail trad vtcon env macro - with CasesError (env,type_error) -> - raise (Stdpp.Exc_located (loc, TypeError(CCI,context env,type_error))) +let prepare_predicate typing_fun isevars env tomatchs = function + | None -> None + | Some pred -> + let loc = loc_of_rawconstr pred in + (* First typing to know if it is dependent *) + let predj1 = typing_fun empty_tycon env pred in + let cdep,arity = case_dependent env !isevars loc predj1 tomatchs in + (* We got the expected arity of pred and relaunch pretype with it *) + let predj = typing_fun (mk_tycon arity) env pred in + let etapred = eta_expand env !isevars predj.uj_val predj.uj_type in + Some (build_initial_predicate cdep etapred tomatchs) + +(**************************************************************************) +(* Main entry of the matching compilation *) + +let compile_cases (typing_fun,isevars) vtcon env (predopt, tomatchl, eqns) = + + (* We build the matrix of patterns and right-hand-side *) + let matx = matx_of_eqns env eqns in + + (* We build the vector of terms to match consistently with the *) + (* constructors found in patterns *) + let tomatchs = coerce_to_indtype typing_fun isevars env matx tomatchl in + + (* We build the elimination predicate if any and check its consistency *) + (* with the type of arguments to match *) + let pred = prepare_predicate typing_fun isevars env tomatchs predopt in + + let initial_pushed = + List.map (fun tm -> Pushed (insert_lifted (tm,NotDepInRhs))) tomatchs in + + let pb = + { env = env; + isevars = isevars; + pred = pred; + tomatch = initial_pushed; + mat = matx; + typing_function = typing_fun } in + + let j = compile pb in + + match vtcon with + | (_,(_,Some p)) -> Coercion.inh_conv_coerce_to env isevars p j + | _ -> j diff --git a/pretyping/cases.mli b/pretyping/cases.mli index 9f121b1222..246f2135d5 100644 --- a/pretyping/cases.mli +++ b/pretyping/cases.mli @@ -17,9 +17,9 @@ val branch_scheme : (* Compilation of pattern-matching. *) -val compile_multcase : +val compile_cases : (trad_constraint -> env -> rawconstr -> unsafe_judgment) - * 'a evar_defs -> trad_constraint -> env -> loc -> + * 'a evar_defs -> trad_constraint -> env -> rawconstr option * rawconstr list * (identifier list * pattern list * rawconstr) list -> unsafe_judgment |
