aboutsummaryrefslogtreecommitdiff
path: root/tactics
diff options
context:
space:
mode:
Diffstat (limited to 'tactics')
-rw-r--r--tactics/cbn.ml797
-rw-r--r--tactics/cbn.mli13
-rw-r--r--tactics/class_tactics.ml14
-rw-r--r--tactics/eauto.ml179
-rw-r--r--tactics/hints.ml8
-rw-r--r--tactics/hints.mli32
-rw-r--r--tactics/redexpr.ml6
-rw-r--r--tactics/tactics.mllib1
8 files changed, 905 insertions, 145 deletions
diff --git a/tactics/cbn.ml b/tactics/cbn.ml
new file mode 100644
index 0000000000..21e38df6db
--- /dev/null
+++ b/tactics/cbn.ml
@@ -0,0 +1,797 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2019 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \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 Util
+open Names
+open Constr
+open Context
+open Termops
+open Univ
+open Evd
+open Environ
+open EConstr
+open Vars
+open Context.Rel.Declaration
+
+(** This module implements a call by name reduction used by the cbn tactic.
+
+ It has an ability to "refold" constants by storing constants and
+ their parameters in its stack.
+*)
+
+(** Machinery to custom the behavior of the reduction *)
+module ReductionBehaviour = Reductionops.ReductionBehaviour
+
+(** Machinery about stack of unfolded constants *)
+module Cst_stack = struct
+ open EConstr
+
+(** constant * params * args
+
+- constant applied to params = term in head applied to args
+- there is at most one arguments with an empty list of args, it must be the first.
+- in args, the int represents the indice of the first arg to consider *)
+ type t = (constr * constr list * (int * constr array) list) list
+
+ let empty = []
+ let is_empty = CList.is_empty
+
+ let drop_useless = function
+ | _ :: ((_,_,[])::_ as q) -> q
+ | l -> l
+
+ let add_param h cst_l =
+ let append2cst = function
+ | (c,params,[]) -> (c, h::params, [])
+ | (c,params,((i,t)::q)) when i = pred (Array.length t) ->
+ (c, params, q)
+ | (c,params,(i,t)::q) ->
+ (c, params, (succ i,t)::q)
+ in
+ drop_useless (List.map append2cst cst_l)
+
+ let add_args cl =
+ List.map (fun (a,b,args) -> (a,b,(0,cl)::args))
+
+ let add_cst cst = function
+ | (_,_,[]) :: q as l -> l
+ | l -> (cst,[],[])::l
+
+ let best_cst = function
+ | (cst,params,[])::_ -> Some(cst,params)
+ | _ -> None
+
+ let reference sigma t = match best_cst t with
+ | Some (c, _) when isConst sigma c -> Some (fst (destConst sigma c))
+ | _ -> None
+
+ (** [best_replace d cst_l c] makes the best replacement for [d]
+ by [cst_l] in [c] *)
+ let best_replace sigma d cst_l c =
+ let reconstruct_head = List.fold_left
+ (fun t (i,args) -> mkApp (t,Array.sub args i (Array.length args - i))) in
+ List.fold_right
+ (fun (cst,params,args) t -> Termops.replace_term sigma
+ (reconstruct_head d args)
+ (applist (cst, List.rev params))
+ t) cst_l c
+
+ let pr env sigma l =
+ let open Pp in
+ let p_c c = Termops.Internal.print_constr_env env sigma c in
+ prlist_with_sep pr_semicolon
+ (fun (c,params,args) ->
+ hov 1 (str"(" ++ p_c c ++ str ")" ++ spc () ++ pr_sequence p_c params ++ spc () ++ str "(args:" ++
+ pr_sequence (fun (i,el) -> prvect_with_sep spc p_c (Array.sub el i (Array.length el - i))) args ++
+ str ")")) l
+end
+
+
+(** The type of (machine) stacks (= lambda-bar-calculus' contexts) *)
+module Stack :
+sig
+ open EConstr
+ type 'a app_node
+
+ type cst_member =
+ | Cst_const of pconstant
+ | Cst_proj of Projection.t
+
+ type 'a member =
+ | App of 'a app_node
+ | Case of case_info * 'a * 'a array * Cst_stack.t
+ | Proj of Projection.t * Cst_stack.t
+ | Fix of ('a, 'a) pfixpoint * 'a t * Cst_stack.t
+ | Primitive of CPrimitives.t * (Constant.t * EInstance.t) * 'a t * CPrimitives.args_red * Cst_stack.t
+ | Cst of cst_member * int * int list * 'a t * Cst_stack.t
+
+ and 'a t = 'a member list
+
+ exception IncompatibleFold2
+
+ val pr : ('a -> Pp.t) -> 'a t -> Pp.t
+ val empty : 'a t
+ val append_app : 'a array -> 'a t -> 'a t
+ val decomp : 'a t -> ('a * 'a t) option
+ val equal : ('a -> 'a -> bool) -> (('a, 'a) pfixpoint -> ('a, 'a) pfixpoint -> bool)
+ -> 'a t -> 'a t -> bool
+ val strip_app : 'a t -> 'a t * 'a t
+ val strip_n_app : int -> 'a t -> ('a t * 'a * 'a t) option
+ val will_expose_iota : 'a t -> bool
+ val list_of_app_stack : constr t -> constr list option
+ val args_size : 'a t -> int
+ val tail : int -> 'a t -> 'a t
+ val nth : 'a t -> int -> 'a
+ val best_state : evar_map -> constr * constr t -> Cst_stack.t -> constr * constr t
+ val zip : ?refold:bool -> evar_map -> constr * constr t -> constr
+ val check_native_args : CPrimitives.t -> 'a t -> bool
+ val get_next_primitive_args : CPrimitives.args_red -> 'a t -> CPrimitives.args_red * ('a t * 'a * 'a t) option
+end =
+struct
+ open EConstr
+ type 'a app_node = int * 'a array * int
+ (* first releavnt position, arguments, last relevant position *)
+
+ (*
+ Invariant that this module must ensure :
+ (behare of direct access to app_node by the rest of Reductionops)
+ - in app_node (i,_,j) i <= j
+ - There is no array realocation (outside of debug printing)
+ *)
+
+ let pr_app_node pr (i,a,j) =
+ let open Pp in surround (
+ prvect_with_sep pr_comma pr (Array.sub a i (j - i + 1))
+ )
+
+
+ type cst_member =
+ | Cst_const of pconstant
+ | Cst_proj of Projection.t
+
+ type 'a member =
+ | App of 'a app_node
+ | Case of case_info * 'a * 'a array * Cst_stack.t
+ | Proj of Projection.t * Cst_stack.t
+ | Fix of ('a, 'a) pfixpoint * 'a t * Cst_stack.t
+ | Primitive of CPrimitives.t * (Constant.t * EInstance.t) * 'a t * CPrimitives.args_red * Cst_stack.t
+ | Cst of cst_member * int * int list * 'a t * Cst_stack.t
+
+ and 'a t = 'a member list
+
+ (* Debugging printer *)
+ let rec pr_member pr_c member =
+ let open Pp in
+ let pr_c x = hov 1 (pr_c x) in
+ match member with
+ | App app -> str "ZApp" ++ pr_app_node pr_c app
+ | Case (_,_,br,cst) ->
+ str "ZCase(" ++
+ prvect_with_sep (pr_bar) pr_c br
+ ++ str ")"
+ | Proj (p,cst) ->
+ str "ZProj(" ++ Constant.debug_print (Projection.constant p) ++ str ")"
+ | Fix (f,args,cst) ->
+ str "ZFix(" ++ Constr.debug_print_fix pr_c f
+ ++ pr_comma () ++ pr pr_c args ++ str ")"
+ | Primitive (p,c,args,kargs,cst_l) ->
+ str "ZPrimitive(" ++ str (CPrimitives.to_string p)
+ ++ pr_comma () ++ pr pr_c args ++ str ")"
+ | Cst (mem,curr,remains,params,cst_l) ->
+ str "ZCst(" ++ pr_cst_member pr_c mem ++ pr_comma () ++ int curr
+ ++ pr_comma () ++
+ prlist_with_sep pr_semicolon int remains ++
+ pr_comma () ++ pr pr_c params ++ str ")"
+ and pr pr_c l =
+ let open Pp in
+ prlist_with_sep pr_semicolon (fun x -> hov 1 (pr_member pr_c x)) l
+
+ and pr_cst_member pr_c c =
+ let open Pp in
+ match c with
+ | Cst_const (c, u) ->
+ if Univ.Instance.is_empty u then Constant.debug_print c
+ else str"(" ++ Constant.debug_print c ++ str ", " ++
+ Univ.Instance.pr Univ.Level.pr u ++ str")"
+ | Cst_proj p ->
+ str".(" ++ Constant.debug_print (Projection.constant p) ++ str")"
+
+ let empty = []
+
+ let append_app v s =
+ let le = Array.length v in
+ if Int.equal le 0 then s else App (0,v,pred le) :: s
+
+ let decomp_node (i,l,j) sk =
+ if i < j then (l.(i), App (succ i,l,j) :: sk)
+ else (l.(i), sk)
+
+ let decomp = function
+ | App node::s -> Some (decomp_node node s)
+ | _ -> 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)
+
+ let equal f f_fix sk1 sk2 =
+ let equal_cst_member x y =
+ match x, y with
+ | Cst_const (c1,u1), Cst_const (c2, u2) ->
+ Constant.equal c1 c2 && Univ.Instance.equal u1 u2
+ | Cst_proj p1, Cst_proj p2 -> Projection.repr_equal p1 p2
+ | _, _ -> false
+ in
+ let rec equal_rec sk1 sk2 =
+ match sk1,sk2 with
+ | [],[] -> true
+ | App a1 :: s1, App a2 :: s2 ->
+ let t1,s1' = decomp_node_last a1 s1 in
+ let t2,s2' = decomp_node_last a2 s2 in
+ (f t1 t2) && (equal_rec s1' s2')
+ | Case (_,t1,a1,_) :: s1, Case (_,t2,a2,_) :: s2 ->
+ f t1 t2 && CArray.equal (fun x y -> f x y) a1 a2 && equal_rec s1 s2
+ | (Proj (p,_)::s1, Proj(p2,_)::s2) ->
+ Projection.Repr.equal (Projection.repr p) (Projection.repr p2)
+ && equal_rec s1 s2
+ | Fix (f1,s1,_) :: s1', Fix (f2,s2,_) :: s2' ->
+ f_fix f1 f2
+ && equal_rec (List.rev s1) (List.rev s2)
+ && equal_rec s1' s2'
+ | Cst (c1,curr1,remains1,params1,_)::s1', Cst (c2,curr2,remains2,params2,_)::s2' ->
+ equal_cst_member c1 c2
+ && equal_rec (List.rev params1) (List.rev params2)
+ && equal_rec s1' s2'
+ | ((App _|Case _|Proj _|Fix _|Cst _|Primitive _)::_|[]), _ -> false
+ in equal_rec (List.rev sk1) (List.rev sk2)
+
+ exception IncompatibleFold2
+
+ 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 _|Cst _|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 else App (i,a,p-1) :: out),
+ a.(p),
+ if j > p then App(succ p,a,j)::s else s)
+ | s -> None
+ in aux n [] s
+
+ let will_expose_iota args =
+ List.exists
+ (function (Fix (_,_,l) | Case (_,_,_,l) |
+ Proj (_,l) | Cst (_,_,_,_,l)) when Cst_stack.is_empty l -> true | _ -> false)
+ args
+
+ 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
+ let init = match s' with [] -> true | _ -> false in
+ Option.init init out
+
+ 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 then App(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
+
+ (** This function breaks the abstraction of Cst_stack ! *)
+ let best_state sigma (_,sk as s) l =
+ let rec aux sk def = function
+ |(cst, params, []) -> (cst, append_app_list (List.rev params) sk)
+ |(cst, params, (i,t)::q) -> match decomp sk with
+ | Some (el,sk') when EConstr.eq_constr sigma el t.(i) ->
+ if i = pred (Array.length t)
+ then aux sk' def (cst, params, q)
+ else aux sk' def (cst, params, (succ i,t)::q)
+ | _ -> def
+ in List.fold_left (aux sk) s l
+
+ let constr_of_cst_member f sk =
+ match f with
+ | Cst_const (c, u) -> mkConstU (c, EInstance.make u), sk
+ | Cst_proj p ->
+ match decomp sk with
+ | Some (hd, sk) -> mkProj (p, hd), sk
+ | None -> assert false
+
+ let zip ?(refold=false) 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,rt,br,cst_l)::s) when refold ->
+ zip (best_state sigma (mkCase (ci,rt,f,br), s) cst_l)
+ | f, (Case (ci,rt,br,_)::s) -> zip (mkCase (ci,rt,f,br), s)
+ | f, (Fix (fix,st,cst_l)::s) when refold ->
+ zip (best_state sigma (mkFix fix, st @ (append_app [|f|] s)) cst_l)
+ | f, (Fix (fix,st,_)::s) -> zip
+ (mkFix fix, st @ (append_app [|f|] s))
+ | f, (Cst (cst,_,_,params,cst_l)::s) when refold ->
+ zip (best_state sigma (constr_of_cst_member cst (params @ (append_app [|f|] s))) cst_l)
+ | f, (Cst (cst,_,_,params,_)::s) ->
+ zip (constr_of_cst_member cst (params @ (append_app [|f|] s)))
+ | f, (Proj (p,cst_l)::s) when refold ->
+ zip (best_state sigma (mkProj (p,f),s) cst_l)
+ | f, (Proj (p,_)::s) -> zip (mkProj (p,f),s)
+ | f, (Primitive (p,c,args,kargs,cst_l)::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 :: _ -> 0
+ | _ :: s -> 1 + nargs s
+ in
+ let n = nargs kargs in
+ (List.skipn (n+1) kargs, strip_n_app n stk)
+
+end
+
+(** The type of (machine) states (= lambda-bar-calculus' cuts) *)
+
+(*************************************)
+(*** Reduction Functions Operators ***)
+(*************************************)
+
+let safe_meta_value sigma ev =
+ try Some (Evd.meta_value sigma ev)
+ with Not_found -> None
+
+(*************************************)
+(*** Reduction using bindingss ***)
+(*************************************)
+
+(* Beta Reduction tools *)
+
+let apply_subst recfun env sigma refold cst_l t stack =
+ let rec aux env cst_l t stack =
+ match (Stack.decomp stack, EConstr.kind sigma t) with
+ | Some (h,stacktl), Lambda (_,_,c) ->
+ let cst_l' = if refold then Cst_stack.add_param h cst_l else cst_l in
+ aux (h::env) cst_l' c stacktl
+ | _ -> recfun sigma cst_l (substl env t, stack)
+ in aux env cst_l t stack
+
+(* Iota reduction tools *)
+
+(** @return c if there is a constant c whose body is bd
+ @return bd else.
+
+ It has only a meaning because internal representation of "Fixpoint f x
+ := t" is Definition f := fix f x => t
+
+ Even more fragile that we could hope because do Module M. Fixpoint
+ f x := t. End M. Definition f := u. and say goodbye to any hope
+ of refolding M.f this way ...
+*)
+let magically_constant_of_fixbody env sigma reference bd = function
+ | Name.Anonymous -> bd
+ | Name.Name id ->
+ let open UnivProblem in
+ let (cst_mod,_) = Constant.repr2 reference in
+ let cst = Constant.make2 cst_mod (Label.of_id id) in
+ if not (Environ.mem_constant cst env) then bd
+ else
+ let (cst, u), ctx = UnivGen.fresh_constant_instance env cst in
+ match constant_opt_value_in env (cst,u) with
+ | None -> bd
+ | Some t ->
+ let csts = EConstr.eq_constr_universes env sigma (EConstr.of_constr t) bd in
+ begin match csts with
+ | Some csts ->
+ let subst = Set.fold (fun cst acc ->
+ let l, r = match cst with
+ | ULub (u, v) | UWeak (u, v) -> u, v
+ | UEq (u, v) | ULe (u, v) ->
+ let get u = Option.get (Universe.level u) in
+ get u, get v
+ in
+ Univ.LMap.add l r acc)
+ csts Univ.LMap.empty
+ in
+ let inst = Instance.subst_fn (fun u -> Univ.LMap.find u subst) u in
+ mkConstU (cst, EInstance.make inst)
+ | None -> bd
+ end
+
+let contract_cofix ?env sigma ?reference (bodynum,(names,types,bodies as typedbodies)) =
+ let nbodies = Array.length bodies in
+ let make_Fi j =
+ let ind = nbodies-j-1 in
+ if Int.equal bodynum ind then mkCoFix (ind,typedbodies)
+ else
+ let bd = mkCoFix (ind,typedbodies) in
+ match env with
+ | None -> bd
+ | Some e ->
+ match reference with
+ | None -> bd
+ | Some r -> magically_constant_of_fixbody e sigma r bd names.(ind).binder_name in
+ let closure = List.init nbodies make_Fi in
+ substl closure bodies.(bodynum)
+
+(** Similar to the "fix" case below *)
+let reduce_and_refold_cofix recfun env sigma refold cst_l cofix sk =
+ let raw_answer =
+ let env = if refold then Some env else None in
+ contract_cofix ?env sigma ?reference:(Cst_stack.reference sigma cst_l) cofix in
+ apply_subst
+ (fun sigma x (t,sk') ->
+ let t' =
+ if refold then Cst_stack.best_replace sigma (mkCoFix cofix) cst_l t else t in
+ recfun x (t',sk'))
+ [] sigma refold Cst_stack.empty 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 ?env sigma ?reference ((recindices,bodynum),(names,types,bodies as typedbodies)) =
+ let nbodies = Array.length recindices in
+ let make_Fi j =
+ let ind = nbodies-j-1 in
+ if Int.equal bodynum ind then mkFix ((recindices,ind),typedbodies)
+ else
+ let bd = mkFix ((recindices,ind),typedbodies) in
+ match env with
+ | None -> bd
+ | Some e ->
+ match reference with
+ | None -> bd
+ | Some r -> magically_constant_of_fixbody e sigma r bd names.(ind).binder_name 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 recfun env sigma refold cst_l fix sk =
+ let raw_answer =
+ let env = if refold then Some env else None in
+ contract_fix ?env sigma ?reference:(Cst_stack.reference sigma cst_l) fix in
+ apply_subst
+ (fun sigma x (t,sk') ->
+ let t' =
+ if refold then
+ Cst_stack.best_replace sigma (mkFix fix) cst_l t
+ else t
+ in recfun x (t',sk'))
+ [] sigma refold Cst_stack.empty raw_answer sk
+
+module CredNative = Reductionops.CredNative
+
+(** 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 = Reductionops.debug_RAKAM
+
+let equal_stacks sigma (x, l) (y, l') =
+ let f_equal x y = eq_constr sigma x y in
+ let eq_fix a b = f_equal (mkFix a) (mkFix b) in
+ Stack.equal f_equal eq_fix l l' && f_equal x y
+
+let rec whd_state_gen ?csts ~refold ~tactic_mode flags env sigma =
+ let open Context.Named.Declaration in
+ let open ReductionBehaviour in
+ let rec whrec cst_l (x, stack) =
+ let () = if debug_RAKAM () then
+ let open Pp in
+ let pr c = Termops.Internal.print_constr_env env sigma c in
+ Feedback.msg_debug
+ (h 0 (str "<<" ++ pr x ++
+ str "|" ++ cut () ++ Cst_stack.pr env sigma cst_l ++
+ str "|" ++ cut () ++ Stack.pr pr stack ++
+ str ">>"))
+ in
+ let c0 = EConstr.kind sigma x in
+ let fold () =
+ let () = if debug_RAKAM () then
+ let open Pp in Feedback.msg_debug (str "<><><><><>") in
+ ((EConstr.of_kind c0, stack),cst_l)
+ in
+ match c0 with
+ | Rel n when CClosure.RedFlags.red_set flags CClosure.RedFlags.fDELTA ->
+ (match lookup_rel n env with
+ | LocalDef (_,body,_) -> whrec Cst_stack.empty (lift n body, stack)
+ | _ -> fold ())
+ | Var id when CClosure.RedFlags.red_set flags (CClosure.RedFlags.fVAR id) ->
+ (match lookup_named id env with
+ | LocalDef (_,body,_) ->
+ whrec (if refold then Cst_stack.add_cst (mkVar id) cst_l else cst_l) (body, stack)
+ | _ -> fold ())
+ | Evar ev -> fold ()
+ | Meta ev ->
+ (match safe_meta_value sigma ev with
+ | Some body -> whrec cst_l (body, stack)
+ | None -> fold ())
+ | Const (c,u as const) ->
+ Reductionops.reduction_effect_hook env sigma c
+ (lazy (EConstr.to_constr sigma (Stack.zip sigma (x,stack))));
+ if CClosure.RedFlags.red_set flags (CClosure.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
+ if not tactic_mode
+ then whrec (if refold then Cst_stack.add_cst (mkConstU const) cst_l else cst_l)
+ (body, stack)
+ else (* Looks for ReductionBehaviour *)
+ match ReductionBehaviour.get (GlobRef.ConstRef c) with
+ | None -> whrec (Cst_stack.add_cst (mkConstU const) cst_l) (body, stack)
+ | Some behavior ->
+ begin match behavior with
+ | NeverUnfold -> fold ()
+ | (UnfoldWhen { nargs = Some n } |
+ UnfoldWhenNoMatch { nargs = Some n } )
+ when Stack.args_size stack < n ->
+ fold ()
+ | UnfoldWhenNoMatch { recargs } -> (* maybe unfolds *)
+ let app_sk,sk = Stack.strip_app stack in
+ let (tm',sk'),cst_l' =
+ whrec (Cst_stack.add_cst (mkConstU const) cst_l) (body, app_sk)
+ in
+ let rec is_case x = match EConstr.kind sigma x with
+ | Lambda (_,_, x) | LetIn (_,_,_, x) | Cast (x, _,_) -> is_case x
+ | App (hd, _) -> is_case hd
+ | Case _ -> true
+ | _ -> false in
+ if equal_stacks sigma (x, app_sk) (tm', sk')
+ || Stack.will_expose_iota sk'
+ || is_case tm'
+ then fold ()
+ else whrec cst_l' (tm', sk' @ sk)
+ | UnfoldWhen { recargs } -> (* maybe unfolds *)
+ begin match recargs with
+ |[] -> (* if nargs has been specified *)
+ (* CAUTION : the constant is NEVER refold
+ (even when it hides a (co)fix) *)
+ whrec cst_l (body, stack)
+ |curr::remains -> match Stack.strip_n_app curr stack with
+ | None -> fold ()
+ | Some (bef,arg,s') ->
+ whrec Cst_stack.empty
+ (arg,Stack.Cst(Stack.Cst_const (fst const, u'),curr,remains,bef,cst_l)::s')
+ end
+ end
+ end
+ | exception NotEvaluableConst (IsPrimitive 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 Cst_stack.empty (a,Stack.Primitive(p,const,before,kargs,cst_l)::after)
+ | exception NotEvaluableConst _ -> fold ()
+ else fold ()
+ | Proj (p, c) when CClosure.RedFlags.red_projection flags p ->
+ (let npars = Projection.npars p in
+ if not tactic_mode then
+ let stack' = (c, Stack.Proj (p, Cst_stack.empty (*cst_l*)) :: stack) in
+ whrec Cst_stack.empty stack'
+ else match ReductionBehaviour.get (GlobRef.ConstRef (Projection.constant p)) with
+ | None ->
+ let stack' = (c, Stack.Proj (p, cst_l) :: stack) in
+ let stack'', csts = whrec Cst_stack.empty stack' in
+ if equal_stacks sigma stack' stack'' then fold ()
+ else stack'', csts
+ | Some behavior ->
+ begin match behavior with
+ | NeverUnfold -> fold ()
+ | (UnfoldWhen { nargs = Some n }
+ | UnfoldWhenNoMatch { nargs = Some n })
+ when Stack.args_size stack < n - (npars + 1) -> fold ()
+ | UnfoldWhen { recargs }
+ | UnfoldWhenNoMatch { recargs }-> (* maybe unfolds *)
+ let recargs = List.map_filter (fun x ->
+ let idx = x - npars in
+ if idx < 0 then None else Some idx) recargs
+ in
+ match recargs with
+ |[] -> (* if nargs has been specified *)
+ (* CAUTION : the constant is NEVER refold
+ (even when it hides a (co)fix) *)
+ let stack' = (c, Stack.Proj (p, cst_l) :: stack) in
+ whrec Cst_stack.empty(* cst_l *) stack'
+ | curr::remains ->
+ if curr == 0 then (* Try to reduce the record argument *)
+ whrec Cst_stack.empty
+ (c, Stack.Cst(Stack.Cst_proj p,curr,remains,Stack.empty,cst_l)::stack)
+ else
+ match Stack.strip_n_app curr stack with
+ | None -> fold ()
+ | Some (bef,arg,s') ->
+ whrec Cst_stack.empty
+ (arg,Stack.Cst(Stack.Cst_proj p,curr,remains,
+ Stack.append_app [|c|] bef,cst_l)::s')
+ end)
+
+ | LetIn (_,b,_,c) when CClosure.RedFlags.red_set flags CClosure.RedFlags.fZETA ->
+ apply_subst (fun _ -> whrec) [b] sigma refold cst_l c stack
+ | Cast (c,_,_) -> whrec cst_l (c, stack)
+ | App (f,cl) ->
+ whrec
+ (if refold then Cst_stack.add_args cl cst_l else cst_l)
+ (f, Stack.append_app cl stack)
+ | Lambda (na,t,c) ->
+ (match Stack.decomp stack with
+ | Some _ when CClosure.RedFlags.red_set flags CClosure.RedFlags.fBETA ->
+ apply_subst (fun _ -> whrec) [] sigma refold cst_l x stack
+ | None when CClosure.RedFlags.red_set flags CClosure.RedFlags.fETA ->
+ let env' = push_rel (LocalAssum (na, t)) env in
+ let whrec' = whd_state_gen ~refold ~tactic_mode flags env' sigma in
+ (match EConstr.kind sigma (Stack.zip ~refold sigma (fst (whrec' (c, Stack.empty)))) with
+ | App (f,cl) ->
+ let napp = Array.length cl in
+ if napp > 0 then
+ let (x', l'),_ = whrec' (Array.last cl, Stack.empty) in
+ match EConstr.kind sigma x', l' with
+ | Rel 1, [] ->
+ let lc = Array.sub cl 0 (napp-1) in
+ let u = if Int.equal napp 1 then f else mkApp (f,lc) in
+ if noccurn sigma 1 u then (pop u,Stack.empty),Cst_stack.empty else fold ()
+ | _ -> fold ()
+ else fold ()
+ | _ -> fold ())
+ | _ -> fold ())
+
+ | Case (ci,p,d,lf) ->
+ whrec Cst_stack.empty (d, Stack.Case (ci,p,lf,cst_l) :: stack)
+
+ | Fix ((ri,n),_ as f) ->
+ (match Stack.strip_n_app ri.(n) stack with
+ |None -> fold ()
+ |Some (bef,arg,s') ->
+ whrec Cst_stack.empty (arg, Stack.Fix(f,bef,cst_l)::s'))
+
+ | Construct ((ind,c),u) ->
+ let use_match = CClosure.RedFlags.red_set flags CClosure.RedFlags.fMATCH in
+ let use_fix = CClosure.RedFlags.red_set flags CClosure.RedFlags.fFIX in
+ if use_match || use_fix then
+ match Stack.strip_app stack with
+ |args, (Stack.Case(ci, _, lf,_)::s') when use_match ->
+ whrec Cst_stack.empty (lf.(c-1), (Stack.tail ci.ci_npar args) @ s')
+ |args, (Stack.Proj (p,_)::s') when use_match ->
+ whrec Cst_stack.empty (Stack.nth args (Projection.npars p + Projection.arg p), s')
+ |args, (Stack.Fix (f,s',cst_l)::s'') when use_fix ->
+ let x' = Stack.zip sigma (x, args) in
+ let out_sk = s' @ (Stack.append_app [|x'|] s'') in
+ reduce_and_refold_fix whrec env sigma refold cst_l f out_sk
+ |args, (Stack.Cst (const,curr,remains,s',cst_l) :: s'') ->
+ let x' = Stack.zip sigma (x, args) in
+ begin match remains with
+ | [] ->
+ (match const with
+ | Stack.Cst_const const ->
+ (match constant_opt_value_in env const with
+ | None -> fold ()
+ | Some body ->
+ let const = (fst const, EInstance.make (snd const)) in
+ let body = EConstr.of_constr body in
+ whrec (if refold then Cst_stack.add_cst (mkConstU const) cst_l else cst_l)
+ (body, s' @ (Stack.append_app [|x'|] s'')))
+ | Stack.Cst_proj p ->
+ let stack = s' @ (Stack.append_app [|x'|] s'') in
+ match Stack.strip_n_app 0 stack with
+ | None -> assert false
+ | Some (_,arg,s'') ->
+ whrec Cst_stack.empty (arg, Stack.Proj (p,cst_l) :: s''))
+ | next :: remains' -> match Stack.strip_n_app (next-curr-1) s'' with
+ | None -> fold ()
+ | Some (bef,arg,s''') ->
+ whrec Cst_stack.empty
+ (arg,
+ Stack.Cst (const,next,remains',s' @ (Stack.append_app [|x'|] bef),cst_l) :: s''')
+ end
+ |_, (Stack.App _)::_ -> assert false
+ |_, _ -> fold ()
+ else fold ()
+
+ | CoFix cofix ->
+ if CClosure.RedFlags.red_set flags CClosure.RedFlags.fCOFIX then
+ match Stack.strip_app stack with
+ |args, ((Stack.Case _ |Stack.Proj _)::s') ->
+ reduce_and_refold_cofix whrec env sigma refold cst_l cofix stack
+ |_ -> fold ()
+ else fold ()
+
+ | Int _ | Float _ ->
+ begin match Stack.strip_app stack with
+ | (_, Stack.Primitive(p,kn,rargs,kargs,cst_l')::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 Cst_stack.empty (a,Stack.Primitive(p,kn,rargs @ Stack.append_app [|x|] before,kargs,cst_l')::after)
+ else
+ let n = List.length kargs in
+ let (args,s) = Stack.strip_app s in
+ let (args,extra_args) =
+ try List.chop n args
+ with List.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
+ begin match CredNative.red_prim env sigma p args with
+ | Some t -> whrec cst_l' (t,s)
+ | None -> ((mkApp (mkConstU kn, args), s), cst_l)
+ end
+ | _ -> fold ()
+ end
+
+ | Rel _ | Var _ | LetIn _ | Proj _ -> fold ()
+ | Sort _ | Ind _ | Prod _ -> fold ()
+ in
+ fun xs ->
+ let (s,cst_l as res) = whrec (Option.default Cst_stack.empty csts) xs in
+ if tactic_mode then (Stack.best_state sigma s cst_l,Cst_stack.empty) else res
+
+let whd_cbn flags env sigma t =
+ let (state,_) =
+ (whd_state_gen ~refold:true ~tactic_mode:true flags env sigma (t, Stack.empty))
+ in
+ Stack.zip ~refold:true sigma state
diff --git a/tactics/cbn.mli b/tactics/cbn.mli
new file mode 100644
index 0000000000..af54771382
--- /dev/null
+++ b/tactics/cbn.mli
@@ -0,0 +1,13 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2019 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \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) *)
+(************************************************************************)
+
+val whd_cbn :
+ CClosure.RedFlags.reds ->
+ Environ.env -> Evd.evar_map -> EConstr.constr -> EConstr.constr
diff --git a/tactics/class_tactics.ml b/tactics/class_tactics.ml
index 80c76bee60..195073d7aa 100644
--- a/tactics/class_tactics.ml
+++ b/tactics/class_tactics.ml
@@ -516,25 +516,21 @@ let make_resolve_hyp env sigma st flags only_classes pri decl =
let is_class = iscl env cty in
let keep = not only_classes || is_class in
if keep then
- let c = mkVar id in
- let name = PathHints [GlobRef.VarRef id] in
+ let id = GlobRef.VarRef id in
+ let name = PathHints [id] in
let hints =
if is_class then
- let hints = build_subclasses ~check:false env sigma (GlobRef.VarRef id) empty_hint_info in
+ let hints = build_subclasses ~check:false env sigma id empty_hint_info in
(List.map_append
(fun (path,info,c) ->
let h = IsConstr (EConstr.of_constr c,Univ.ContextSet.empty) [@ocaml.warning "-3"] in
make_resolves env sigma ~name:(PathHints path)
- (true,false,not !Flags.quiet) info ~poly:false
+ (true,false,not !Flags.quiet) info ~check:true ~poly:false
h)
hints)
else []
in
- (hints @ List.map_filter
- (fun f -> try Some (f (c, cty, Univ.ContextSet.empty))
- with Failure _ | UserError _ -> None)
- [make_exact_entry ~name env sigma pri ~poly:false;
- make_apply_entry ~name env sigma flags pri ~poly:false])
+ (hints @ make_resolves env sigma flags pri ~name ~check:false ~poly:false (IsGlobRef id))
else []
let make_hints g (modes,st) only_classes sign =
diff --git a/tactics/eauto.ml b/tactics/eauto.ml
index 7d8620468d..c2eabffd44 100644
--- a/tactics/eauto.ml
+++ b/tactics/eauto.ml
@@ -59,32 +59,12 @@ let registered_e_assumption =
(* PROLOG tactic *)
(************************************************************************)
-(*s Tactics handling a list of goals. *)
-
-(* first_goal : goal list sigma -> goal sigma *)
-
-let first_goal gls =
- let gl = gls.Evd.it and sig_0 = gls.Evd.sigma in
- if List.is_empty gl then user_err Pp.(str "first_goal");
- { Evd.it = List.hd gl; Evd.sigma = sig_0; }
-
-(* tactic -> tactic_list : Apply a tactic to the first goal in the list *)
-
-let apply_tac_list tac glls =
- match glls.it with
- | (g1::rest) ->
- let pack = tac (re_sig g1 glls.sigma) in
- re_sig (pack.it @ rest) pack.sigma
- | _ -> user_err Pp.(str "apply_tac_list")
-
open Auto
(***************************************************************************)
(* A tactic similar to Auto, but using EApply, Assumption and e_give_exact *)
(***************************************************************************)
-let priority l = List.map snd (List.filter (fun (pr,_) -> Int.equal pr 0) l)
-
let unify_e_resolve poly flags (c,clenv) =
Proofview.Goal.enter begin fun gl ->
let clenv', c = connect_hint_clenv ~poly c clenv gl in
@@ -94,7 +74,9 @@ let unify_e_resolve poly flags (c,clenv) =
(Tactics.Simple.eapply c)
end
-let hintmap_of sigma secvars hdc concl =
+let hintmap_of sigma secvars concl =
+ (* Warning: for computation sharing, we need to return a closure *)
+ let hdc = try Some (decompose_app_bound sigma concl) with Bound -> None in
match hdc with
| None -> fun db -> Hint_db.map_none ~secvars db
| Some hdc ->
@@ -125,13 +107,13 @@ let rec e_trivial_fail_db db_list local_db =
let tacl =
registered_e_assumption ::
(Tacticals.New.tclTHEN Tactics.intro next) ::
- (List.map fst (e_trivial_resolve (Tacmach.New.pf_env gl) (Tacmach.New.project gl) db_list local_db secvars (Tacmach.New.pf_concl gl)))
+ (e_trivial_resolve (Tacmach.New.pf_env gl) (Tacmach.New.project gl) db_list local_db secvars (Tacmach.New.pf_concl gl))
in
Tacticals.New.tclSOLVE tacl
end
-and e_my_find_search env sigma db_list local_db secvars hdc concl =
- let hint_of_db = hintmap_of sigma secvars hdc concl in
+and e_my_find_search env sigma db_list local_db secvars concl =
+ let hint_of_db = hintmap_of sigma secvars concl in
let hintl =
List.map_append (fun db ->
let flags = auto_flags_of_state (Hint_db.transparent_state db) in
@@ -143,35 +125,40 @@ and e_my_find_search env sigma db_list local_db secvars hdc concl =
| Unfold_nth _ -> 1
| _ -> b
in
- (b,
- let tac = function
- | Res_pf (term,cl) -> unify_resolve ~poly st (term,cl)
- | ERes_pf (term,cl) -> unify_e_resolve poly st (term,cl)
- | Give_exact (c,cl) -> e_exact poly st (c,cl)
- | Res_pf_THEN_trivial_fail (term,cl) ->
- Tacticals.New.tclTHEN (unify_e_resolve poly st (term,cl))
- (e_trivial_fail_db db_list local_db)
- | Unfold_nth c -> reduce (Unfold [AllOccurrences,c]) onConcl
- | Extern tacast -> conclPattern concl p tacast
- in
- let tac = run_hint t tac in
- (tac, lazy (pr_hint env sigma t)))
+ let tac = function
+ | Res_pf (term,cl) -> unify_resolve ~poly st (term,cl)
+ | ERes_pf (term,cl) -> unify_e_resolve poly st (term,cl)
+ | Give_exact (c,cl) -> e_exact poly st (c,cl)
+ | Res_pf_THEN_trivial_fail (term,cl) ->
+ Tacticals.New.tclTHEN (unify_e_resolve poly st (term,cl))
+ (e_trivial_fail_db db_list local_db)
+ | Unfold_nth c -> reduce (Unfold [AllOccurrences,c]) onConcl
+ | Extern tacast -> conclPattern concl p tacast
+ in
+ let tac = run_hint t tac in
+ (tac, b, lazy (pr_hint env sigma t))
in
List.map tac_of_hint hintl
and e_trivial_resolve env sigma db_list local_db secvars gl =
- let hd = try Some (decompose_app_bound sigma gl) with Bound -> None in
- try priority (e_my_find_search env sigma db_list local_db secvars hd gl)
+ let filter (tac, pr, _) = if Int.equal pr 0 then Some tac else None in
+ try List.map_filter filter (e_my_find_search env sigma db_list local_db secvars gl)
with Not_found -> []
let e_possible_resolve env sigma db_list local_db secvars gl =
- let hd = try Some (decompose_app_bound sigma gl) with Bound -> None in
- try List.map (fun (b, (tac, pp)) -> (tac, b, pp))
- (e_my_find_search env sigma db_list local_db secvars hd gl)
+ try e_my_find_search env sigma db_list local_db secvars gl
with Not_found -> []
+(*s Tactics handling a list of goals. *)
+
+(* first_goal : goal list sigma -> goal sigma *)
+
let find_first_goal gls =
- try first_goal gls with UserError _ -> assert false
+ let gl = gls.Evd.it and sig_0 = gls.Evd.sigma in
+ match gl with
+ | [] -> assert false
+ | (gl, db) :: _ ->
+ { Evd.it = gl; Evd.sigma = sig_0; }, db
(*s The following module [SearchProblem] is used to instantiate the generic
exploration functor [Explore.Make]. *)
@@ -179,10 +166,9 @@ let find_first_goal gls =
type search_state = {
priority : int;
depth : int; (*r depth of search before failing *)
- tacres : Goal.goal list sigma;
+ tacres : (Goal.goal * hint_db) list sigma;
last_tactic : Pp.t Lazy.t;
dblist : hint_db list;
- localdb : hint_db list;
prev : prev_search_state;
local_lemmas : delayed_open_constr list;
}
@@ -200,7 +186,16 @@ module SearchProblem = struct
(* let pr_ev evs ev = Printer.pr_constr_env (Evd.evar_env ev) (Evarutil.nf_evar evs ev.Evd.evar_concl) *)
- let filter_tactics glls l =
+(* tactic -> tactic_list : Apply a tactic to the first goal in the list *)
+
+ let apply_tac_list tac mkdb glls =
+ match glls.it with
+ | ((g1, db) :: rest) ->
+ let pack = tac (re_sig g1 glls.sigma) in
+ List.map (fun gl -> gl, mkdb db (re_sig gl pack.sigma)) pack.it, re_sig rest pack.sigma
+ | _ -> user_err Pp.(str "apply_tac_list")
+
+ let filter_tactics mkdb glls l =
(* let _ = Proof_trees.db_pr_goal (List.hd (sig_it glls)) in *)
(* let evars = Evarutil.nf_evars (Refiner.project glls) in *)
(* msg (str"Goal:" ++ pr_ev evars (List.hd (sig_it glls)) ++ str"\n"); *)
@@ -208,10 +203,10 @@ module SearchProblem = struct
| [] -> []
| (tac, cost, pptac) :: tacl ->
try
- let lgls = apply_tac_list (Proofview.V82.of_tactic tac) glls in
+ let ngls, lgls = apply_tac_list (Proofview.V82.of_tactic tac) mkdb glls in
(* let gl = Proof_trees.db_pr_goal (List.hd (sig_it glls)) in *)
(* msg (hov 1 (pptac ++ str" gives: \n" ++ pr_goals lgls ++ str"\n")); *)
- (lgls, cost, pptac) :: aux tacl
+ (ngls, lgls, cost, pptac) :: aux tacl
with e when CErrors.noncritical e ->
let e = Exninfo.capture e in
Refiner.catch_failerror e; aux tacl
@@ -233,63 +228,54 @@ module SearchProblem = struct
else
let ps = if s.prev == Unknown then Unknown else State s in
let lg = s.tacres in
- let nbgl = List.length (sig_it lg) in
- assert (nbgl > 0);
- let g = find_first_goal lg in
+ let g, db = find_first_goal lg in
let hyps = pf_ids_of_hyps g in
let secvars = secvars_of_hyps (pf_hyps g) in
let map_assum id = (e_give_exact (mkVar id), (-1), lazy (str "exact" ++ spc () ++ Id.print id)) in
let assumption_tacs =
let tacs = List.map map_assum hyps in
- let l = filter_tactics s.tacres tacs in
- List.map (fun (res, cost, pp) -> { depth = s.depth; priority = cost; tacres = res;
+ let mkdb db gl = assert false in (* no goal can be generated *)
+ let l = filter_tactics mkdb s.tacres tacs in
+ List.map (fun (ngl, res, cost, pp) ->
+ let () = assert (List.is_empty ngl) in
+ { depth = s.depth; priority = cost; tacres = res;
last_tactic = pp; dblist = s.dblist;
- localdb = List.tl s.localdb;
prev = ps; local_lemmas = s.local_lemmas}) l
in
let intro_tac =
- let l = filter_tactics s.tacres [Tactics.intro, (-1), lazy (str "intro")] in
+ let mkdb db gl =
+ let hintl = make_resolve_hyp (pf_env gl) (project gl) (pf_last_hyp gl) in
+ Hint_db.add_list (pf_env gl) (project gl) hintl db
+ in
+ let l = filter_tactics mkdb s.tacres [Tactics.intro, (-1), lazy (str "intro")] in
List.map
- (fun (lgls, cost, pp) ->
- let g' = first_goal lgls in
- let hintl =
- make_resolve_hyp (pf_env g') (project g') (pf_last_hyp g')
- in
- let ldb = Hint_db.add_list (pf_env g') (project g')
- hintl (List.hd s.localdb) in
+ (fun (ngls, lgls, cost, pp) ->
+ let lgls = re_sig (ngls @ lgls.it) lgls.sigma in
{ depth = s.depth; priority = cost; tacres = lgls;
last_tactic = pp; dblist = s.dblist;
- localdb = ldb :: List.tl s.localdb; prev = ps;
+ prev = ps;
local_lemmas = s.local_lemmas})
l
in
let rec_tacs =
+ let hyps = pf_hyps g in
+ let mkdb db gls =
+ let hyps' = pf_hyps gls in
+ if hyps' == hyps then db
+ else make_local_hint_db (pf_env gls) (project gls) ~ts:TransparentState.full true s.local_lemmas
+ in
let l =
let concl = Reductionops.nf_evar (project g) (pf_concl g) in
- filter_tactics s.tacres
- (e_possible_resolve (pf_env g) (project g) s.dblist (List.hd s.localdb) secvars concl)
+ filter_tactics mkdb s.tacres
+ (e_possible_resolve (pf_env g) (project g) s.dblist db secvars concl)
in
List.map
- (fun (lgls, cost, pp) ->
- let nbgl' = List.length (sig_it lgls) in
- if nbgl' < nbgl then
- { depth = s.depth; priority = cost; tacres = lgls; last_tactic = pp;
- prev = ps; dblist = s.dblist; localdb = List.tl s.localdb;
- local_lemmas = s.local_lemmas }
- else
- let newlocal =
- let hyps = pf_hyps g in
- List.map (fun gl ->
- let gls = {Evd.it = gl; sigma = lgls.Evd.sigma } in
- let hyps' = pf_hyps gls in
- if hyps' == hyps then List.hd s.localdb
- else make_local_hint_db (pf_env gls) (project gls) ~ts:TransparentState.full true s.local_lemmas)
- (List.firstn ((nbgl'-nbgl) + 1) (sig_it lgls))
- in
- { depth = pred s.depth; priority = cost; tacres = lgls;
- dblist = s.dblist; last_tactic = pp; prev = ps;
- localdb = newlocal @ List.tl s.localdb;
- local_lemmas = s.local_lemmas })
+ (fun (ngls, lgls, cost, pp) ->
+ let lgls = re_sig (ngls @ lgls.it) lgls.sigma in
+ let depth = if List.is_empty ngls then s.depth else pred s.depth in
+ { depth; priority = cost; tacres = lgls; last_tactic = pp;
+ prev = ps; dblist = s.dblist;
+ local_lemmas = s.local_lemmas })
l
in
List.sort compare (assumption_tacs @ intro_tac @ rec_tacs)
@@ -353,15 +339,15 @@ let pr_info dbg s =
let make_initial_state dbg n gl dblist localdb lems =
{ depth = n;
priority = 0;
- tacres = tclIDTAC gl;
+ tacres = re_sig [gl.it, localdb] gl.sigma;
last_tactic = lazy (mt());
dblist = dblist;
- localdb = [localdb];
prev = if dbg == Info then Init else Unknown;
local_lemmas = lems;
}
-let e_search_auto debug (in_depth,p) lems db_list gl =
+let e_search_auto debug (in_depth,p) lems db_list =
+ Proofview.V82.tactic ~nf_evars:false begin fun gl ->
let local_db = make_local_hint_db (pf_env gl) (project gl) ~ts:TransparentState.full true lems in
let d = mk_eauto_dbg debug in
let tac = match in_depth,d with
@@ -374,28 +360,29 @@ let e_search_auto debug (in_depth,p) lems db_list gl =
pr_dbg_header d;
let s = tac (make_initial_state d p gl db_list local_db lems) in
pr_info d s;
- s.tacres
+ re_sig (List.map fst s.tacres.it) s.tacres.sigma
with Not_found ->
pr_info_nop d;
- user_err Pp.(str "eauto: search failed")
+ tclIDTAC gl
+ end
(* let e_search_auto_key = CProfile.declare_profile "e_search_auto" *)
(* let e_search_auto = CProfile.profile5 e_search_auto_key e_search_auto *)
let eauto_with_bases ?(debug=Off) np lems db_list =
- Hints.wrap_hint_warning (Proofview.V82.tactic (tclTRY (e_search_auto debug np lems db_list)))
+ Hints.wrap_hint_warning (e_search_auto debug np lems db_list)
let eauto ?(debug=Off) np lems dbnames =
let db_list = make_db_list dbnames in
- tclTRY (e_search_auto debug np lems db_list)
+ e_search_auto debug np lems db_list
-let full_eauto ?(debug=Off) n lems gl =
+let full_eauto ?(debug=Off) n lems =
let db_list = current_pure_db () in
- tclTRY (e_search_auto debug n lems db_list) gl
+ e_search_auto debug n lems db_list
let gen_eauto ?(debug=Off) np lems = function
- | None -> Hints.wrap_hint_warning (Proofview.V82.tactic (full_eauto ~debug np lems))
- | Some l -> Hints.wrap_hint_warning (Proofview.V82.tactic (eauto ~debug np lems l))
+ | None -> Hints.wrap_hint_warning (full_eauto ~debug np lems)
+ | Some l -> Hints.wrap_hint_warning (eauto ~debug np lems l)
let make_depth = function
| None -> !default_search_depth
diff --git a/tactics/hints.ml b/tactics/hints.ml
index a0670ef70d..0c23532e12 100644
--- a/tactics/hints.ml
+++ b/tactics/hints.ml
@@ -882,7 +882,7 @@ let fresh_global_or_constr env sigma poly cr =
(c, Univ.ContextSet.empty)
end
-let make_resolves env sigma flags info ~poly ?name cr =
+let make_resolves env sigma flags info ~check ~poly ?name cr =
let c, ctx = fresh_global_or_constr env sigma poly cr in
let cty = Retyping.get_type_of env sigma c in
let try_apply f =
@@ -891,7 +891,7 @@ let make_resolves env sigma flags info ~poly ?name cr =
[make_exact_entry env sigma info ~poly ?name;
make_apply_entry env sigma flags info ~poly ?name]
in
- if List.is_empty ents then
+ if check && List.is_empty ents then
user_err ~hdr:"Hint"
(pr_leconstr_env env sigma c ++ spc() ++
(if pi1 flags then str"cannot be used as a hint."
@@ -1183,7 +1183,7 @@ let add_resolves env sigma clist ~local ~superglobal dbnames =
let r =
List.flatten (List.map (fun (pri, poly, hnf, path, gr) ->
make_resolves env sigma (true,hnf,not !Flags.quiet)
- pri ~poly ~name:path gr) clist)
+ pri ~check:true ~poly ~name:path gr) clist)
in
let hint = make_hint ~local dbname (AddHints { superglobal; hints = r }) in
Lib.add_anonymous_leaf (inAutoHint hint))
@@ -1334,7 +1334,7 @@ let expand_constructor_hints env sigma lems =
let constructor_hints env sigma eapply lems =
let lems = expand_constructor_hints env sigma lems in
List.map_append (fun (poly, lem) ->
- make_resolves env sigma (eapply,true,false) empty_hint_info ~poly lem) lems
+ make_resolves env sigma (eapply,true,false) empty_hint_info ~check:true ~poly lem) lems
let make_local_hint_db env sigma ts eapply lems =
let map c = c env sigma in
diff --git a/tactics/hints.mli b/tactics/hints.mli
index f5fd3348e4..6c8b7fed75 100644
--- a/tactics/hints.mli
+++ b/tactics/hints.mli
@@ -206,36 +206,6 @@ val add_hints : locality:Goptions.option_locality -> hint_db_name list -> hints_
val prepare_hint : bool (* Check no remaining evars *) ->
env -> evar_map -> evar_map * constr -> (constr * Univ.ContextSet.t)
-(** [make_exact_entry info (c, ctyp, ctx)].
- [c] is the term given as an exact proof to solve the goal;
- [ctyp] is the type of [c].
- [ctx] is its (refreshable) universe context.
- In info:
- [hint_priority] is the hint's desired priority, it is 0 if unspecified
- [hint_pattern] is the hint's desired pattern, it is inferred if not specified
-*)
-
-val make_exact_entry : env -> evar_map -> hint_info -> poly:bool -> ?name:hints_path_atom ->
- (constr * types * Univ.ContextSet.t) -> hint_entry
-
-(** [make_apply_entry (eapply,hnf,verbose) info (c,cty,ctx))].
- [eapply] is true if this hint will be used only with EApply;
- [hnf] should be true if we should expand the head of cty before searching for
- products;
- [c] is the term given as an exact proof to solve the goal;
- [cty] is the type of [c].
- [ctx] is its (refreshable) universe context.
- In info:
- [hint_priority] is the hint's desired priority, it is computed as the number of products in [cty]
- if unspecified
- [hint_pattern] is the hint's desired pattern, it is inferred from the conclusion of [cty]
- if not specified
-*)
-
-val make_apply_entry :
- env -> evar_map -> bool * bool * bool -> hint_info -> poly:bool -> ?name:hints_path_atom ->
- (constr * types * Univ.ContextSet.t) -> hint_entry
-
(** A constr which is Hint'ed will be:
- (1) used as an Exact, if it does not start with a product
- (2) used as an Apply, if its HNF starts with a product, and
@@ -244,7 +214,7 @@ val make_apply_entry :
has missing arguments. *)
val make_resolves :
- env -> evar_map -> bool * bool * bool -> hint_info -> poly:bool -> ?name:hints_path_atom ->
+ env -> evar_map -> bool * bool * bool -> hint_info -> check:bool -> poly:bool -> ?name:hints_path_atom ->
hint_term -> hint_entry list
(** [make_resolve_hyp hname htyp].
diff --git a/tactics/redexpr.ml b/tactics/redexpr.ml
index f681e4e99e..e000ddce74 100644
--- a/tactics/redexpr.ml
+++ b/tactics/redexpr.ml
@@ -44,11 +44,7 @@ let cbv_native env sigma c =
(warn_native_compute_disabled ();
cbv_vm env sigma c)
-let whd_cbn flags env sigma t =
- let (state,_) =
- (whd_state_gen ~refold:true ~tactic_mode:true flags env sigma (t,Reductionops.Stack.empty))
- in
- Reductionops.Stack.zip ~refold:true sigma state
+let whd_cbn = Cbn.whd_cbn
let strong_cbn flags =
strong_with_flags whd_cbn flags
diff --git a/tactics/tactics.mllib b/tactics/tactics.mllib
index 36d61feed1..88025e3fb4 100644
--- a/tactics/tactics.mllib
+++ b/tactics/tactics.mllib
@@ -9,6 +9,7 @@ Eqschemes
Elimschemes
Genredexpr
Redops
+Cbn
Redexpr
Ppred
Tactics