aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pretyping/clenv.ml5
-rw-r--r--pretyping/reductionops.ml42
-rw-r--r--tactics/tacinterp.ml201
-rw-r--r--tactics/tacinterp.mli3
4 files changed, 123 insertions, 128 deletions
diff --git a/pretyping/clenv.ml b/pretyping/clenv.ml
index 2d26e5bb1..dbc51514c 100644
--- a/pretyping/clenv.ml
+++ b/pretyping/clenv.ml
@@ -62,6 +62,7 @@ let subst_clenv sub clenv =
env = clenv.env }
let clenv_nf_meta clenv c = nf_meta clenv.evd c
+let clenv_term clenv c = meta_instance clenv.evd c
let clenv_meta_type clenv mv = Typing.meta_type clenv.evd mv
let clenv_value clenv = meta_instance clenv.evd clenv.templval
let clenv_type clenv = meta_instance clenv.evd clenv.templtyp
@@ -313,12 +314,12 @@ let clenv_fchain ?(allow_K=true) mv clenv nextclenv =
(* unify the type of the template of [nextclenv] with the type of [mv] *)
let clenv'' =
clenv_unify allow_K CUMUL
- (clenv_nf_meta clenv' nextclenv.templtyp.rebus)
+ (clenv_term clenv' nextclenv.templtyp)
(clenv_meta_type clenv' mv)
clenv' in
(* assign the metavar *)
let clenv''' =
- clenv_assign mv (clenv_nf_meta clenv' nextclenv.templval.rebus) clenv''
+ clenv_assign mv (clenv_term clenv' nextclenv.templval) clenv''
in
clenv'''
diff --git a/pretyping/reductionops.ml b/pretyping/reductionops.ml
index f247f47b6..617bd7717 100644
--- a/pretyping/reductionops.ml
+++ b/pretyping/reductionops.ml
@@ -675,10 +675,42 @@ let plain_instance s c =
in
if s = [] then c else irec c
-(* Pourquoi ne fait-on pas nf_betaiota si s=[] ? *)
-let instance s c =
- if s = [] then c else local_strong whd_betaiota (plain_instance s c)
-
+(* [instance] is used for [res_pf]; the call to [local_strong whd_betaiota]
+ has (unfortunately) different subtle side effects:
+
+ - ** Order of subgoals **
+ If the lemma is a case analysis with parameters, it will move the
+ parameters as first subgoals (e.g. "case H" applied on
+ "H:D->A/\B|-C" will present the subgoal |-D first while w/o
+ betaiota the subgoal |-D would have come last).
+
+ - ** Betaiota-contraction in statement **
+ If the lemma has a parameter which is a function and this
+ function is applied in the lemma, then the _strong_ betaiota will
+ contract the application of the function to its argument (e.g.
+ "apply (H (fun x => x))" in "H:forall f, f 0 = 0 |- 0=0" will
+ result in applying the lemma 0=0 in which "(fun x => x) 0" has
+ been contracted). A goal to rewrite may then fail or succeed
+ differently.
+
+ - ** Naming of hypotheses **
+ If a lemma is a function of the form "fun H:(forall a:A, P a)
+ => .. F H .." where the expected type of H is "forall b:A, P b",
+ then, without reduction, the application of the lemma will
+ generate a subgoal "forall a:A, P a" (and intro will use name
+ "a"), while with reduction, it will generate a subgoal "forall
+ b:A, P b" (and intro will use name "b").
+
+ - ** First-order pattern-matching **
+ If a lemma has the type "(fun x => p) t" then rewriting t may fail
+ if the type of the lemma is first beta-reduced (this typically happens
+ when rewriting a single variable and the type of the lemma is obtained
+ by meta_instance (with empty map) which itself call instance with this
+ empty map.
+ *)
+
+let instance s c =
+ (* if s = [] then c else *) local_strong whd_betaiota (plain_instance s c)
(* pseudo-reduction rule:
* [hnf_prod_app env s (Prod(_,B)) N --> B[N]
@@ -876,7 +908,7 @@ let meta_instance env b =
List.map
(fun mv -> (mv,meta_value env mv)) (Metaset.elements b.freemetas)
in
- instance c_sigma b.rebus
+ if c_sigma = [] then b.rebus else instance c_sigma b.rebus
let nf_meta env c = meta_instance env (mk_freelisted c)
diff --git a/tactics/tacinterp.ml b/tactics/tacinterp.ml
index bff8b1b49..71039e3bb 100644
--- a/tactics/tacinterp.ml
+++ b/tactics/tacinterp.ml
@@ -102,9 +102,10 @@ let catch_error loc tac g =
(* Signature for interpretation: val_interp and interpretation functions *)
type interp_sign =
{ lfun : (identifier * value) list;
- avoid_ids : identifier list; (* ids inherited fromm the call context
+ avoid_ids : identifier list; (* ids inherited from the call context
(needed to get fresh ids) *)
- debug : debug_info }
+ debug : debug_info;
+ last_loc : loc }
let check_is_value = function
| VRTactic _ -> (* These are goals produced by Match *)
@@ -1057,6 +1058,19 @@ let set_debug pos = debug := pos
(* Gives the state of debug *)
let get_debug () = !debug
+let debugging_step ist pp =
+ match ist.debug with
+ | DebugOn lev ->
+ safe_msgnl (str "Level " ++ int lev ++ str": " ++ pp ++ fnl())
+ | _ -> ()
+
+let debugging_exception_step ist signal_anomaly e pp =
+ let explain_exc =
+ if signal_anomaly then explain_logic_error
+ else explain_logic_error_no_anomaly in
+ debugging_step ist
+ (pp ++ spc() ++ str "raised the exception" ++ fnl() ++ !explain_exc e)
+
let error_ltac_variable loc id env v s =
user_err_loc (loc, "", str "Ltac variable " ++ pr_id id ++
str " is bound to" ++ spc () ++ pr_value env v ++ spc () ++
@@ -1448,34 +1462,18 @@ let interp_may_eval f ist gl = function
| ConstrTerm c ->
try
f ist gl c
- with e ->
- begin
- match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": interpretation of term " ++
- Printer.pr_rawconstr_env (pf_env gl) (fst c) ++
- str " raised an exception" ++
- fnl() ++
- !Tactic_debug.explain_logic_error_no_anomaly e)
- | _ -> ()
- end;
- raise e
+ with e ->
+ debugging_exception_step ist false e
+ (str"interpretation of term " ++ pr_rawconstr_env (pf_env gl)(fst c));
+ raise e
(* Interprets a constr expression possibly to first evaluate *)
let interp_constr_may_eval ist gl c =
let csr =
try
interp_may_eval pf_interp_constr ist gl c
- with e ->
- begin match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": evaluation of term raised an exception" ++
- fnl() ++
- !Tactic_debug.explain_logic_error_no_anomaly e)
- | _ -> ()
- end;
+ with e ->
+ debugging_exception_step ist false e (str "evaluation of term");
raise e
in
begin
@@ -1599,7 +1597,7 @@ let rec val_interp ist gl (tac:glob_tactic_expr) =
| TacMatch (lz,c,lmr) -> interp_match ist gl lz c lmr
| TacArg a -> interp_tacarg ist gl a
(* Delayed evaluation *)
- | t -> VTactic (dloc,eval_tactic ist t)
+ | t -> VTactic (ist.last_loc,eval_tactic ist t)
in check_for_interrupt ();
match ist.debug with
@@ -1636,8 +1634,10 @@ and interp_ltac_reference isapplied mustbetac ist gl = function
if mustbetac then coerce_to_tactic loc id v else v
| ArgArg (loc,r) ->
let ids = extract_ids [] ist.lfun in
- let v = val_interp {lfun=[];avoid_ids=ids; debug=ist.debug} gl (lookup r) in
- if isapplied then v else locate_tactic_call loc v
+ let ist =
+ { lfun=[]; debug=ist.debug; avoid_ids=ids;
+ last_loc = if isapplied then ist.last_loc else loc } in
+ val_interp ist gl (lookup r)
and interp_tacarg ist gl = function
| TacVoid -> VVoid
@@ -1682,32 +1682,15 @@ and interp_app ist gl fv largs loc =
let (newlfun,lvar,lval)=head_with_value (var,largs) in
if lvar=[] then
let v =
- let res =
- try
- val_interp { ist with lfun=newlfun@olfun } gl body
- with e ->
- begin match ist.debug with
- DebugOn lev ->
- safe_msgnl
- (str "Level " ++ int lev ++
- str ": evaluation raises an exception" ++
- fnl() ++
- !Tactic_debug.explain_logic_error_no_anomaly e)
- | _ -> ()
- end;
- raise e
- in
- (match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": evaluation returns" ++ fnl() ++
- pr_value (Some (pf_env gl)) res)
- | _ -> ());
- res
- in
-
- if lval=[] then locate_tactic_call loc v
- else interp_app ist gl v lval loc
+ try
+ let lloc = if lval=[] then loc else ist.last_loc in
+ val_interp { ist with lfun=newlfun@olfun; last_loc=lloc } gl body
+ with e ->
+ debugging_exception_step ist false e (str "evaluation");
+ raise e in
+ debugging_step ist
+ (str "evaluation returns" ++ fnl() ++ pr_value (Some (pf_env gl)) v);
+ if lval=[] then v else interp_app ist gl v lval loc
else
VFun(newlfun@olfun,lvar,body)
| _ ->
@@ -1955,34 +1938,25 @@ and interp_match ist g lz constr lmr =
(try eval_with_fail ist lz g t
with e when is_match_catchable e -> apply_match ist csr [])
| (Pat ([],Term c,mt))::tl ->
- (try let lm =
- (try matches c csr with
- e ->
- (match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": matching with pattern" ++ fnl() ++
- Printer.pr_constr_pattern_env (pf_env g) c ++ fnl() ++
- str "raised the exception" ++ fnl() ++
- !Tactic_debug.explain_logic_error_no_anomaly e)
- | _ -> ()); raise e) in
- (try let lm = List.map (fun (id,c) -> (id,VConstr c)) lm in
- eval_with_fail { ist with lfun=lm@ist.lfun } lz g mt
+ (try
+ let lm =
+ try matches c csr
+ with e ->
+ debugging_exception_step ist false e
+ (str "matching with pattern" ++ fnl () ++
+ pr_constr_pattern_env (pf_env g) c);
+ raise e in
+ try
+ let lm = List.map (fun (id,c) -> (id,VConstr c)) lm in
+ eval_with_fail { ist with lfun=lm@ist.lfun } lz g mt
with e ->
- (match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "rule body for pattern" ++ fnl() ++
- Printer.pr_constr_pattern_env (pf_env g) c ++ fnl() ++
- str "raised the exception" ++ fnl() ++
- !Tactic_debug.explain_logic_error_no_anomaly e)
- | _ -> ()); raise e)
+ debugging_exception_step ist false e
+ (str "rule body for pattern" ++
+ pr_constr_pattern_env (pf_env g) c);
+ raise e
with e when is_match_catchable e ->
- (match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ":switching to the next rule");
- | DebugOff -> ());
- apply_match ist csr tl)
+ debugging_step ist (str "switching to the next rule");
+ apply_match ist csr tl)
| (Pat ([],Subterm (id,c),mt))::tl ->
(try apply_match_subterm ist 0 (id,c) csr mt
@@ -1991,49 +1965,33 @@ and interp_match ist g lz constr lmr =
errorlabstrm "Tacinterp.apply_match" (str
"No matching clauses for match") in
let csr =
- try interp_ltac_constr ist g constr with
- e -> (match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": evaluation of the matched expression raised " ++
- str "the exception" ++ fnl() ++
- !Tactic_debug.explain_logic_error e)
- | _ -> ()); raise e in
+ try interp_ltac_constr ist g constr with e ->
+ debugging_exception_step ist true e
+ (str "evaluation of the matched expression");
+ raise e in
let ilr = read_match_rule (fst (constr_list ist (pf_env g))) lmr in
let res =
- try apply_match ist csr ilr with
- e ->
- begin match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": match expression failed with error" ++ fnl() ++
- !Tactic_debug.explain_logic_error e)
- | _ -> ()
- end;
- raise e in
- (if ist.debug <> DebugOff then
- safe_msgnl (str "match expression returns " ++
- pr_value (Some (pf_env g)) res));
- res
+ try apply_match ist csr ilr with e ->
+ debugging_exception_step ist true e (str "match expression");
+ raise e in
+ debugging_step ist
+ (str "match expression returns " ++ pr_value (Some (pf_env g)) res);
+ res
(* Interprets tactic expressions : returns a "constr" *)
and interp_ltac_constr ist gl e =
let result =
- try (val_interp ist gl e) with Not_found ->
- begin match ist.debug with
- DebugOn lev ->
- safe_msgnl (str "Level " ++ int lev ++
- str ": evaluation failed for" ++ fnl() ++
- Pptactic.pr_glob_tactic (pf_env gl) e)
- | _ -> ()
- end;
+ try val_interp ist gl e with Not_found ->
+ debugging_step ist
+ (str "evaluation failed for" ++ fnl() ++
+ Pptactic.pr_glob_tactic (pf_env gl) e);
raise Not_found in
- try let cresult = constr_of_value (pf_env gl) result in
- (if !debug <> DebugOff then
- safe_msgnl (Pptactic.pr_glob_tactic (pf_env gl) e ++ fnl() ++
- str " has value " ++ fnl() ++ print_constr_env (pf_env gl) cresult);
- cresult)
-
+ try
+ let cresult = constr_of_value (pf_env gl) result in
+ debugging_step ist
+ (Pptactic.pr_glob_tactic (pf_env gl) e ++ fnl() ++
+ str " has value " ++ fnl() ++ print_constr_env (pf_env gl) cresult);
+ cresult
with Not_found ->
errorlabstrm ""
(str "Must evaluate to a term" ++ fnl() ++
@@ -2289,17 +2247,20 @@ let make_empty_glob_sign () =
(* Initial call for interpretation *)
let interp_tac_gen lfun avoid_ids debug t gl =
- interp_tactic { lfun=lfun; avoid_ids=avoid_ids; debug=debug }
+ interp_tactic { lfun=lfun; avoid_ids=avoid_ids; debug=debug; last_loc=dloc }
(intern_tactic {
ltacvars = (List.map fst lfun, []); ltacrecvars = [];
gsigma = project gl; genv = pf_env gl } t) gl
-let eval_tactic t gls = interp_tactic { lfun=[]; avoid_ids=[]; debug=get_debug() } t gls
+let eval_tactic t gls =
+ interp_tactic { lfun=[]; avoid_ids=[]; debug=get_debug(); last_loc=dloc }
+ t gls
let interp t = interp_tac_gen [] [] (get_debug()) t
let eval_ltac_constr gl t =
- interp_ltac_constr { lfun=[]; avoid_ids=[]; debug=get_debug() } gl
+ interp_ltac_constr
+ { lfun=[]; avoid_ids=[]; debug=get_debug(); last_loc=dloc } gl
(intern_tactic (make_empty_glob_sign ()) t )
(* Hides interpretation for pretty-print *)
@@ -2700,7 +2661,7 @@ let glob_tactic_env l env x =
x
let interp_redexp env sigma r =
- let ist = { lfun=[]; avoid_ids=[]; debug=get_debug () } in
+ let ist = { lfun=[]; avoid_ids=[]; debug=get_debug (); last_loc=dloc } in
let gist = {(make_empty_glob_sign ()) with genv = env; gsigma = sigma } in
interp_red_expr ist sigma env (intern_red_expr gist r)
@@ -2710,7 +2671,7 @@ let interp_redexp env sigma r =
let _ = Auto.set_extern_interp
(fun l ->
let l = List.map (fun (id,c) -> (id,VConstr c)) l in
- interp_tactic {lfun=l;avoid_ids=[];debug=get_debug()})
+ interp_tactic {lfun=l;avoid_ids=[];debug=get_debug(); last_loc=dloc})
let _ = Auto.set_extern_intern_tac
(fun l ->
Options.with_option strict_check
diff --git a/tactics/tacinterp.mli b/tactics/tacinterp.mli
index 7f497501b..420ae8d74 100644
--- a/tactics/tacinterp.mli
+++ b/tactics/tacinterp.mli
@@ -41,7 +41,8 @@ type value =
and interp_sign =
{ lfun : (identifier * value) list;
avoid_ids : identifier list;
- debug : debug_info }
+ debug : debug_info;
+ last_loc : loc }
(* Transforms an id into a constr if possible *)
val constr_of_id : Environ.env -> identifier -> constr