(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
open CErrors open Util open Names open Constr open Termops open Univ open Evd open Environ open EConstr open Vars open Context.Rel.Declaration
exception Elimconst
(** This module implements a call by name reduction used by (at
least) evarconv unification. *)
(** Support for reduction effects *)
open Mod_subst open Libobject
type effect_name = string
(** create a persistent set to store effect functions *)
(* Table bindings a constant to an effect *) let constant_effect_table = Summary.ref ~name:"reduction-side-effect" Cmap.empty
(* Table bindings function key to effective functions *) let effect_table = refString.Map.empty
(** a test to know whether a constant is actually the effect function *) let reduction_effect_hook env sigma con c = try let funkey = Cmap.find con !constant_effect_table in let effect_function = String.Map.find funkey !effect_table in
effect_function env sigma (Lazy.force c) with Not_found -> ()
let cache_reduction_effect (con,funkey) =
constant_effect_table := Cmap.add con funkey !constant_effect_table
let subst_reduction_effect (subst,(con,funkey)) =
(subst_constant subst con,funkey)
let more_args k = function
| NeverUnfold -> NeverUnfold
| UnfoldWhen x -> UnfoldWhen (more_args_when k x)
| UnfoldWhenNoMatch x -> UnfoldWhenNoMatch (more_args_when k x)
type table = Cpred.t * t Cmap.t
(* We need to have a fast way to know the set of all constants that have the NeverUnfold flag. Therefore, the table has a distinct subpart
that is this set. *) let table =
Summary.ref ((Cpred.empty, Cmap.empty)) ~name:"reductionbehaviour"
let load _ (_,(r, b)) =
table := (match b with
| None -> Cpred.remove r (fst !table), Cmap.remove r (snd !table)
| Some NeverUnfold -> Cpred.add r (fst !table), Cmap.remove r (snd !table)
| Some b -> Cpred.remove r (fst !table), Cmap.add r b (snd !table))
let cache o = load 1 o
let classify (local,_) = if local then Dispose else Substitute
let subst (subst, (local, (r,o) as orig)) = let r' = subst_constant subst r in if r==r'then orig else (local,(r',o))
let discharge = function
| false, (gr, b) -> let b = let gr = GlobRef.ConstRef gr in if Global.is_in_section gr then let vars = Global.section_instance gr in let extra = Array.length vars in Option.map (more_args extra) b else b in
Some (false, (gr, b))
| true, _ -> None
letset ~local r b =
Lib.add_leaf (inRedBehaviour (local, (r, b)))
let get_from_db table r = if Cpred.mem r (fst table) then
Some NeverUnfold else
Cmap.find_opt r (snd table)
let print_from_db table ref = letopen Pp in let pr_global c = Nametab.pr_global_env Id.Set.empty (ConstRef c) in match get_from_db table refwith
| None -> mt ()
| Some b -> let pp_nomatch = spc () ++ str "but avoid exposing match constructs"in let pp_recargs recargs = spc() ++ str "when the " ++
pr_enum (fun x -> pr_nth (x+1)) recargs ++ str (String.plural (List.length recargs) " argument") ++
str (String.plural (ifList.length recargs >= 2 then 1 else 2) " evaluate") ++
str " to a constructor"in let pp_nargs nargs =
spc() ++ str "when applied to " ++ int nargs ++
str (String.plural nargs " argument") in let pp_when = function
| { recargs = []; nargs = Some 0 } ->
str "always unfold " ++ pr_global ref
| { recargs = []; nargs = Some n } ->
str "unfold " ++ pr_global ref ++ pp_nargs n
| { recargs = []; nargs = None } ->
str "unfold " ++ pr_global ref
| { recargs; nargs = Some n } when n > List.fold_left max 0 recargs ->
str "unfold " ++ pr_global ref ++ pp_recargs recargs ++
str " and" ++ pp_nargs n
| { recargs; nargs = _ } ->
str "unfold " ++ pr_global ref ++ pp_recargs recargs in let pp_behavior = function
| NeverUnfold -> str "never unfold " ++ pr_global ref
| UnfoldWhen x -> pp_when x
| UnfoldWhenNoMatch x -> pp_when x ++ pp_nomatch in
hov 2 (str "The reduction tactics " ++ pp_behavior b)
module Db = struct type t = table let get () = !table let empty = (Cpred.empty, Cmap.empty) letprint = print_from_db let all_never_unfold table = fst table end
let get r = get_from_db (Db.get ()) r
letprint c = print_from_db (Db.get ()) c
end
(** The type of (machine) stacks (= lambda-bar-calculus' contexts) *)
module Stack : sig open EConstr type app_node val pr_app_node : (EConstr.t -> Pp.t) -> app_node -> Pp.t
type member =
| Appof app_node
| Caseof case_stk
| Proj of Projection.t * ERelevance.t
| Fix of fixpoint * t
| Primitive of CPrimitives.t * (Constant.t * EInstance.t) * t * CPrimitives.args_red
and t = member list
exception IncompatibleFold2
val pr : (EConstr.t -> Pp.t) -> t -> Pp.t val empty : t val is_empty : t -> bool val append_app : EConstr.t array -> t -> t val decomp : t -> (EConstr.t * t) option val decomp_rev : t -> (EConstr.t * t) option val compare_shape : t -> t -> bool val fold2 : ('a -> constr -> constr -> 'a) -> 'a -> t -> t -> 'a val append_app_list : EConstr.t list -> t -> t val strip_app : t -> t * t val strip_n_app : int -> t -> (t * EConstr.t * t) option val not_purely_applicative : t -> bool val list_of_app_stack : t -> constr listoption val args_size : t -> int val tail : int -> t -> t val nth : t -> int -> EConstr.t val zip : evar_map -> constr * t -> constr val check_native_args : CPrimitives.t -> t -> bool val get_next_primitive_args : CPrimitives.args_red -> t -> CPrimitives.args_red * (t * EConstr.t * t) option val expand_case : env -> evar_map -> case_stk -> case_info * EInstance.t * constr array * ((rel_context * constr) * ERelevance.t) * (rel_context * constr) array end = struct open EConstr type app_node = int * EConstr.t array * int (* first relevant position, arguments, last relevant position *)
(* Invariant that this module must ensure: (beware of direct access to app_node by the rest of Reductionops) - in app_node (i,_,j) i <= j - There is no array reallocation (outside of debug printing)
*)
let pr_app_node pr (i,a,j) = letopen Pp in surround (
prvect_with_sep pr_comma pr (Array.sub a i (j - i + 1))
)
type member =
| Appof app_node
| Caseof case_stk
| Proj of Projection.t * ERelevance.t
| Fix of fixpoint * t
| Primitive of CPrimitives.t * (Constant.t * EInstance.t) * t * CPrimitives.args_red
and t = member list
(* Debugging printer *) let rec pr_member pr_c member = letopen Pp in let pr_c x = hov 1 (pr_c x) in match member with
| Appapp -> str "ZApp" ++ pr_app_node pr_c app
| Case (_,_,_,_,_,br) ->
str "ZCase(" ++
prvect_with_sep (pr_bar) (fun (_, c) -> pr_c c) br
++ str ")"
| Proj (p,_) ->
str "ZProj(" ++ Projection.debug_print p ++ str ")"
| Fix (f,args) ->
str "ZFix(" ++ Constr.debug_print_fix pr_c f
++ pr_comma () ++ pr pr_c args ++ str ")"
| Primitive (p,c,args,kargs) ->
str "ZPrimitive(" ++ str (CPrimitives.to_string p)
++ pr_comma () ++ pr pr_c args ++ str ")" and pr pr_c l = letopen Pp in
prlist_with_sep pr_semicolon (fun x -> hov 1 (pr_member pr_c x)) l
let empty = [] let is_empty = CList.is_empty
let append_app v s = let le = Array.length v in if Int.equal le 0 then s elseApp (0,v,pred le) :: s
let decomp_rev = function
| App (i,l,j) :: sk -> if i < j then Some (l.(j), App (i,l,pred j) :: sk) else Some (l.(j), sk)
| _ -> None
let decomp_node_last (i,l,j) sk = if i < j then (l.(j), App (i,l,pred j) :: sk) else (l.(j), sk)
exception IncompatibleFold2 let fold2 f o sk1 sk2 = let rec aux o sk1 sk2 = match sk1,sk2 with
| [], [] -> o
| App n1 :: q1, App n2 :: q2 -> let t1,l1 = decomp_node_last n1 q1 in let t2,l2 = decomp_node_last n2 q2 in
aux (f o t1 t2) l1 l2
| Case ((_,_,pms1,((_, t1),_),_,a1)) :: q1, Case ((_,_,pms2, ((_, t2),_),_,a2)) :: q2 -> let f' o (_, t1) (_, t2) = f o t1 t2 in
aux (Array.fold_left2 f' (f (Array.fold_left2 f o pms1 pms2) t1 t2) a1 a2) q1 q2
| Proj (p1,_) :: q1, Proj (p2,_) :: q2 ->
aux o q1 q2
| Fix ((_,(_,a1,b1)),s1) :: q1, Fix ((_,(_,a2,b2)),s2) :: q2 -> let o' = aux (Array.fold_left2 f (Array.fold_left2 f o b1 b2) a1 a2) (List.rev s1) (List.rev s2) in
aux o' q1 q2
| (((App _|Case _|Proj _|Fix _|Primitive _) :: _|[]), _) -> raise IncompatibleFold2 in aux o (List.rev sk1) (List.rev sk2)
let append_app_list l s = let a = Array.of_list l in
append_app a s
let rec args_size = function
| App (i,_,j) :: s -> j + 1 - i + args_size s
| (Case _ | Fix _ | Proj _ | Primitive _) :: _ | [] -> 0
let strip_app s = let rec aux out = function
| ( App _ as e) :: s -> aux (e :: out) s
| s -> List.rev out,s in aux [] s
let strip_n_app n s = let rec aux n out = function
| App (i,a,j) as e :: s -> let nb = j - i + 1 in if n >= nb then
aux (n - nb) (e :: out) s else let p = i + n in
Some (CList.rev
(if Int.equal n 0 then out elseApp (i,a,p-1) :: out),
a.(p), if j > p thenApp (succ p,a,j) :: s else s)
| s -> None in aux n [] s
let decomp s = match strip_n_app 0 s with
| Some (_,a,s) -> Some (a,s)
| None -> None
let list_of_app_stack s = let rec aux = function
| App (i,a,j) :: s -> let (args',s') = aux s in let a' = Array.sub a i (j - i + 1) in
(Array.fold_right (fun x y -> x::y) a' args', s')
| s -> ([],s) in let (out,s') = aux s in match s' with [] -> Some out | _ -> None
let tail n0 s0 = let rec aux n s = if Int.equal n 0 then s else match s with
| App (i,a,j) :: s -> let nb = j - i + 1 in if n >= nb then
aux (n - nb) s else let p = i+n in if j >= p thenApp (p,a,j) :: s else s
| _ -> raise (Invalid_argument "Reductionops.Stack.tail") in aux n0 s0
let nth s p = match strip_n_app p s with
| Some (_,el,_) -> el
| None -> raise Not_found
let zip sigma s = let rec zip = function
| f, [] -> f
| f, (App (i,a,j) :: s) -> let a' = if Int.equal i 0 && Int.equal j (Array.length a - 1) then a else Array.sub a i (j - i + 1) in
zip (mkApp (f, a'), s)
| f, (Case (ci,u,pms,rt,iv,br)::s) -> zip (mkCase (ci,u,pms,rt,iv,f,br), s)
| f, (Fix (fix,st)::s) -> zip
(mkFix fix, st @ (append_app [|f|] s))
| f, (Proj (p,r)::s) -> zip (mkProj (p,r,f),s)
| f, (Primitive (p,c,args,kargs)::s) ->
zip (mkConstU c, args @ append_app [|f|] s) in
zip s
(* Check if there is enough arguments on [stk] w.r.t. arity of [op] *) let check_native_args op stk = let nargs = CPrimitives.arity op in let rargs = args_size stk in
nargs <= rargs
let get_next_primitive_args kargs stk = let rec nargs = function
| [] -> 0
| (CPrimitives.Kwhnf | CPrimitives.Karg) :: _ -> 0
| CPrimitives.Kparam :: s -> 1 + nargs s in let n = nargs kargs in
(List.skipn (n+1) kargs, strip_n_app n stk)
let expand_case env sigma ((ci, u, pms, t, iv, br) : case_stk) = let dummy = mkProp in let (ci, u, pms, t, _, _, br) = EConstr.annotate_case env sigma (ci, u, pms, t, iv, dummy, br) in
(ci, u, pms, t, br)
end
(** The type of (machine) states (= lambda-bar-calculus' cuts) *) type state = constr * Stack.t
type stack_reduction_function =
env -> evar_map -> constr -> constr * constr list
type state_reduction_function =
env -> evar_map -> state -> state
let pr_state env sigma (tm,sk) = letopen Pp in let pr c = Termops.Internal.print_constr_env env sigma c in
h (pr tm ++ str "|" ++ cut () ++ Stack.pr pr sk)
let safe_meta_value metas ev = match metas with
| None -> None
| Some f -> f.meta_value ev
(*************************************) (*** Reduction using bindingss ***) (*************************************)
(* Beta Reduction tools *)
let apply_subst env sigma t stack = let rec aux env t stack = match (Stack.decomp stack, EConstr.kind sigma t) with
| Some (h,stacktl), Lambda (_,_,c) ->
aux (h::env) c stacktl
| _ -> (substl env t, stack) in
aux env t stack
let beta_applist sigma (c,l) =
Stack.zip sigma (apply_subst [] sigma c (Stack.append_app_list l Stack.empty))
(* Iota reduction tools *)
let reducible_mind_case sigma c = match EConstr.kind sigma c with
| Construct _ | CoFix _ -> true
| _ -> false
let contract_cofix sigma (bodynum,(names,types,bodies as typedbodies)) = let nbodies = Array.length bodies in let make_Fi j = let ind = nbodies-j-1 in
mkCoFix (ind,typedbodies) in let closure = List.init nbodies make_Fi in
substl closure bodies.(bodynum)
(** Similar to the "fix" case below *) let reduce_and_refold_cofix env sigma cofix sk = let raw_answer = contract_cofix sigma cofix in
apply_subst [] sigma raw_answer sk
(* contracts fix==FIX[nl;i](A1...Ak;[F1...Fk]{B1....Bk}) to produce
Bi[Fj --> FIX[nl;j](A1...Ak;[F1...Fk]{B1...Bk})] *)
let contract_fix sigma ((recindices,bodynum),(names,types,bodies as typedbodies)) = let nbodies = Array.length recindices in let make_Fi j = let ind = nbodies-j-1 in
mkFix ((recindices,ind),typedbodies) in let closure = List.init nbodies make_Fi in
substl closure bodies.(bodynum)
(** First we substitute the Rel bodynum by the fixpoint and then we try to replace the fixpoint by the best constant from [cst_l] Other rels are directly substituted by constants "magically found from the
context" in contract_fix *) let reduce_and_refold_fix env sigma fix sk = let raw_answer = contract_fix sigma fix in
apply_subst [] sigma raw_answer sk
open Primred
module CNativeEntries = struct
open UnsafeMonomorphic
type elem = EConstr.t type args = EConstr.t array type evd = evar_map type uinstance = EConstr.EInstance.t
let get = Array.get
let get_int evd e = match EConstr.kind evd e with
| Int i -> i
| _ -> raise Primred.NativeDestKO
let get_float evd e = match EConstr.kind evd e with
| Float f -> f
| _ -> raise Primred.NativeDestKO
let get_string evd e = match EConstr.kind evd e with
| String s -> s
| _ -> raise Primred.NativeDestKO
let get_parray evd e = match EConstr.kind evd e with
| Array(_u,t,def,_ty) -> Parray.of_array t def
| _ -> raise Not_found
let mkInt env i =
mkInt i
let mkFloat env f =
mkFloat f
let mkString env s =
mkString s
let mkBool env b = let (ct,cf) = get_bool_constructors env in
mkConstruct (if b then ct else cf)
let mkCarry env b e = let int_ty = mkConst @@ get_int_type env in let (c0,c1) = get_carry_constructors env in
mkApp (mkConstruct (if b then c1 else c0),[|int_ty;e|])
let mkIntPair env e1 e2 = let int_ty = mkConst @@ get_int_type env in let c = get_pair_constructor env in
mkApp(mkConstruct c, [|int_ty;int_ty;e1;e2|])
let mkFloatIntPair env f i = let float_ty = mkConst @@ get_float_type env in let int_ty = mkConst @@ get_int_type env in let c = get_pair_constructor env in
mkApp(mkConstruct c, [|float_ty;int_ty;f;i|])
let mkLt env = let (_eq, lt, _gt) = get_cmp_constructors env in
mkConstruct lt
let mkEq env = let (eq, _lt, _gt) = get_cmp_constructors env in
mkConstruct eq
let mkGt env = let (_eq, _lt, gt) = get_cmp_constructors env in
mkConstruct gt
let mkFLt env = let (_eq, lt, _gt, _nc) = get_f_cmp_constructors env in
mkConstruct lt
let mkFEq env = let (eq, _lt, _gt, _nc) = get_f_cmp_constructors env in
mkConstruct eq
let mkFGt env = let (_eq, _lt, gt, _nc) = get_f_cmp_constructors env in
mkConstruct gt
let mkFNotComparable env = let (_eq, _lt, _gt, nc) = get_f_cmp_constructors env in
mkConstruct nc
let mkPNormal env = let (pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct pNormal
let mkNNormal env = let (_pNormal,nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct nNormal
let mkPSubn env = let (_pNormal,_nNormal,pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct pSubn
let mkNSubn env = let (_pNormal,_nNormal,_pSubn,nSubn,_pZero,_nZero,_pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct nSubn
let mkPZero env = let (_pNormal,_nNormal,_pSubn,_nSubn,pZero,_nZero,_pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct pZero
let mkNZero env = let (_pNormal,_nNormal,_pSubn,_nSubn,_pZero,nZero,_pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct nZero
let mkPInf env = let (_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,pInf,_nInf,_nan) =
get_f_class_constructors env in
mkConstruct pInf
let mkNInf env = let (_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,nInf,_nan) =
get_f_class_constructors env in
mkConstruct nInf
let mkNaN env = let (_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,nan) =
get_f_class_constructors env in
mkConstruct nan
let mkArray env u t ty = let (t,def) = Parray.to_array t in
mkArray(u,t,def,ty)
end
module CredNative = RedNative(CNativeEntries)
(** Generic reduction function with environment
Here is where unfolded constant are stored in order to be eventually refolded.
If tactic_mode is true, it uses ReductionBehaviour, prefers refold constant instead of value and tries to infer constants fix and cofix came from.
It substitutes fix and cofix by the constant they come from in contract_* in any case .
*)
let debug_RAKAM = CDebug.create ~name:"RAKAM" ()
let apply_branch env sigma (ind, i) args (ci, u, pms, iv, r, lf) = let args = Stack.tail ci.ci_npar args in let args = Option.get (Stack.list_of_app_stack args) in let br = lf.(i - 1) in if Int.equal ci.ci_cstr_nargs.(i - 1) ci.ci_cstr_ndecls.(i - 1) then (* No let-bindings *) let subst = List.rev args in
Vars.substl subst (snd br) else (* For backwards compat with unification, we do not reduce the let-bindings
upfront. *) let ctx = expand_branch env sigma u pms (ind, i) br in
applist (it_mkLambda_or_LetIn (snd br) ctx, args)
exception PatternFailure
let match_einstance sigma pu u psubst = match UVars.Instance.pattern_match pu (EInstance.kind sigma u) psubst with
| Some psubst -> psubst
| None -> raise PatternFailure
let match_sort ps s psubst = match Sorts.pattern_match ps s psubst with
| Some psubst -> psubst
| None -> raise PatternFailure
let rec match_arg_pattern whrec env sigma ctx psubst p t = letopen Declarations in let t' = EConstr.it_mkLambda_or_LetIn t ctx in match p with
| EHole i -> Partial_subst.add_term i t' psubst
| EHoleIgnored -> psubst
| ERigid (ph, es) -> let t, stk = whrec (t, Stack.empty) in let psubst = match_rigid_arg_pattern whrec env sigma ctx psubst ph t in let psubst, stk = apply_rule whrec env sigma ctx psubst es stk in if Stack.is_empty stk then psubst elseraise PatternFailure
and match_rigid_arg_pattern whrec env sigma ctx psubst p t = match [@ocaml.warning "-4"] p, EConstr.kind sigma t with
| PHInd (ind, pu), Ind (ind', u) -> if QInd.equal env ind ind' then match_einstance sigma pu u psubst else raise PatternFailure
| PHConstr (constr, pu), Construct (constr', u) -> if QConstruct.equal env constr constr' then match_einstance sigma pu u psubst else raise PatternFailure
| PHRel i, Rel n when i = n -> psubst
| PHSort ps, Sort s -> match_sort ps (ESorts.kind sigma s) psubst
| PHSymbol (c, pu), Const (c', u) -> if QConstant.equal env c c' then match_einstance sigma pu u psubst else raise PatternFailure
| PHInt i, Int i' -> if Uint63.equal i i' then psubst else raise PatternFailure
| PHFloat f, Float f' -> if Float64.equal f f' then psubst else raise PatternFailure
| PHString s, String s' -> if Pstring.equal s s' then psubst else raise PatternFailure
| PHLambda (ptys, pbod), _ -> let ntys, _ = EConstr.decompose_lambda sigma t in let na = List.length ntys and np = Array.length ptys in if np > na thenraise PatternFailure; let ntys, body = EConstr.decompose_lambda_n sigma np t in let ctx' = List.map (fun (n, ty) -> Context.Rel.Declaration.LocalAssum (n, ty)) ntys in let tys = Array.of_list @@ List.rev_map snd ntys in let na = Array.length tys in let contexts_upto = Array.init na (fun i -> List.skipn (na - i) ctx' @ ctx) in let psubst = Array.fold_left3 (fun psubst ctx -> match_arg_pattern whrec env sigma ctx psubst) psubst contexts_upto ptys tys in let psubst = match_arg_pattern whrec env sigma (ctx' @ ctx) psubst pbod body in
psubst
| PHProd (ptys, pbod), _ -> let ntys, _ = EConstr.decompose_prod sigma t in let na = List.length ntys and np = Array.length ptys in if np > na thenraise PatternFailure; let ntys, body = EConstr.decompose_prod_n sigma np t in let ctx' = List.map (fun (n, ty) -> Context.Rel.Declaration.LocalAssum (n, ty)) ntys in let tys = Array.of_list @@ List.rev_map snd ntys in let na = Array.length tys in let contexts_upto = Array.init na (fun i -> List.skipn (na - i) ctx' @ ctx) in let psubst = Array.fold_left3 (fun psubst ctx -> match_arg_pattern whrec env sigma ctx psubst) psubst contexts_upto ptys tys in let psubst = match_arg_pattern whrec env sigma (ctx' @ ctx) psubst pbod body in
psubst
| (PHInd _ | PHConstr _ | PHRel _ | PHSort _ | PHSymbol _ | PHInt _ | PHFloat _ | PHString _), _ -> raise PatternFailure
and extract_n_stack args n s = if n = 0 thenList.rev args, s else match Stack.decomp s with
| Some (arg, rest) -> extract_n_stack (arg :: args) (n-1) rest
| None -> raise PatternFailure
and apply_rule whrec env sigma ctx psubst es stk = match [@ocaml.warning "-4"] es, stk with
| [], _ -> psubst, stk
| Declarations.PEApp pargs :: e, s -> let np = Array.length pargs in let pargs = Array.to_list pargs in let args, s = extract_n_stack [] np s in let psubst = List.fold_left2 (match_arg_pattern whrec env sigma ctx) psubst pargs args in
apply_rule whrec env sigma ctx psubst e s
| Declarations.PECase (pind, pu, pret, pbrs) :: e, Stack.Case (ci, u, pms, p, iv, brs) :: s -> ifnot @@ QInd.equal env pind ci.ci_ind thenraise PatternFailure; let dummy = mkProp in let psubst = match_einstance sigma pu u psubst in let (_, _, _, ((ntys_ret, ret), _), _, _, brs) = EConstr.annotate_case env sigma (ci, u, pms, p, NoInvert, dummy, brs) in let psubst = match_arg_pattern whrec env sigma (ntys_ret @ ctx) psubst pret ret in let psubst = Array.fold_left2 (fun psubst pat (ctx', br) -> match_arg_pattern whrec env sigma (ctx' @ ctx) psubst pat br) psubst pbrs brs in
apply_rule whrec env sigma ctx psubst e s
| Declarations.PEProj proj :: e, Stack.Proj (proj', r) :: s -> ifnot @@ QProjection.Repr.equal env proj (Projection.repr proj') then raise PatternFailure;
apply_rule whrec env sigma ctx psubst e s
| _, _ -> raise PatternFailure
let rec apply_rules whrec env sigma u r stk = letopen Declarations in match r with
| [] -> raise PatternFailure
| { lhs_pat = (pu, elims); nvars; rhs } :: rs -> try let psubst = Partial_subst.make nvars in let psubst = match_einstance sigma pu u psubst in let psubst, stk = apply_rule whrec env sigma [] psubst elims stk in let subst, qsubst, usubst = Partial_subst.to_arrays psubst in let usubst = UVars.Instance.of_array (qsubst, usubst) in let rhsu = subst_instance_constr (EConstr.EInstance.make usubst) (EConstr.of_constr rhs) in let rhs' = substl (Array.to_list subst) rhsu in
(rhs', stk) with PatternFailure -> apply_rules whrec env sigma u rs stk
let whd_state_gen flags ?metas env sigma = letopen Context.Named.Declaration in let rec whrec (x, stack) : state = let () = letopen Pp in let pr c = Termops.Internal.print_constr_env env sigma c in
debug_RAKAM (fun () ->
(h (str "<<" ++ pr x ++
str "|" ++ cut () ++ Stack.pr pr stack ++
str ">>"))) in let c0 = EConstr.kind sigma x in let fold () = let () = debug_RAKAM (fun () -> letopen Pp in str "<><><><><>") in
((EConstr.of_kind c0, stack)) in match c0 with
| Rel n when RedFlags.red_set flags RedFlags.fDELTA ->
(match lookup_rel n env with
| LocalDef (_,body,_) -> whrec (lift n body, stack)
| _ -> fold ())
| Var id when RedFlags.red_set flags (RedFlags.fVAR id) ->
(match lookup_named id env with
| LocalDef (_,body,_) ->
whrec (body, stack)
| _ -> fold ())
| Evar ev -> fold ()
| Meta ev ->
(match safe_meta_value metas ev with
| Some body -> whrec (body, stack)
| None -> fold ())
| Const (c,u as const) ->
reduction_effect_hook env sigma c
(lazy (EConstr.to_constr sigma (Stack.zip sigma (x,fst (Stack.strip_app stack))))); if RedFlags.red_set flags (RedFlags.fCONST c) then let u' = EInstance.kind sigma u in match constant_value_in env (c, u') with
| body -> begin let body = EConstr.of_constr body in
whrec (body, stack) end
| exception NotEvaluableConst (IsPrimitive (u,p)) when Stack.check_native_args p stack -> let kargs = CPrimitives.kind p in let (kargs,o) = Stack.get_next_primitive_args kargs stack in (* Should not fail thanks to [check_native_args] *) let (before,a,after) = Option.get o in
whrec (a,Stack.Primitive(p,const,before,kargs)::after)
| exception NotEvaluableConst (HasRules (u', b, r)) -> begintry let rhs, stack = apply_rules whrec env sigma u r stack in
whrec (rhs, stack) with PatternFailure -> ifnot b then fold () else match Stack.strip_app stack with
| args, (Stack.Fix (f,s')::s'') when RedFlags.red_set flags RedFlags.fFIX -> let x' = Stack.zip sigma (x, args) in let out_sk = s' @ (Stack.append_app [|x'|] s'') in
whrec (reduce_and_refold_fix env sigma f out_sk)
| _ -> fold () end
| exception NotEvaluableConst _ -> fold () else fold ()
| Proj (p, r, c) when RedFlags.red_projection flags p -> let stack' = (c, Stack.Proj (p,r) :: stack) in
whrec stack'
| LetIn (_,b,_,c) when RedFlags.red_set flags RedFlags.fZETA ->
whrec (apply_subst [b] sigma c stack)
| Cast (c,_,_) -> whrec (c, stack)
| App (f,cl) ->
whrec
(f, Stack.append_app cl stack)
| Lambda (na,t,c) ->
(match Stack.decomp stack with
| Some _ when RedFlags.red_set flags RedFlags.fBETA ->
whrec (apply_subst [] sigma x stack)
| _ -> fold ())
| Case (ci,u,pms,p,iv,d,lf) ->
whrec (d, Stack.Case (ci,u,pms,p,iv,lf) :: stack)
| Construct (cstr ,u) -> let use_match = RedFlags.red_set flags RedFlags.fMATCH in let use_fix = RedFlags.red_set flags RedFlags.fFIX in if use_match || use_fix then match Stack.strip_app stack with
|args, (Stack.Casecase::s') when use_match -> let r = apply_branch env sigma cstr args casein
whrec (r, s')
|args, (Stack.Proj (p,_)::s') when use_match ->
whrec (Stack.nth args (Projection.npars p + Projection.arg p), s')
|args, (Stack.Fix (f,s')::s'') when use_fix -> let x' = Stack.zip sigma (x, args) in let out_sk = s' @ (Stack.append_app [|x'|] s'') in
whrec (reduce_and_refold_fix env sigma f out_sk)
|_, (Stack.App _)::_ -> assert false
|_, _ -> fold () else fold ()
| CoFix cofix -> if RedFlags.red_set flags RedFlags.fCOFIX then match Stack.strip_app stack with
|args, ((Stack.Case _ |Stack.Proj _)::s') ->
whrec (reduce_and_refold_cofix env sigma cofix stack)
|_ -> fold () else fold ()
| Int _ | Float _ | String _ | Array _ -> beginmatch Stack.strip_app stack with
| (_, Stack.Primitive(p,(_, u as kn),rargs,kargs)::s) -> let more_to_reduce = List.exists (fun k -> CPrimitives.Kwhnf = k) kargs in if more_to_reduce then let (kargs,o) = Stack.get_next_primitive_args kargs s in (* Should not fail because Primitive is put on the stack only if fully applied *) let (before,a,after) = Option.get o in
whrec (a,Stack.Primitive(p,kn,rargs @ Stack.append_app [|x|] before,kargs)::after) else let n = List.length kargs in let (args,s) = Stack.strip_app s in let (args,extra_args) = tryList.chop n args withList.IndexOutOfRange -> (args,[]) (* FIXME probably useless *) in let args = Array.of_list (Option.get (Stack.list_of_app_stack (rargs @ Stack.append_app [|x|] args))) in let s = extra_args @ s in beginmatch CredNative.red_prim env sigma p u args with
| Some t -> whrec (t,s)
| None -> ((mkApp (mkConstU kn, args), s)) end
| _ -> fold () end
| Rel _ | Var _ | LetIn _ | Proj _ -> fold ()
| Sort _ | Ind _ | Prod _ -> fold () in
whrec
(** reduction machine without global env and refold machinery *) let local_whd_state_gen flags ?metas env sigma = let rec whrec (x, stack) = let c0 = EConstr.kind sigma x in let s = (EConstr.of_kind c0, stack) in match c0 with
| LetIn (_,b,_,c) when RedFlags.red_set flags RedFlags.fZETA ->
whrec (apply_subst [b] sigma c stack)
| Cast (c,_,_) -> whrec (c, stack)
| App (f,cl) -> whrec (f, Stack.append_app cl stack)
| Lambda (_,_,c) ->
(match Stack.decomp stack with
| Some (a,m) when RedFlags.red_set flags RedFlags.fBETA ->
whrec (apply_subst [a] sigma c m)
| _ -> s)
| Proj (p,r,c) when RedFlags.red_projection flags p ->
(whrec (c, Stack.Proj (p,r) :: stack))
| Case (ci,u,pms,p,iv,d,lf) ->
whrec (d, Stack.Case (ci,u,pms,p,iv,lf) :: stack)
| Fix ((ri,n),_ as f) ->
(match Stack.strip_n_app ri.(n) stack with
|None -> s
|Some (bef,arg,s') -> whrec (arg, Stack.Fix(f,bef)::s'))
| Evar ev -> s
| Meta ev ->
(match safe_meta_value metas ev with
Some c -> whrec (c,stack)
| None -> s)
| Construct (cstr, u) -> let use_match = RedFlags.red_set flags RedFlags.fMATCH in let use_fix = RedFlags.red_set flags RedFlags.fFIX in if use_match || use_fix then match Stack.strip_app stack with
|args, (Stack.Casecase :: s') when use_match -> let r = apply_branch env sigma cstr args casein
whrec (r, s')
|args, (Stack.Proj (p,_) :: s') when use_match ->
whrec (Stack.nth args (Projection.npars p + Projection.arg p), s')
|args, (Stack.Fix (f,s')::s'') when use_fix -> let x' = Stack.zip sigma (x,args) in
whrec (contract_fix sigma f, s' @ (Stack.append_app [|x'|] s''))
|_, (Stack.App _)::_ -> assert false
|_, _ -> s else s
| CoFix cofix -> if RedFlags.red_set flags RedFlags.fCOFIX then match Stack.strip_app stack with
|args, ((Stack.Case _ | Stack.Proj _)::s') ->
whrec (contract_cofix sigma cofix, stack)
|_ -> s else s
| Rel _ | Var _ | Sort _ | Prod _ | LetIn _ | Const _ | Ind _ | Proj _
| Int _ | Float _ | String _ | Array _ -> s
in
whrec
let stack_red_of_state_red f ?metas = let f env sigma x = EConstr.decompose_app_list sigma (Stack.zip sigma (f ?metas env sigma (x, Stack.empty))) in
f
let red_of_state_red ?metas ~delta f env sigma x = let rec is_whnf c = match Constr.kind c with
| Const _ | Var _ -> not delta
| Construct _ | Ind _ | Int _ | Float _ | String _
| Sort _ | Prod _ -> true
| App (h,_) -> is_whnf h
| _ -> false in (* preserve physical equality if possible not sure if anything relies on reduction unfolding head evars
for now use Unsafe.to_constr to keep such unfolds *) if is_whnf (EConstr.Unsafe.to_constr x) then x else Stack.zip sigma (f ?metas env sigma (x,Stack.empty))
(* 0. No Reduction Functions *)
let whd_nored_state = local_whd_state_gen RedFlags.nored let whd_nored_stack = stack_red_of_state_red whd_nored_state let whd_nored ?metas = red_of_state_red ?metas ~delta:false whd_nored_state
(* 1. Beta Reduction Functions *)
let whd_beta_state = local_whd_state_gen RedFlags.beta let whd_beta_stack = stack_red_of_state_red whd_beta_state let whd_beta = red_of_state_red ~delta:false whd_beta_state
let whd_betalet_state = local_whd_state_gen RedFlags.betazeta let whd_betalet_stack = stack_red_of_state_red whd_betalet_state let whd_betalet = red_of_state_red ~delta:false whd_betalet_state
(* 2. Delta Reduction Functions *)
let whd_const_state c e = whd_state_gen RedFlags.(mkflags [fCONST c]) e let whd_const c = red_of_state_red ~delta:true (fun ?metas -> whd_const_state c)
let whd_delta_state = whd_state_gen RedFlags.delta let whd_delta_stack = stack_red_of_state_red whd_delta_state let whd_delta = red_of_state_red ~delta:true whd_delta_state
let whd_betadeltazeta_state = whd_state_gen RedFlags.betadeltazeta let whd_betadeltazeta_stack = stack_red_of_state_red whd_betadeltazeta_state let whd_betadeltazeta = red_of_state_red ~delta:true whd_betadeltazeta_state
(* 3. Iota reduction Functions *)
let whd_betaiota_state = local_whd_state_gen RedFlags.betaiota let whd_betaiota_stack = stack_red_of_state_red whd_betaiota_state let whd_betaiota ?metas = red_of_state_red ?metas ~delta:false whd_betaiota_state
let whd_betaiotazeta_state = local_whd_state_gen RedFlags.betaiotazeta let whd_betaiotazeta_stack = stack_red_of_state_red whd_betaiotazeta_state let whd_betaiotazeta ?metas = red_of_state_red ?metas ~delta:false whd_betaiotazeta_state
let whd_all_state = whd_state_gen RedFlags.all let whd_all_stack = stack_red_of_state_red whd_all_state let whd_all ?metas = red_of_state_red ?metas ~delta:true whd_all_state
let whd_allnolet_state = whd_state_gen RedFlags.allnolet let whd_allnolet_stack = stack_red_of_state_red whd_allnolet_state let whd_allnolet = red_of_state_red ~delta:true whd_allnolet_state
let whd_stack_gen reds = stack_red_of_state_red (whd_state_gen reds)
let is_head_evar env sigma c = let head, _ = whd_all_state env sigma (c,Stack.empty) in
EConstr.isEvar sigma head
(* 4. Ad-hoc eta reduction *)
let shrink_eta sigma c = let rec whrec x = match EConstr.kind sigma x with
| Cast (c, _, _) -> whrec c
| Lambda (_, _, c) -> let (f, cl) = decompose_app sigma (whrec c) in let napp = Array.length cl in if napp > 0 then let x' = whrec (Array.last cl) in match EConstr.kind sigma x' with
| Rel 1 -> let lc = Array.sub cl 0 (napp-1) in let u = mkApp (f, lc) in if noccurn sigma 1 u then pop u else x
| _ -> x else x
| Meta _ | App _ | Case _ | Fix _ | Construct _ | CoFix _ | Evar _ | Rel _ | Var _ | Sort _ | Prod _
| LetIn _ | Const _ | Ind _ | Proj _ | Int _ | Float _ | String _ | Array _ -> x in
whrec c
(* 5. Zeta Reduction Functions *)
let whd_zeta_state = local_whd_state_gen RedFlags.zeta let whd_zeta_stack = stack_red_of_state_red whd_zeta_state let whd_zeta = red_of_state_red ~delta:false whd_zeta_state
(* Replacing defined evars for error messages *) let whd_evar = Evarutil.whd_evar let nf_evar = Evarutil.nf_evar
(* lazy reduction functions. The infos must be created for each term *) (* Note by HH [oct 08] : why would it be the job of clos_norm_flags to add
a [nf_evar] here *) let clos_norm_flags flgs env sigma t = try
EConstr.of_constr (CClosure.norm_term
(Evarutil.create_clos_infos env sigma flgs)
(CClosure.create_tab ())
(Esubst.subs_id 0, UVars.Instance.empty) (EConstr.Unsafe.to_constr t)) with e when is_anomaly e -> user_err Pp.(str "Tried to normalize ill-typed term")
let clos_whd_flags flgs env sigma t = try
EConstr.of_constr (CClosure.whd_val
(Evarutil.create_clos_infos env sigma flgs)
(CClosure.create_tab ())
(CClosure.inject (EConstr.Unsafe.to_constr t))) with e when is_anomaly e -> user_err Pp.(str "Tried to normalize ill-typed term")
let nf_beta = clos_norm_flags RedFlags.beta let nf_betaiota = clos_norm_flags RedFlags.betaiota let nf_betaiotazeta = clos_norm_flags RedFlags.betaiotazeta let nf_zeta = clos_norm_flags RedFlags.zeta let nf_all env sigma =
clos_norm_flags RedFlags.all env sigma
let is_transparent e k = match Conv_oracle.get_strategy (Environ.oracle e) (Evaluable.to_kevaluable k) with
| Conv_oracle.Opaque -> false
| _ -> true
(* Conversion utility functions *)
type conversion_test = Constraints.t -> Constraints.t
(* NOTE: We absorb anomalies happening in the conversion tactic, which is a bit ugly. This is mostly due to efficiency both in tactics and in the conversion machinery itself. It is not uncommon for a tactic to send some ill-typed term to the engine.
We would usually say that a tactic that converts ill-typed terms is buggy, but fixing the tactic could have a very large runtime cost
*)
exception AnomalyInConversion of exn
let _ = CErrors.register_handler (function
| AnomalyInConversion e ->
Some Pp.(str "Conversion test raised an anomaly:" ++
spc () ++ CErrors.print e)
| _ -> None)
let report_anomaly (e, info) = let e = if is_anomaly e then AnomalyInConversion e else e in
Exninfo.iraise (e, info)
module CheckUnivs = struct
open Conversion
let check_eq univs u u' = if Evd.check_eq univs u u' then Result.Ok univs else Result.Error None
let check_leq univs u u' = if Evd.check_leq univs u u' then Result.Ok univs else Result.Error None
let checked_sort_cmp_universes _env pb s0 s1 univs = let s0 = ESorts.make s0 in let s1 = ESorts.make s1 in match pb with
| CUMUL -> check_leq univs s0 s1
| CONV -> check_eq univs s0 s1
let check_convert_instances ~flex:_ u u' univs = let csts = UVars.enforce_eq_instances u u' (Sorts.QConstraints.empty,Constraints.empty) in if Evd.check_quconstraints univs csts then Result.Ok univs else Result.Error None
(* general conversion and inference functions *) let check_inductive_instances cv_pb variance u1 u2 univs = let csts = get_cumulativity_constraints cv_pb variance u1 u2 in if (Evd.check_quconstraints univs csts) then Result.Ok univs else Result.Error None
let is_fconv ?(reds=TransparentState.full) pb env sigma t1 t2 = let univs = Evd.universes sigma in let t1 = EConstr.Unsafe.to_constr t1 in let t2 = EConstr.Unsafe.to_constr t2 in let b = match pb with
| Conversion.CUMUL -> leq_constr_univs univs t1 t2
| Conversion.CONV -> eq_constr_univs univs t1 t2 in if b thentrue else let evars = Evd.evar_handler sigma in try let env = Environ.set_universes (Evd.universes sigma) env in beginmatch Conversion.generic_conv ~l2r:false pb ~evars reds env (sigma, CheckUnivs.checked_universes) t1 t2 with
| Result.Ok (_ : Evd.evar_map) -> true
| Result.Error None -> false
| Result.Error (Some e) -> Empty.abort e end with
| e -> let e = Exninfo.capture e in
report_anomaly e
let is_conv ?(reds=TransparentState.full) env sigma x y =
is_fconv ~reds Conversion.CONV env sigma x y let is_conv_leq ?(reds=TransparentState.full) env sigma x y =
is_fconv ~reds Conversion.CUMUL env sigma x y let check_conv ?(pb=Conversion.CUMUL) ?(ts=TransparentState.full) env sigma x y =
is_fconv ~reds:ts pb env sigma x y
let sigma_compare_sorts _env pb s0 s1 sigma = match pb with
| Conversion.CONV -> begin try Result.Ok (Evd.set_eq_sort sigma (ESorts.make s0) (ESorts.make s1)) with UGraph.UniverseInconsistency err -> Result.Error (Some err) end
| Conversion.CUMUL -> begin try Result.Ok (Evd.set_leq_sort sigma (ESorts.make s0) (ESorts.make s1)) with UGraph.UniverseInconsistency err -> Result.Error (Some err) end
let infer_conv_gen conv_fun ?(catch_incon=true) ?(pb=Conversion.CUMUL)
?(ts=TransparentState.full) env sigma x y = try let ans = match pb with
| Conversion.CUMUL ->
EConstr.leq_constr_universes env sigma x y
| Conversion.CONV ->
EConstr.eq_constr_universes env sigma x y in let ans = match ans with
| None -> None
| Some cstr -> try Some (Evd.add_universe_constraints sigma cstr) with UGraph.UniverseInconsistency _ | Evd.UniversesDiffer -> None in match ans with
| Some sigma -> ans
| None -> let x = EConstr.Unsafe.to_constr x in let y = EConstr.Unsafe.to_constr y in let env = Environ.set_universes (Evd.universes sigma) env in (* First try conversion with postponed universe problems as a kind of FO approximation. This may result in unsatisfiable constraints even if some unfoldings of the arguments could have been unified, but this
should be exceedingly rare. *) let ans = match conv_fun.genconv pb ~l2r:false sigma ts env (UnivProblem.Set.empty, univproblem_univ_state) x y with
| Result.Ok cstr -> Some cstr
| Result.Error None ->
None (* no universe unification can make these terms convertible *)
| Result.Error (Some e) -> Empty.abort e in match ans with
| None -> None
| Some cstr -> match Evd.add_universe_constraints sigma cstr with
| sigma -> Some sigma
| exception UGraph.UniverseInconsistency _ | exception Evd.UniversesDiffer -> (* Retry with local universe checking, which may imply constant unfolding *) match conv_fun.genconv pb ~l2r:false sigma ts env (sigma, sigma_univ_state) x y with
| Result.Ok sigma -> Some sigma
| Result.Error None -> None
| Result.Error (Some e) -> raise (UGraph.UniverseInconsistency e) with
| UGraph.UniverseInconsistency _ when catch_incon -> None
| e -> let e = Exninfo.capture e in
report_anomaly e
let infer_conv = infer_conv_gen { genconv = fun pb ~l2r sigma ->
Conversion.generic_conv pb ~l2r ~evars:(Evd.evar_handler sigma) }
let infer_conv_ustate ?(catch_incon=true) ?(pb=Conversion.CUMUL)
?(ts=TransparentState.full) env sigma x y = try let ans = match pb with
| Conversion.CUMUL ->
EConstr.leq_constr_universes env sigma x y
| Conversion.CONV ->
EConstr.eq_constr_universes env sigma x y in match ans with
| Some cstr -> Some cstr
| None -> let x = EConstr.Unsafe.to_constr x in let y = EConstr.Unsafe.to_constr y in let env = Environ.set_universes (Evd.universes sigma) env in match
Conversion.generic_conv pb ~l2r:false ~evars:(Evd.evar_handler sigma) ts
env (UnivProblem.Set.empty, univproblem_univ_state) x y with
| Result.Ok cstr -> Some cstr
| Result.Error None -> None
| Result.Error (Some e) -> raise (UGraph.UniverseInconsistency e) with
| UGraph.UniverseInconsistency _ when catch_incon -> None
| e -> let e = Exninfo.capture e in
report_anomaly e
let evars_of_evar_map sigma =
{ Genlambda.evars_val = Evd.evar_handler sigma }
let check_hyps_inclusion env sigma x hyps = let env = Environ.set_universes (Evd.universes sigma) env in let evars = Evd.evar_handler sigma in
Typeops.check_hyps_inclusion env ~evars x hyps
(* pseudo-reduction rule: * [hnf_prod_app env s (Prod(_,B)) N --> B[N] * with an HNF on the first argument to produce a product. * if this does not work, then we use the string S as part of our
* error message. *)
let hnf_prod_app env sigma t n = match EConstr.kind sigma (whd_all env sigma t) with
| Prod (_,_,b) -> subst1 n b
| _ -> anomaly ~label:"hnf_prod_app" (Pp.str "Need a product.")
let hnf_prod_appvect env sigma t nl =
Array.fold_left (fun acc t -> hnf_prod_app env sigma acc t) t nl
let hnf_prod_applist env sigma t nl = List.fold_left (fun acc t -> hnf_prod_app env sigma acc t) t nl
let hnf_lam_app env sigma t n = match EConstr.kind sigma (whd_all env sigma t) with
| Lambda (_,_,b) -> subst1 n b
| _ -> anomaly ~label:"hnf_lam_app" (Pp.str "Need an abstraction.")
let hnf_lam_appvect env sigma t nl =
Array.fold_left (fun acc t -> hnf_lam_app env sigma acc t) t nl
let hnf_lam_applist env sigma t nl = List.fold_left (fun acc t -> hnf_lam_app env sigma acc t) t nl
let whd_decompose_prod env sigma = let rec decrec env hyps c = let t = whd_all env sigma c in match EConstr.kind sigma t with
| Prod (n,a,c0) ->
decrec (push_rel (LocalAssum (n,a)) env) ((n,a)::hyps) c0
| _ -> hyps, t in
decrec env []
let whd_decompose_lambda env sigma = let rec decrec env hyps c = let t = whd_all env sigma c in match EConstr.kind sigma t with
| Lambda (n,a,c0) ->
decrec (push_rel (LocalAssum (n,a)) env) ((n,a)::hyps) c0
| _ -> hyps, t in
decrec env []
let whd_decompose_prod_n env sigma n = let rec decrec env m hyps c = if Int.equal m 0 then (hyps,c) else match EConstr.kind sigma (whd_all env sigma c) with
| Prod (n,a,c0) ->
decrec (push_rel (LocalAssum (n,a)) env) (m-1) ((n,a)::hyps) c0
| _ -> invalid_arg "whd_decompose_prod_n" in
decrec env n []
let whd_decompose_lambda_n env sigma n = let rec decrec env m hyps c = if Int.equal m 0 then (hyps,c) else match EConstr.kind sigma (whd_all env sigma c) with
| Lambda (n,a,c0) ->
decrec (push_rel (LocalAssum (n,a)) env) (m-1) ((n,a)::hyps) c0
| _ -> invalid_arg "whd_decompose_lambda_n" in
decrec env n []
let whd_decompose_prod_decls env sigma = let rec prodec_rec env l c = let t = whd_allnolet env sigma c in match EConstr.kind sigma t with
| Prod (x,t,c) -> let d = LocalAssum (x,t) in
prodec_rec (push_rel d env) (Context.Rel.add d l) c
| LetIn (x,b,t,c) -> (* note: there is a compromise in situations such as "let x := forall y, P in x": expose the let-in and stop looking
for products or ignore the let and find a new product *) let d = LocalDef (x,b,t) in
prodec_rec (push_rel d env) (Context.Rel.add d l) c
| _ -> (* deal with situations of the form "(let x:=t in fun y => u) v", or even "(let x:=fun y => u in x) v", ...
ideally, shouldn't we move instead the let-ins outside the redexes? *) let t' = whd_all env sigma t in if EConstr.eq_constr sigma t t' then l,t else prodec_rec env l t' in
prodec_rec env Context.Rel.empty
let splay_arity env sigma c = let l, c = whd_decompose_prod env sigma c in match EConstr.kind sigma c with
| Sort s -> l,s
| _ -> raise Reduction.NotArity
let dest_arity env sigma c = let l, c = whd_decompose_prod_decls env sigma c in match EConstr.kind sigma c with
| Sort s -> l,s
| _ -> raise Reduction.NotArity
let sort_of_arity env sigma c = snd (dest_arity env sigma c)
(* deprecated (wrong behavior) *) let hnf_decompose_prod_n_decls env sigma n = let rec decrec env m ln c = if Int.equal m 0 then (ln,c) else match EConstr.kind sigma (whd_all env sigma c) with
| Prod (n,a,c0) ->
decrec (push_rel (LocalAssum (n,a)) env)
(m-1) (Context.Rel.add (LocalAssum (n,a)) ln) c0
| _ -> invalid_arg "whd_decompose_prod_n_decls" in
decrec env n Context.Rel.empty
(* deprecated (wrong behavior) *) let hnf_decompose_lambda_n_assum env sigma n = let rec decrec env m ln c = if Int.equal m 0 then (ln,c) else match EConstr.kind sigma (whd_all env sigma c) with
| Lambda (n,a,c0) ->
decrec (push_rel (LocalAssum (n,a)) env)
(m-1) (Context.Rel.add (LocalAssum (n,a)) ln) c0
| _ -> invalid_arg "whd_decompose_lambda_n_assum" in
decrec env n Context.Rel.empty
let whd_decompose_prod_n_assum env sigma n = let rec decrec env m ctx c = if Int.equal m 0 then (ctx,c) else match EConstr.kind sigma (whd_allnolet env sigma c) with
| Prod (n,a,c0) -> let d = LocalAssum (n,a) in
decrec (push_rel d env) (m-1) (Context.Rel.add d ctx) c0
| LetIn (x,b,t,c) -> let d = LocalDef (x,b,t) in
decrec (push_rel d env) m (Context.Rel.add d ctx) c
| _ -> (* deal with situations of the form "(let x:=t in fun y => u) v", or even "(let x:=fun y => u in x) v", ...
ideally, shouldn't we move instead the let-ins outside the redexes? *) let c' = whd_all env sigma c in if EConstr.eq_constr sigma c c' then invalid_arg "whd_decompose_prod_n_assum" else decrec env m ctx c' in
decrec env n Context.Rel.empty
let whd_decompose_prod_n_decls env sigma n = let rec decrec env m ctx c = if Int.equal m 0 then (ctx,c) else match EConstr.kind sigma (whd_all env sigma c) with
| Prod (n,a,c0) -> let d = LocalAssum (n,a) in
decrec (push_rel d env) (m-1) (Context.Rel.add d ctx) c0
| LetIn (x,b,t,c) -> let d = LocalDef (x,b,t) in
decrec (push_rel d env) (m-1) (Context.Rel.add d ctx) c
| _ -> (* deal with situations of the form "(let x:=t in fun y => u) v", or even "(let x:=fun y => u in x) v", ...
ideally, shouldn't we move instead the let-ins outside the redexes? *) let c' = whd_all env sigma c in if EConstr.eq_constr sigma c c' then invalid_arg "whd_decompose_prod_n_decls" else decrec env m ctx c' in
decrec env n Context.Rel.empty
let whd_decompose_lambda_n_assum env sigma n = let rec decrec env m ctx c = if Int.equal m 0 then (ctx,c) else match EConstr.kind sigma (whd_allnolet env sigma c) with
| Lambda (n,a,c0) -> let d = LocalAssum (n,a) in
decrec (push_rel d env) (m-1) (Context.Rel.add d ctx) c0
| LetIn (x,b,t,c) -> let d = LocalDef (x,b,t) in
decrec (push_rel d env) m (Context.Rel.add d ctx) c
| _ -> (* deal with situations of the form "(let x:=t in fun y => u) v", or even "(let x:=fun y => u in x) v", ...
ideally, shouldn't we move instead the let-ins outside the redexes? *) let c' = whd_all env sigma c in if EConstr.eq_constr sigma c c' then invalid_arg "whd_decompose_lambda_n_assum" else decrec env m ctx c' in
decrec env n Context.Rel.empty
let is_sort env sigma t = match EConstr.kind sigma (whd_all env sigma t) with
| Sort s -> true
| _ -> false
(* reduction to head-normal-form allowing delta/zeta only in argument
of case/fix (heuristic used by evar_conv) *)
let whd_betaiota_deltazeta_for_iota_state ts ?metas env sigma s = letall' = RedFlags.red_add_transparent RedFlags.all ts in (* Unset the sharing flag to get a call-by-name reduction. This matters for
the shape of the generated term. *) let env' = Environ.set_typing_flags { (Environ.typing_flags env) with Declarations.share_reduction = false } env in let whd_opt c = letopen CClosure in let infos = Evarutil.create_clos_infos env' sigma all'in let tab = create_tab () in let c = inject (EConstr.Unsafe.to_constr (Stack.zip sigma c)) in let (c, stk) = whd_stack infos tab c [] in match fterm_of c with
| (FConstruct _ | FCoFix _) -> (* Non-neutral normal, can trigger reduction below *) let c = EConstr.of_constr (term_of_process c stk) in
Some (decompose_app sigma c)
| _ -> None in let rec whrec s = let (t, stack as s) = whd_state_gen RedFlags.betaiota ?metas env sigma s in let rewrite_step = match kind sigma t with
| Const (cst, u) when Environ.is_symbol env cst -> let r = Environ.lookup_rewrite_rules cst env in beginmatch apply_rules whrec env sigma u r stack with
| r -> Some r
| exception PatternFailure -> None end
| _ -> None in match rewrite_step with
| Some r -> whrec r
| None -> match Stack.strip_app stack with
|args, (Stack.Case _ :: _ as stack') -> beginmatch whd_opt (t, args) with
| Some (t_o, args) when reducible_mind_case sigma t_o -> whrec (t_o, Stack.append_app args stack')
| (Some _ | None) -> s end
|args, (Stack.Fix _ :: _ as stack') -> beginmatch whd_opt (t, args) with
| Some (t_o, args) when isConstruct sigma t_o -> whrec (t_o, Stack.append_app args stack')
| (Some _ | None) -> s end
|args, (Stack.Proj (p,_) :: stack'') -> beginmatch whd_opt (t, args) with
| Some (t_o, args) when isConstruct sigma t_o ->
whrec (args.(Projection.npars p + Projection.arg p), stack'')
| (Some _ | None) -> s end
|_, ((Stack.App _|Stack.Primitive _) :: _|[]) -> s in
whrec s
let find_conclusion env sigma = let rec decrec env c = let t = whd_all env sigma c in match EConstr.kind sigma t with
| Prod (x,t,c0) -> decrec (push_rel (LocalAssum (x,t)) env) c0
| Lambda (x,t,c0) -> decrec (push_rel (LocalAssum (x,t)) env) c0
| t -> t in
decrec env
let is_arity env sigma c = match find_conclusion env sigma c with
| Sort _ -> true
| _ -> false
module Infer = struct
open Conversion
let infer_eq (univs, cstrs as cuniv) u u' = if UGraph.check_eq_sort univs u u' then Result.Ok cuniv elsetry let cstrs' = UnivSubst.enforce_eq_sort u u' Constraints.empty in
Result.Ok (UGraph.merge_constraints cstrs' univs, Constraints.union cstrs cstrs') with UGraph.UniverseInconsistency err -> Result.Error (Some err)
let infer_leq (univs, cstrs as cuniv) u u' = if UGraph.check_leq_sort univs u u' then Result.Ok cuniv elsematch UnivSubst.enforce_leq_alg_sort u u' univs with
| cstrs', univs ->
Result.Ok (univs, Univ.Constraints.union cstrs cstrs')
| exception UGraph.UniverseInconsistency err -> Result.Error (Some err)
let infer_cmp_universes _env pb s0 s1 univs = match pb with
| CUMUL -> infer_leq univs s0 s1
| CONV -> infer_eq univs s0 s1
let infer_convert_instances ~flex u u' (univs,cstrs as cuniv) = if flex then if UGraph.check_eq_instances univs u u' then Result.Ok cuniv else Result.Error None else let qcstrs, cstrs' = UVars.enforce_eq_instances u u' Sorts.QUConstraints.empty in if Sorts.QConstraints.trivial qcstrs then
Result.Ok (univs, Constraints.union cstrs cstrs') else
Result.Error None
let infer_inductive_instances cv_pb variance u1 u2 (univs,csts) = let qcsts, csts' = get_cumulativity_constraints cv_pb variance u1 u2 in if Sorts.QConstraints.trivial qcsts then match UGraph.merge_constraints csts' univs with
| univs -> Result.Ok (univs, Univ.Constraints.union csts csts')
| exception (UGraph.UniverseInconsistency err) -> Result.Error (Some err) else Result.Error None
let splay_prod = whd_decompose_prod let splay_lam = whd_decompose_lambda let splay_prod_assum = whd_decompose_prod_decls let splay_prod_n = hnf_decompose_prod_n_decls let splay_lam_n = hnf_decompose_lambda_n_assum
let hnf_decompose_prod = whd_decompose_prod let hnf_decompose_lambda = whd_decompose_lambda let hnf_decompose_prod_decls = whd_decompose_prod_decls
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.