diff options
Diffstat (limited to 'kernel/closure.ml')
-rw-r--r-- | kernel/closure.ml | 523 |
1 files changed, 310 insertions, 213 deletions
diff --git a/kernel/closure.ml b/kernel/closure.ml index 9e2af94b..f06b13d8 100644 --- a/kernel/closure.ml +++ b/kernel/closure.ml @@ -1,6 +1,6 @@ (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) -(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *) +(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) @@ -19,11 +19,12 @@ (* This file implements a lazy reduction for the Calculus of Inductive Constructions *) +open Errors open Util open Pp -open Term open Names -open Declarations +open Term +open Vars open Environ open Esubst @@ -33,6 +34,7 @@ let share = ref true (* Profiling *) let beta = ref 0 let delta = ref 0 +let eta = ref 0 let zeta = ref 0 let evar = ref 0 let iota = ref 0 @@ -43,9 +45,10 @@ let reset () = prune := 0 let stop() = - msgnl (str "[Reds: beta=" ++ int !beta ++ str" delta=" ++ int !delta ++ - str" zeta=" ++ int !zeta ++ str" evar=" ++ int !evar ++ - str" iota=" ++ int !iota ++ str" prune=" ++ int !prune ++ str"]") + msg_debug (str "[Reds: beta=" ++ int !beta ++ str" delta=" ++ int !delta ++ + str " eta=" ++ int !eta ++ str" zeta=" ++ int !zeta ++ str" evar=" ++ + int !evar ++ str" iota=" ++ int !iota ++ str" prune=" ++ int !prune ++ + str"]") let incr_cnt red cnt = if red then begin @@ -63,10 +66,10 @@ let with_stats c = end else Lazy.force c -let all_opaque = (Idpred.empty, Cpred.empty) -let all_transparent = (Idpred.full, Cpred.full) +let all_opaque = (Id.Pred.empty, Cpred.empty) +let all_transparent = (Id.Pred.full, Cpred.full) -let is_transparent_variable (ids, _) id = Idpred.mem id ids +let is_transparent_variable (ids, _) id = Id.Pred.mem id ids let is_transparent_constant (_, csts) cst = Cpred.mem cst csts module type RedFlagsSig = sig @@ -74,16 +77,18 @@ module type RedFlagsSig = sig type red_kind val fBETA : red_kind val fDELTA : red_kind + val fETA : red_kind val fIOTA : red_kind val fZETA : red_kind val fCONST : constant -> red_kind - val fVAR : identifier -> red_kind + val fVAR : Id.t -> red_kind val no_red : reds val red_add : reds -> red_kind -> reds val red_sub : reds -> red_kind -> reds val red_add_transparent : reds -> transparent_state -> reds val mkflags : red_kind list -> reds val red_set : reds -> red_kind -> bool + val red_projection : reds -> projection -> bool end module RedFlags = (struct @@ -95,14 +100,16 @@ module RedFlags = (struct type reds = { r_beta : bool; r_delta : bool; + r_eta : bool; r_const : transparent_state; r_zeta : bool; r_iota : bool } - type red_kind = BETA | DELTA | IOTA | ZETA - | CONST of constant | VAR of identifier + type red_kind = BETA | DELTA | ETA | IOTA | ZETA + | CONST of constant | VAR of Id.t let fBETA = BETA let fDELTA = DELTA + let fETA = ETA let fIOTA = IOTA let fZETA = ZETA let fCONST kn = CONST kn @@ -110,12 +117,14 @@ module RedFlags = (struct let no_red = { r_beta = false; r_delta = false; + r_eta = false; r_const = all_opaque; r_zeta = false; r_iota = false } let red_add red = function | BETA -> { red with r_beta = true } + | ETA -> { red with r_eta = true } | DELTA -> { red with r_delta = true; r_const = all_transparent } | CONST kn -> let (l1,l2) = red.r_const in @@ -124,10 +133,11 @@ module RedFlags = (struct | ZETA -> { red with r_zeta = true } | VAR id -> let (l1,l2) = red.r_const in - { red with r_const = Idpred.add id l1, l2 } + { red with r_const = Id.Pred.add id l1, l2 } let red_sub red = function | BETA -> { red with r_beta = false } + | ETA -> { red with r_eta = false } | DELTA -> { red with r_delta = false } | CONST kn -> let (l1,l2) = red.r_const in @@ -136,7 +146,7 @@ module RedFlags = (struct | ZETA -> { red with r_zeta = false } | VAR id -> let (l1,l2) = red.r_const in - { red with r_const = Idpred.remove id l1, l2 } + { red with r_const = Id.Pred.remove id l1, l2 } let red_add_transparent red tr = { red with r_const = tr } @@ -145,19 +155,24 @@ module RedFlags = (struct let red_set red = function | BETA -> incr_cnt red.r_beta beta + | ETA -> incr_cnt red.r_eta eta | CONST kn -> let (_,l) = red.r_const in let c = Cpred.mem kn l in incr_cnt c delta | VAR id -> (* En attendant d'avoir des kn pour les Var *) let (l,_) = red.r_const in - let c = Idpred.mem id l in + let c = Id.Pred.mem id l in incr_cnt c delta | ZETA -> incr_cnt red.r_zeta zeta | IOTA -> incr_cnt red.r_iota iota | DELTA -> (* Used for Rel/Var defined in context *) incr_cnt red.r_delta delta + let red_projection red p = + if Projection.unfolded p then true + else red_set red (fCONST (Projection.constant p)) + end : RedFlagsSig) open RedFlags @@ -185,9 +200,8 @@ let unfold_red kn = * * i_repr is the function to get the representation from the current * state of the cache and the body of the constant. The result * is stored in the table. - * * i_rels = (4,[(1,c);(3,d)]) means there are 4 free rel variables - * and only those with index 1 and 3 have bodies which are c and d resp. - * * i_vars is the list of _defined_ named variables. + * * i_rels is the array of free rel variables together with their optional + * body * * ref_value_cache searchs in the tab, otherwise uses i_repr to * compute the result and store it in the table. If the constant can't @@ -197,72 +211,96 @@ let unfold_red kn = * instantiations (cbv or lazy) are. *) -type table_key = id_key +type table_key = constant puniverses tableKey + +let eq_pconstant_key (c,u) (c',u') = + eq_constant_key c c' && Univ.Instance.equal u u' + +module IdKeyHash = +struct + open Hashset.Combine + type t = table_key + let equal = Names.eq_table_key eq_pconstant_key + let hash = function + | ConstKey (c, _) -> combinesmall 1 (Constant.UserOrd.hash c) + | VarKey id -> combinesmall 2 (Id.hash id) + | RelKey i -> combinesmall 3 (Int.hash i) +end -let eq_table_key = Names.eq_id_key +module KeyTable = Hashtbl.Make(IdKeyHash) -type 'a infos = { - i_flags : reds; +let eq_table_key = IdKeyHash.equal + +type 'a infos_cache = { i_repr : 'a infos -> constr -> 'a; i_env : env; i_sigma : existential -> constr option; - i_rels : int * (int * constr) list; - i_vars : (identifier * constr) list; - i_tab : (table_key, 'a) Hashtbl.t } + i_rels : constr option array; + i_tab : 'a KeyTable.t } + +and 'a infos = { + i_flags : reds; + i_cache : 'a infos_cache } let info_flags info = info.i_flags +let info_env info = info.i_cache.i_env -let ref_value_cache info ref = +let rec assoc_defined id = function +| [] -> raise Not_found +| (_, None, _) :: ctxt -> assoc_defined id ctxt +| (id', Some c, _) :: ctxt -> + if Id.equal id id' then c else assoc_defined id ctxt + +let ref_value_cache ({i_cache = cache} as infos) ref = try - Some (Hashtbl.find info.i_tab ref) + Some (KeyTable.find cache.i_tab ref) with Not_found -> try let body = match ref with | RelKey n -> - let (s,l) = info.i_rels in lift n (List.assoc (s-n) l) - | VarKey id -> List.assoc id info.i_vars - | ConstKey cst -> constant_value info.i_env cst + let len = Array.length cache.i_rels in + let i = n - 1 in + let () = if i < 0 || len <= i then raise Not_found in + begin match Array.unsafe_get cache.i_rels i with + | None -> raise Not_found + | Some t -> lift n t + end + | VarKey id -> assoc_defined id (named_context cache.i_env) + | ConstKey cst -> constant_value_in cache.i_env cst in - let v = info.i_repr info body in - Hashtbl.add info.i_tab ref v; + let v = cache.i_repr infos body in + KeyTable.add cache.i_tab ref v; Some v with | Not_found (* List.assoc *) | NotEvaluableConst _ (* Const *) -> None -let evar_value info ev = - info.i_sigma ev - -let defined_vars flags env = -(* if red_local_const (snd flags) then*) - Sign.fold_named_context - (fun (id,b,_) e -> - match b with - | None -> e - | Some body -> (id, body)::e) - (named_context env) ~init:[] -(* else []*) +let evar_value cache ev = + cache.i_sigma ev let defined_rels flags env = (* if red_local_const (snd flags) then*) - Sign.fold_rel_context - (fun (id,b,t) (i,subs) -> - match b with - | None -> (i+1, subs) - | Some body -> (i+1, (i,body) :: subs)) - (rel_context env) ~init:(0,[]) + let ctx = rel_context env in + let len = List.length ctx in + let ans = Array.make len None in + let iter i (_, b, _) = match b with + | None -> () + | Some _ -> Array.unsafe_set ans i b + in + let () = List.iteri iter ctx in + ans (* else (0,[])*) let create mk_cl flgs env evars = - { i_flags = flgs; - i_repr = mk_cl; - i_env = env; - i_sigma = evars; - i_rels = defined_rels flgs env; - i_vars = defined_vars flgs env; - i_tab = Hashtbl.create 17 } + let cache = + { i_repr = mk_cl; + i_env = env; + i_sigma = evars; + i_rels = defined_rels flgs env; + i_tab = KeyTable.create 17 } + in { i_flags = flgs; i_cache = cache } (**********************************************************************) @@ -302,15 +340,17 @@ and fterm = | FAtom of constr (* Metas and Sorts *) | FCast of fconstr * cast_kind * fconstr | FFlex of table_key - | FInd of inductive - | FConstruct of constructor + | FInd of pinductive + | FConstruct of pconstructor | FApp of fconstr * fconstr array + | FProj of projection * fconstr | FFix of fixpoint * fconstr subs | FCoFix of cofixpoint * fconstr subs - | FCases of case_info * fconstr * fconstr * fconstr array - | FLambda of int * (name * constr) list * constr * fconstr subs - | FProd of name * fconstr * fconstr - | FLetIn of name * fconstr * fconstr * constr * fconstr subs + | FCase of case_info * fconstr * fconstr * fconstr array + | FCaseT of case_info * constr * fconstr * constr array * fconstr subs (* predicate and branches are closures *) + | FLambda of int * (Name.t * constr) list * constr * fconstr subs + | FProd of Name.t * fconstr * fconstr + | FLetIn of Name.t * fconstr * fconstr * constr * fconstr subs | FEvar of existential * fconstr subs | FLIFT of int * fconstr | FCLOS of constr * fconstr subs @@ -318,13 +358,13 @@ and fterm = let fterm_of v = v.term let set_norm v = v.norm <- Norm -let is_val v = v.norm = Norm +let is_val v = match v.norm with Norm -> true | _ -> false let mk_atom c = {norm=Norm;term=FAtom c} (* Could issue a warning if no is still Red, pointing out that we loose sharing. *) -let update v1 (no,t) = +let update v1 no t = if !share then (v1.norm <- no; v1.term <- t; @@ -337,6 +377,8 @@ let update v1 (no,t) = type stack_member = | Zapp of fconstr array | Zcase of case_info * fconstr * fconstr array + | ZcaseT of case_info * constr * constr array * fconstr subs + | Zproj of int * int * constant | Zfix of fconstr * stack | Zshift of int | Zupdate of fconstr @@ -345,7 +387,7 @@ and stack = stack_member list let empty_stack = [] let append_stack v s = - if Array.length v = 0 then s else + if Int.equal (Array.length v) 0 then s else match s with | Zapp l :: s -> Zapp (Array.append v l) :: s | _ -> Zapp v :: s @@ -389,7 +431,7 @@ let rec stack_assign s p c = match s with Zapp nargs :: s) | _ -> s let rec stack_tail p s = - if p = 0 then s else + if Int.equal p 0 then s else match s with | Zapp args :: s -> let q = Array.length args in @@ -417,9 +459,9 @@ let rec lft_fconstr n ft = | FLOCKED -> assert false | _ -> {norm=ft.norm; term=FLIFT(n,ft)} let lift_fconstr k f = - if k=0 then f else lft_fconstr k f + if Int.equal k 0 then f else lft_fconstr k f let lift_fconstr_vect k v = - if k=0 then v else Array.map (fun f -> lft_fconstr k f) v + if Int.equal k 0 then v else CArray.Fun1.map lft_fconstr k v let clos_rel e i = match expand_rel i e with @@ -436,88 +478,21 @@ let compact_stack head stk = (* Be sure to create a new cell otherwise sharing would be lost by the update operation *) let h' = lft_fconstr depth head in - let _ = update m (h'.norm,h'.term) in + let _ = update m h'.norm h'.term in strip_rec depth s | stk -> zshift depth stk in strip_rec 0 stk (* Put an update mark in the stack, only if needed *) let zupdate m s = - if !share & m.norm = Red + if !share && begin match m.norm with Red -> true | _ -> false end then let s' = compact_stack m s in let _ = m.term <- FLOCKED in Zupdate(m)::s' else s -(* Closure optimization: *) -let rec compact_constr (lg, subs as s) c k = - match kind_of_term c with - Rel i -> - if i < k then c,s else - (try mkRel (k + lg - list_index (i-k+1) subs), (lg,subs) - with Not_found -> mkRel (k+lg), (lg+1, (i-k+1)::subs)) - | (Sort _|Var _|Meta _|Ind _|Const _|Construct _) -> c,s - | Evar(ev,v) -> - let (v',s) = compact_vect s v k in - if v==v' then c,s else mkEvar(ev,v'),s - | Cast(a,ck,b) -> - let (a',s) = compact_constr s a k in - let (b',s) = compact_constr s b k in - if a==a' && b==b' then c,s else mkCast(a', ck, b'), s - | App(f,v) -> - let (f',s) = compact_constr s f k in - let (v',s) = compact_vect s v k in - if f==f' && v==v' then c,s else mkApp(f',v'), s - | Lambda(n,a,b) -> - let (a',s) = compact_constr s a k in - let (b',s) = compact_constr s b (k+1) in - if a==a' && b==b' then c,s else mkLambda(n,a',b'), s - | Prod(n,a,b) -> - let (a',s) = compact_constr s a k in - let (b',s) = compact_constr s b (k+1) in - if a==a' && b==b' then c,s else mkProd(n,a',b'), s - | LetIn(n,a,ty,b) -> - let (a',s) = compact_constr s a k in - let (ty',s) = compact_constr s ty k in - let (b',s) = compact_constr s b (k+1) in - if a==a' && ty==ty' && b==b' then c,s else mkLetIn(n,a',ty',b'), s - | Fix(fi,(na,ty,bd)) -> - let (ty',s) = compact_vect s ty k in - let (bd',s) = compact_vect s bd (k+Array.length ty) in - if ty==ty' && bd==bd' then c,s else mkFix(fi,(na,ty',bd')), s - | CoFix(i,(na,ty,bd)) -> - let (ty',s) = compact_vect s ty k in - let (bd',s) = compact_vect s bd (k+Array.length ty) in - if ty==ty' && bd==bd' then c,s else mkCoFix(i,(na,ty',bd')), s - | Case(ci,p,a,br) -> - let (p',s) = compact_constr s p k in - let (a',s) = compact_constr s a k in - let (br',s) = compact_vect s br k in - if p==p' && a==a' && br==br' then c,s else mkCase(ci,p',a',br'),s -and compact_vect s v k = compact_v [] s v k (Array.length v - 1) -and compact_v acc s v k i = - if i < 0 then - let v' = Array.of_list acc in - if array_for_all2 (==) v v' then v,s else v',s - else - let (a',s') = compact_constr s v.(i) k in - compact_v (a'::acc) s' v k (i-1) - -(* Computes the minimal environment of a closure. - Idea: if the subs is not identity, the term will have to be - reallocated entirely (to propagate the substitution). So, - computing the set of free variables does not change the - complexity. *) -let optimise_closure env c = - if is_subs_id env then (env,c) else - let (c',(_,s)) = compact_constr (0,[]) c 1 in - let env' = - Array.map (fun i -> clos_rel env i) (Array.of_list s) in - (subs_cons (env', subs_id 0),c') - let mk_lambda env t = - let (env,t) = optimise_closure env t in let (rvars,t') = decompose_lam t in FLambda(List.length rvars, List.rev rvars, t', env) @@ -539,10 +514,10 @@ let mk_clos e t = | Meta _ | Sort _ -> { norm = Norm; term = FAtom t } | Ind kn -> { norm = Norm; term = FInd kn } | Construct kn -> { norm = Cstr; term = FConstruct kn } - | (CoFix _|Lambda _|Fix _|Prod _|Evar _|App _|Case _|Cast _|LetIn _) -> + | (CoFix _|Lambda _|Fix _|Prod _|Evar _|App _|Case _|Cast _|LetIn _|Proj _) -> {norm = Red; term = FCLOS(t,e)} -let mk_clos_vect env v = Array.map (mk_clos env) v +let mk_clos_vect env v = CArray.Fun1.map mk_clos env v (* Translate the head constructor of t from constr to fconstr. This function is parameterized by the function to apply on the direct @@ -557,11 +532,13 @@ let mk_clos_deep clos_fun env t = term = FCast (clos_fun env a, k, clos_fun env b)} | App (f,v) -> { norm = Red; - term = FApp (clos_fun env f, Array.map (clos_fun env) v) } + term = FApp (clos_fun env f, CArray.Fun1.map clos_fun env v) } + | Proj (p,c) -> + { norm = Red; + term = FProj (p, clos_fun env c) } | Case (ci,p,c,v) -> { norm = Red; - term = FCases (ci, clos_fun env p, clos_fun env c, - Array.map (clos_fun env) v) } + term = FCaseT (ci, p, clos_fun env c, v, env) } | Fix fx -> { norm = Cstr; term = FFix (fx, env) } | CoFix cfx -> @@ -589,30 +566,37 @@ let rec to_constr constr_fun lfts v = | FAtom c -> exliftn lfts c | FCast (a,k,b) -> mkCast (constr_fun lfts a, k, constr_fun lfts b) - | FFlex (ConstKey op) -> mkConst op - | FInd op -> mkInd op - | FConstruct op -> mkConstruct op - | FCases (ci,p,c,ve) -> + | FFlex (ConstKey op) -> mkConstU op + | FInd op -> mkIndU op + | FConstruct op -> mkConstructU op + | FCase (ci,p,c,ve) -> mkCase (ci, constr_fun lfts p, constr_fun lfts c, - Array.map (constr_fun lfts) ve) + CArray.Fun1.map constr_fun lfts ve) + | FCaseT (ci,p,c,ve,env) -> + mkCase (ci, constr_fun lfts (mk_clos env p), + constr_fun lfts c, + Array.map (fun b -> constr_fun lfts (mk_clos env b)) ve) | FFix ((op,(lna,tys,bds)),e) -> let n = Array.length bds in - let ftys = Array.map (mk_clos e) tys in - let fbds = Array.map (mk_clos (subs_liftn n e)) bds in + let ftys = CArray.Fun1.map mk_clos e tys in + let fbds = CArray.Fun1.map mk_clos (subs_liftn n e) bds in let lfts' = el_liftn n lfts in - mkFix (op, (lna, Array.map (constr_fun lfts) ftys, - Array.map (constr_fun lfts') fbds)) + mkFix (op, (lna, CArray.Fun1.map constr_fun lfts ftys, + CArray.Fun1.map constr_fun lfts' fbds)) | FCoFix ((op,(lna,tys,bds)),e) -> let n = Array.length bds in - let ftys = Array.map (mk_clos e) tys in - let fbds = Array.map (mk_clos (subs_liftn n e)) bds in + let ftys = CArray.Fun1.map mk_clos e tys in + let fbds = CArray.Fun1.map mk_clos (subs_liftn n e) bds in let lfts' = el_liftn (Array.length bds) lfts in - mkCoFix (op, (lna, Array.map (constr_fun lfts) ftys, - Array.map (constr_fun lfts') fbds)) + mkCoFix (op, (lna, CArray.Fun1.map constr_fun lfts ftys, + CArray.Fun1.map constr_fun lfts' fbds)) | FApp (f,ve) -> mkApp (constr_fun lfts f, - Array.map (constr_fun lfts) ve) + CArray.Fun1.map constr_fun lfts ve) + | FProj (p,c) -> + mkProj (p,constr_fun lfts c) + | FLambda _ -> let (na,ty,bd) = destFLambda mk_clos2 v in mkLambda (na, constr_fun lfts ty, @@ -630,9 +614,9 @@ let rec to_constr constr_fun lfts v = | FLIFT (k,a) -> to_constr constr_fun (el_shft k lfts) a | FCLOS (t,env) -> let fr = mk_clos2 env t in - let unfv = update v (fr.norm,fr.term) in + let unfv = update v fr.norm fr.term in to_constr constr_fun lfts unfv - | FLOCKED -> assert false (*mkVar(id_of_string"_LOCK_")*) + | FLOCKED -> assert false (*mkVar(Id.of_string"_LOCK_")*) (* This function defines the correspondance between constr and fconstr. When we find a closure whose substitution is the identity, @@ -641,11 +625,11 @@ let rec to_constr constr_fun lfts v = let term_of_fconstr = let rec term_of_fconstr_lift lfts v = match v.term with - | FCLOS(t,env) when is_subs_id env & is_lift_id lfts -> t - | FLambda(_,tys,f,e) when is_subs_id e & is_lift_id lfts -> + | FCLOS(t,env) when is_subs_id env && is_lift_id lfts -> t + | FLambda(_,tys,f,e) when is_subs_id e && is_lift_id lfts -> compose_lam (List.rev tys) f - | FFix(fx,e) when is_subs_id e & is_lift_id lfts -> mkFix fx - | FCoFix(cfx,e) when is_subs_id e & is_lift_id lfts -> mkCoFix cfx + | FFix(fx,e) when is_subs_id e && is_lift_id lfts -> mkFix fx + | FCoFix(cfx,e) when is_subs_id e && is_lift_id lfts -> mkCoFix cfx | _ -> to_constr term_of_fconstr_lift lfts v in term_of_fconstr_lift el_id @@ -663,14 +647,19 @@ let rec zip m stk = | [] -> m | Zapp args :: s -> zip {norm=neutr m.norm; term=FApp(m, args)} s | Zcase(ci,p,br)::s -> - let t = FCases(ci, p, m, br) in + let t = FCase(ci, p, m, br) in + zip {norm=neutr m.norm; term=t} s + | ZcaseT(ci,p,br,e)::s -> + let t = FCaseT(ci, p, m, br, e) in zip {norm=neutr m.norm; term=t} s + | Zproj (i,j,cst) :: s -> + zip {norm=neutr m.norm; term=FProj(Projection.make cst true,m)} s | Zfix(fx,par)::s -> zip fx (par @ append_stack [|m|] s) | Zshift(n)::s -> zip (lift_fconstr n m) s | Zupdate(rf)::s -> - zip (update rf (m.norm,m.term)) s + zip (update rf m.norm m.term) s let fapp_stack (m,stk) = zip m stk @@ -682,8 +671,7 @@ let fapp_stack (m,stk) = zip m stk (strip_update_shift, through get_arg). *) (* optimised for the case where there are no shifts... *) -let strip_update_shift_app head stk = - assert (head.norm <> Red); +let strip_update_shift_app_red head stk = let rec strip_rec rstk h depth = function | Zshift(k) as e :: s -> strip_rec (e::rstk) (lift_fconstr k h) (depth+k) s @@ -691,13 +679,16 @@ let strip_update_shift_app head stk = strip_rec (Zapp args :: rstk) {norm=h.norm;term=FApp(h,args)} depth s | Zupdate(m)::s -> - strip_rec rstk (update m (h.norm,h.term)) depth s + strip_rec rstk (update m h.norm h.term) depth s | stk -> (depth,List.rev rstk, stk) in strip_rec [] head 0 stk +let strip_update_shift_app head stack = + assert (match head.norm with Red -> false | _ -> true); + strip_update_shift_app_red head stack let get_nth_arg head n stk = - assert (head.norm <> Red); + assert (match head.norm with Red -> false | _ -> true); let rec strip_rec rstk h n = function | Zshift(k) as e :: s -> strip_rec (e::rstk) (lift_fconstr k h) n s @@ -710,10 +701,10 @@ let get_nth_arg head n stk = let bef = Array.sub args 0 n in let aft = Array.sub args (n+1) (q-n-1) in let stk' = - List.rev (if n = 0 then rstk else (Zapp bef :: rstk)) in + List.rev (if Int.equal n 0 then rstk else (Zapp bef :: rstk)) in (Some (stk', args.(n)), append_stack aft s') | Zupdate(m)::s -> - strip_rec rstk (update m (h.norm,h.term)) n s + strip_rec rstk (update m h.norm h.term) n s | s -> (None, List.rev rstk @ s) in strip_rec [] head n stk @@ -722,7 +713,7 @@ let get_nth_arg head n stk = let rec get_args n tys f e stk = match stk with Zupdate r :: s -> - let _hd = update r (Cstr,FLambda(n,tys,f,e)) in + let _hd = update r Cstr (FLambda(n,tys,f,e)) in get_args n tys f e s | Zshift k :: s -> get_args n tys f (subs_shft (k,e)) s @@ -734,13 +725,14 @@ let rec get_args n tys f e stk = let eargs = Array.sub l n (na-n) in (Inl (subs_cons(args,e)), Zapp eargs :: s) else (* more lambdas *) - let etys = list_skipn na tys in + let etys = List.skipn na tys in get_args (n-na) etys f (subs_cons(l,e)) s | _ -> (Inr {norm=Cstr;term=FLambda(n,tys,f,e)}, stk) (* Eta expansion: add a reference to implicit surrounding lambda at end of stack *) let rec eta_expand_stack = function - | (Zapp _ | Zfix _ | Zcase _ | Zshift _ | Zupdate _ as e) :: s -> + | (Zapp _ | Zfix _ | Zcase _ | ZcaseT _ | Zproj _ + | Zshift _ | Zupdate _ as e) :: s -> e :: eta_expand_stack s | [] -> [Zshift 1; Zapp [|{norm=Norm; term= FRel 1}|]] @@ -751,29 +743,88 @@ let rec reloc_rargs_rec depth stk = match stk with Zapp args :: s -> Zapp (lift_fconstr_vect depth args) :: reloc_rargs_rec depth s - | Zshift(k)::s -> if k=depth then s else reloc_rargs_rec (depth-k) s + | Zshift(k)::s -> if Int.equal k depth then s else reloc_rargs_rec (depth-k) s | _ -> stk let reloc_rargs depth stk = - if depth = 0 then stk else reloc_rargs_rec depth stk + if Int.equal depth 0 then stk else reloc_rargs_rec depth stk -let rec drop_parameters depth n argstk = +let rec try_drop_parameters depth n argstk = match argstk with Zapp args::s -> let q = Array.length args in - if n > q then drop_parameters depth (n-q) s - else if n = q then reloc_rargs depth s + if n > q then try_drop_parameters depth (n-q) s + else if Int.equal n q then reloc_rargs depth s else let aft = Array.sub args n (q-n) in reloc_rargs depth (append_stack aft s) - | Zshift(k)::s -> drop_parameters (depth-k) n s + | Zshift(k)::s -> try_drop_parameters (depth-k) n s + | [] -> + if Int.equal n 0 then [] + else raise Not_found + | _ -> assert false + (* strip_update_shift_app only produces Zapp and Zshift items *) + +let drop_parameters depth n argstk = + try try_drop_parameters depth n argstk + with Not_found -> + (* we know that n < stack_args_size(argstk) (if well-typed term) *) + anomaly (Pp.str "ill-typed term: found a match on a partially applied constructor") + + +let rec get_parameters depth n argstk = + match argstk with + Zapp args::s -> + let q = Array.length args in + if n > q then Array.append args (get_parameters depth (n-q) s) + else if Int.equal n q then [||] + else Array.sub args 0 n + | Zshift(k)::s -> + get_parameters (depth-k) n s | [] -> (* we know that n < stack_args_size(argstk) (if well-typed term) *) - if n=0 then [] - else anomaly - "ill-typed term: found a match on a partially applied constructor" + if Int.equal n 0 then [||] + else raise Not_found (* Trying to eta-expand a partial application..., should do + eta expansion first? *) | _ -> assert false (* strip_update_shift_app only produces Zapp and Zshift items *) + +(** [eta_expand_ind_stack env ind c s t] computes stacks correspoding + to the conversion of the eta expansion of t, considered as an inhabitant + of ind, and the Constructor c of this inductive type applied to arguments + s. + @assumes [t] is an irreducible term, and not a constructor. [ind] is the inductive + of the constructor term [c] + @raises Not_found if the inductive is not a primitive record, or if the + constructor is partially applied. + *) +let eta_expand_ind_stack env ind m s (f, s') = + let mib = lookup_mind (fst ind) env in + match mib.Declarations.mind_record with + | Some (Some (_,projs,pbs)) when + mib.Declarations.mind_finite <> Decl_kinds.CoFinite -> + (* (Construct, pars1 .. parsm :: arg1...argn :: []) ~= (f, s') -> + arg1..argn ~= (proj1 t...projn t) where t = zip (f,s') *) + let pars = mib.Declarations.mind_nparams in + let right = fapp_stack (f, s') in + let (depth, args, s) = strip_update_shift_app m s in + (** Try to drop the params, might fail on partially applied constructors. *) + let argss = try_drop_parameters depth pars args in + let hstack = Array.map (fun p -> { norm = Red; (* right can't be a constructor though *) + term = FProj (Projection.make p true, right) }) projs in + argss, [Zapp hstack] + | _ -> raise Not_found (* disallow eta-exp for non-primitive records *) + +let rec project_nth_arg n argstk = + match argstk with + | Zapp args :: s -> + let q = Array.length args in + if n >= q then project_nth_arg (n - q) s + else (* n < q *) args.(n) + | _ -> assert false + (* After drop_parameters we have a purely applicative stack *) + + (* Iota reduction: expansion of a fixpoint. * Given a fixpoint and a substitution, returns the corresponding * fixpoint body, and the substitution in which it should be @@ -798,39 +849,51 @@ let contract_fix_vect fix = in (subs_cons(Array.init nfix make_body, env), thisbody) - (*********************************************************************) (* A machine that inspects the head of a term until it finds an atom or a subterm that may produce a redex (abstraction, constructor, cofix, letin, constant), or a neutral term (product, inductive) *) -let rec knh m stk = +let rec knh info m stk = match m.term with - | FLIFT(k,a) -> knh a (zshift k stk) - | FCLOS(t,e) -> knht e t (zupdate m stk) + | FLIFT(k,a) -> knh info a (zshift k stk) + | FCLOS(t,e) -> knht info e t (zupdate m stk) | FLOCKED -> assert false - | FApp(a,b) -> knh a (append_stack b (zupdate m stk)) - | FCases(ci,p,t,br) -> knh t (Zcase(ci,p,br)::zupdate m stk) + | FApp(a,b) -> knh info a (append_stack b (zupdate m stk)) + | FCase(ci,p,t,br) -> knh info t (Zcase(ci,p,br)::zupdate m stk) + | FCaseT(ci,p,t,br,e) -> knh info t (ZcaseT(ci,p,br,e)::zupdate m stk) | FFix(((ri,n),(_,_,_)),_) -> (match get_nth_arg m ri.(n) stk with - (Some(pars,arg),stk') -> knh arg (Zfix(m,pars)::stk') + (Some(pars,arg),stk') -> knh info arg (Zfix(m,pars)::stk') | (None, stk') -> (m,stk')) - | FCast(t,_,_) -> knh t stk + | FCast(t,_,_) -> knh info t stk + | FProj (p,c) -> + let unf = Projection.unfolded p in + if unf || red_set info.i_flags (fCONST (Projection.constant p)) then + (match try Some (lookup_projection p (info_env info)) with Not_found -> None with + | None -> (m, stk) + | Some pb -> + knh info c (Zproj (pb.Declarations.proj_npars, pb.Declarations.proj_arg, + Projection.constant p) + :: zupdate m stk)) + else (m,stk) + (* cases where knh stops *) | (FFlex _|FLetIn _|FConstruct _|FEvar _| FCoFix _|FLambda _|FRel _|FAtom _|FInd _|FProd _) -> (m, stk) (* The same for pure terms *) -and knht e t stk = +and knht info e t stk = match kind_of_term t with | App(a,b) -> - knht e a (append_stack (mk_clos_vect e b) stk) + knht info e a (append_stack (mk_clos_vect e b) stk) | Case(ci,p,t,br) -> - knht e t (Zcase(ci, mk_clos e p, mk_clos_vect e br)::stk) - | Fix _ -> knh (mk_clos2 e t) stk - | Cast(a,_,_) -> knht e a stk - | Rel n -> knh (clos_rel e n) stk + knht info e t (ZcaseT(ci, p, br, e)::stk) + | Fix _ -> knh info (mk_clos2 e t) stk + | Cast(a,_,_) -> knht info e a stk + | Rel n -> knh info (clos_rel e n) stk + | Proj (p,c) -> knh info (mk_clos2 e t) stk | (Lambda _|Prod _|Construct _|CoFix _|Ind _| LetIn _|Const _|Var _|Evar _|Meta _|Sort _) -> (mk_clos2 e t, stk) @@ -845,8 +908,8 @@ let rec knr info m stk = (match get_args n tys f e stk with Inl e', s -> knit info e' f s | Inr lam, s -> (lam,s)) - | FFlex(ConstKey kn) when red_set info.i_flags (fCONST kn) -> - (match ref_value_cache info (ConstKey kn) with + | FFlex(ConstKey (kn,_ as c)) when red_set info.i_flags (fCONST kn) -> + (match ref_value_cache info (ConstKey c) with Some v -> kni info v stk | None -> (set_norm m; (m,stk))) | FFlex(VarKey id) when red_set info.i_flags (fVAR id) -> @@ -857,38 +920,46 @@ let rec knr info m stk = (match ref_value_cache info (RelKey k) with Some v -> kni info v stk | None -> (set_norm m; (m,stk))) - | FConstruct(ind,c) when red_set info.i_flags fIOTA -> + | FConstruct((ind,c),u) when red_set info.i_flags fIOTA -> (match strip_update_shift_app m stk with (depth, args, Zcase(ci,_,br)::s) -> assert (ci.ci_npar>=0); let rargs = drop_parameters depth ci.ci_npar args in kni info br.(c-1) (rargs@s) + | (depth, args, ZcaseT(ci,_,br,e)::s) -> + assert (ci.ci_npar>=0); + let rargs = drop_parameters depth ci.ci_npar args in + knit info e br.(c-1) (rargs@s) | (_, cargs, Zfix(fx,par)::s) -> let rarg = fapp_stack(m,cargs) in let stk' = par @ append_stack [|rarg|] s in let (fxe,fxbd) = contract_fix_vect fx.term in knit info fxe fxbd stk' + | (depth, args, Zproj (n, m, cst)::s) -> + let rargs = drop_parameters depth n args in + let rarg = project_nth_arg m rargs in + kni info rarg s | (_,args,s) -> (m,args@s)) | FCoFix _ when red_set info.i_flags fIOTA -> (match strip_update_shift_app m stk with - (_, args, ((Zcase _::_) as stk')) -> + (_, args, (((Zcase _|ZcaseT _)::_) as stk')) -> let (fxe,fxbd) = contract_fix_vect m.term in knit info fxe fxbd (args@stk') | (_,args,s) -> (m,args@s)) | FLetIn (_,v,_,bd,e) when red_set info.i_flags fZETA -> knit info (subs_cons([|v|],e)) bd stk | FEvar(ev,env) -> - (match evar_value info ev with + (match evar_value info.i_cache ev with Some c -> knit info env c stk | None -> (m,stk)) | _ -> (m,stk) (* Computes the weak head normal form of a term *) and kni info m stk = - let (hm,s) = knh m stk in + let (hm,s) = knh info m stk in knr info hm s and knit info e t stk = - let (ht,s) = knht e t stk in + let (ht,s) = knht info e t stk in knr info ht s let kh info v stk = fapp_stack(kni info v stk) @@ -903,6 +974,13 @@ let rec zip_term zfun m stk = | Zcase(ci,p,br)::s -> let t = mkCase(ci, zfun p, m, Array.map zfun br) in zip_term zfun t s + | ZcaseT(ci,p,br,e)::s -> + let t = mkCase(ci, zfun (mk_clos e p), m, + Array.map (fun b -> zfun (mk_clos e b)) br) in + zip_term zfun t s + | Zproj(_,_,p)::s -> + let t = mkProj (Projection.make p true, m) in + zip_term zfun t s | Zfix(fx,par)::s -> let h = mkApp(zip_term zfun (zfun fx) par,[|m|]) in zip_term zfun h s @@ -940,17 +1018,19 @@ and norm_head info m = | FProd(na,dom,rng) -> mkProd(na, kl info dom, kl info rng) | FCoFix((n,(na,tys,bds)),e) -> - let ftys = Array.map (mk_clos e) tys in + let ftys = CArray.Fun1.map mk_clos e tys in let fbds = - Array.map (mk_clos (subs_liftn (Array.length na) e)) bds in - mkCoFix(n,(na, Array.map (kl info) ftys, Array.map (kl info) fbds)) + CArray.Fun1.map mk_clos (subs_liftn (Array.length na) e) bds in + mkCoFix(n,(na, CArray.Fun1.map kl info ftys, CArray.Fun1.map kl info fbds)) | FFix((n,(na,tys,bds)),e) -> - let ftys = Array.map (mk_clos e) tys in + let ftys = CArray.Fun1.map mk_clos e tys in let fbds = - Array.map (mk_clos (subs_liftn (Array.length na) e)) bds in - mkFix(n,(na, Array.map (kl info) ftys, Array.map (kl info) fbds)) + CArray.Fun1.map mk_clos (subs_liftn (Array.length na) e) bds in + mkFix(n,(na, CArray.Fun1.map kl info ftys, CArray.Fun1.map kl info fbds)) | FEvar((i,args),env) -> mkEvar(i, Array.map (fun a -> kl info (mk_clos env a)) args) + | FProj (p,c) -> + mkProj (p, kl info c) | t -> term_of_fconstr m (* Initialization and then normalization *) @@ -963,7 +1043,7 @@ let whd_val info v = let norm_val info v = with_stats (lazy (kl info v)) -let inject = mk_clos (subs_id 0) +let inject c = mk_clos (subs_id 0) c let whd_stack infos m stk = let k = kni infos m stk in @@ -975,5 +1055,22 @@ type clos_infos = fconstr infos let create_clos_infos ?(evars=fun _ -> None) flgs env = create (fun _ -> inject) flgs env evars - -let unfold_reference = ref_value_cache +let oracle_of_infos infos = Environ.oracle infos.i_cache.i_env + +let env_of_infos infos = infos.i_cache.i_env + +let infos_with_reds infos reds = + { infos with i_flags = reds } + +let unfold_reference info key = + match key with + | ConstKey (kn,_) -> + if red_set info.i_flags (fCONST kn) then + ref_value_cache info key + else None + | VarKey i -> + if red_set info.i_flags (fVAR i) then + ref_value_cache info key + else None + | _ -> ref_value_cache info key + |