(************************************************************************) (* * 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 havetheNeverUnfoldflag.Therefore,thetablehasadistinctsubpart
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 >= 2then1else2) " 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 *)
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 0then 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 + 1in if n >= nb then
aux (n - nb) (e :: out) s else let p = i + n in
Some (CList.rev
(if Int.equal n 0then 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 0then s else match s with
| App (i,a,j) :: s -> let nb = j - i + 1in 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-1in
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-1in
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 replacethefixpointbythebestconstantfrom[cst_l] Otherrelsaredirectlysubstitutedbyconstants"magicallyfoundfromthe
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)
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 = 0thenList.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 notsureifanythingreliesonreductionunfoldingheadevars
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 > 0then 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 isabitugly.Thisismostlyduetoefficiencybothintacticsand intheconversionmachineryitself.Itisnotuncommonforatactic tosendsomeill-typedtermtotheengine.
Wewouldusuallysaythatatacticthatconvertsill-typedtermsis buggy,butfixingthetacticcouldhaveaverylargeruntimecost
*)
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.Thismayresultinunsatisfiableconstraintsevenif someunfoldingsoftheargumentscouldhavebeenunified,butthis
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
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 0then (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 0then (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 "letx:=forally,Pinx":exposethelet-inandstoplooking
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 "(letx:=funy=>uinx)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 0then (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 0then (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 0then (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 "(letx:=funy=>uinx)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 0then (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 "(letx:=funy=>uinx)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 0then (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 "(letx:=funy=>uinx)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
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet am 2026-06-10)
¤
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 und die Messung sind noch experimentell.