summaryrefslogtreecommitdiff
path: root/tactics/hipattern.ml4
diff options
context:
space:
mode:
Diffstat (limited to 'tactics/hipattern.ml4')
-rw-r--r--tactics/hipattern.ml4262
1 files changed, 138 insertions, 124 deletions
diff --git a/tactics/hipattern.ml4 b/tactics/hipattern.ml4
index f8c1db27..4b94f420 100644
--- a/tactics/hipattern.ml4
+++ b/tactics/hipattern.ml4
@@ -1,29 +1,24 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i camlp4deps: "parsing/grammar.cma parsing/q_constr.cmo" i*)
+(*i camlp4deps: "grammar/grammar.cma grammar/q_constr.cmo" i*)
open Pp
+open Errors
open Util
open Names
-open Nameops
open Term
-open Sign
open Termops
-open Reductionops
open Inductiveops
-open Evd
-open Environ
-open Clenv
-open Pattern
-open Matching
+open Constr_matching
open Coqlib
open Declarations
+open Tacmach.New
(* I implemented the following functions which test whether a term t
is an inductive but non-recursive type, a general conjuction, a
@@ -52,8 +47,8 @@ let match_with_non_recursive_type t =
| App _ ->
let (hdapp,args) = decompose_app t in
(match kind_of_term hdapp with
- | Ind ind ->
- if not (Global.lookup_mind (fst ind)).mind_finite then
+ | Ind (ind,u) ->
+ if (Global.lookup_mind (fst ind)).mind_finite == Decl_kinds.CoFinite then
Some (hdapp,args)
else
None
@@ -83,55 +78,67 @@ let has_nodep_prod = has_nodep_prod_after 0
(* style: None = record; Some false = conjunction; Some true = strict conj *)
-let match_with_one_constructor style allow_rec t =
+let is_strict_conjunction = function
+| Some true -> true
+| _ -> false
+
+let is_lax_conjunction = function
+| Some false -> true
+| _ -> false
+
+let match_with_one_constructor style onlybinary allow_rec t =
let (hdapp,args) = decompose_app t in
- match kind_of_term hdapp with
+ let res = match kind_of_term hdapp with
| Ind ind ->
- let (mib,mip) = Global.lookup_inductive ind in
- if (Array.length mip.mind_consnames = 1)
- && (allow_rec or not (mis_is_recursive (ind,mib,mip)))
- && (mip.mind_nrealargs = 0)
+ let (mib,mip) = Global.lookup_inductive (fst ind) in
+ if Int.equal (Array.length mip.mind_consnames) 1
+ && (allow_rec || not (mis_is_recursive (fst ind,mib,mip)))
+ && (Int.equal mip.mind_nrealargs 0)
then
- if style = Some true (* strict conjunction *) then
+ if is_strict_conjunction style (* strict conjunction *) then
let ctx =
(prod_assum (snd
(decompose_prod_n_assum mib.mind_nparams mip.mind_nf_lc.(0)))) in
if
List.for_all
- (fun (_,b,c) -> b=None && isRel c && destRel c = mib.mind_nparams) ctx
+ (fun (_,b,c) -> Option.is_empty b && isRel c && Int.equal (destRel c) mib.mind_nparams) ctx
then
Some (hdapp,args)
else None
else
let ctyp = prod_applist mip.mind_nf_lc.(0) args in
let cargs = List.map pi3 ((prod_assum ctyp)) in
- if style <> Some false || has_nodep_prod ctyp then
+ if not (is_lax_conjunction style) || has_nodep_prod ctyp then
(* Record or non strict conjunction *)
Some (hdapp,List.rev cargs)
else
None
else
None
+ | _ -> None in
+ match res with
+ | Some (hdapp, args) when not onlybinary -> res
+ | Some (hdapp, [_; _]) -> res
| _ -> None
-let match_with_conjunction ?(strict=false) t =
- match_with_one_constructor (Some strict) false t
+let match_with_conjunction ?(strict=false) ?(onlybinary=false) t =
+ match_with_one_constructor (Some strict) onlybinary false t
let match_with_record t =
- match_with_one_constructor None false t
+ match_with_one_constructor None false false t
-let is_conjunction ?(strict=false) t =
- op2bool (match_with_conjunction ~strict t)
+let is_conjunction ?(strict=false) ?(onlybinary=false) t =
+ op2bool (match_with_conjunction ~strict ~onlybinary t)
let is_record t =
op2bool (match_with_record t)
let match_with_tuple t =
- let t = match_with_one_constructor None true t in
+ let t = match_with_one_constructor None false true t in
Option.map (fun (hd,l) ->
let ind = destInd hd in
- let (mib,mip) = Global.lookup_inductive ind in
- let isrec = mis_is_recursive (ind,mib,mip) in
+ let (mib,mip) = Global.lookup_pinductive ind in
+ let isrec = mis_is_recursive (fst ind,mib,mip) in
(hd,l,isrec)) t
let is_tuple t =
@@ -143,20 +150,20 @@ let is_tuple t =
"Inductive I A1 ... An := C1 (_:A1) | ... | Cn : (_:An)" *)
let test_strict_disjunction n lc =
- array_for_all_i (fun i c ->
+ Array.for_all_i (fun i c ->
match (prod_assum (snd (decompose_prod_n_assum n c))) with
- | [_,None,c] -> isRel c && destRel c = (n - i)
+ | [_,None,c] -> isRel c && Int.equal (destRel c) (n - i)
| _ -> false) 0 lc
-let match_with_disjunction ?(strict=false) t =
+let match_with_disjunction ?(strict=false) ?(onlybinary=false) t =
let (hdapp,args) = decompose_app t in
- match kind_of_term hdapp with
- | Ind ind ->
- let car = mis_constr_nargs ind in
+ let res = match kind_of_term hdapp with
+ | Ind (ind,u) ->
+ let car = constructors_nrealargs ind in
let (mib,mip) = Global.lookup_inductive ind in
- if array_for_all (fun ar -> ar = 1) car
- && not (mis_is_recursive (ind,mib,mip))
- && (mip.mind_nrealargs = 0)
+ if Array.for_all (fun ar -> Int.equal ar 1) car
+ && not (mis_is_recursive (ind,mib,mip))
+ && (Int.equal mip.mind_nrealargs 0)
then
if strict then
if test_strict_disjunction mib.mind_nparams mip.mind_nf_lc then
@@ -170,10 +177,14 @@ let match_with_disjunction ?(strict=false) t =
Some (hdapp,Array.to_list cargs)
else
None
+ | _ -> None in
+ match res with
+ | Some (hdapp,args) when not onlybinary -> res
+ | Some (hdapp,[_; _]) -> res
| _ -> None
-let is_disjunction ?(strict=false) t =
- op2bool (match_with_disjunction ~strict t)
+let is_disjunction ?(strict=false) ?(onlybinary=false) t =
+ op2bool (match_with_disjunction ~strict ~onlybinary t)
(* An empty type is an inductive type, possible with indices, that has no
constructors *)
@@ -182,9 +193,9 @@ let match_with_empty_type t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
| Ind ind ->
- let (mib,mip) = Global.lookup_inductive ind in
+ let (mib,mip) = Global.lookup_pinductive ind in
let nconstr = Array.length mip.mind_consnames in
- if nconstr = 0 then Some hdapp else None
+ if Int.equal nconstr 0 then Some hdapp else None
| _ -> None
let is_empty_type t = op2bool (match_with_empty_type t)
@@ -196,11 +207,11 @@ let match_with_unit_or_eq_type t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
| Ind ind ->
- let (mib,mip) = Global.lookup_inductive ind in
+ let (mib,mip) = Global.lookup_pinductive ind in
let constr_types = mip.mind_nf_lc in
let nconstr = Array.length mip.mind_consnames in
- let zero_args c = nb_prod c = mib.mind_nparams in
- if nconstr = 1 && zero_args constr_types.(0) then
+ let zero_args c = Int.equal (nb_prod c) mib.mind_nparams in
+ if Int.equal nconstr 1 && zero_args constr_types.(0) then
Some hdapp
else
None
@@ -214,7 +225,7 @@ let is_unit_or_eq_type t = op2bool (match_with_unit_or_eq_type t)
let is_unit_type t =
match match_with_conjunction t with
- | Some (_,t) when List.length t = 0 -> true
+ | Some (_,[]) -> true
| _ -> false
(* Checks if a given term is an application of an
@@ -232,27 +243,30 @@ let coq_refl_leibniz1_pattern = PATTERN [ forall x:_, _ x x ]
let coq_refl_leibniz2_pattern = PATTERN [ forall A:_, forall x:A, _ A x x ]
let coq_refl_jm_pattern = PATTERN [ forall A:_, forall x:A, _ A x A x ]
-open Libnames
+open Globnames
+
+let is_matching x y = is_matching (Global.env ()) Evd.empty x y
+let matches x y = matches (Global.env ()) Evd.empty x y
let match_with_equation t =
if not (isApp t) then raise NoEquationFound;
let (hdapp,args) = destApp t in
match kind_of_term hdapp with
- | Ind ind ->
- if IndRef ind = glob_eq then
+ | Ind (ind,u) ->
+ if eq_gr (IndRef ind) glob_eq then
Some (build_coq_eq_data()),hdapp,
PolymorphicLeibnizEq(args.(0),args.(1),args.(2))
- else if IndRef ind = glob_identity then
+ else if eq_gr (IndRef ind) glob_identity then
Some (build_coq_identity_data()),hdapp,
PolymorphicLeibnizEq(args.(0),args.(1),args.(2))
- else if IndRef ind = glob_jmeq then
+ else if eq_gr (IndRef ind) glob_jmeq then
Some (build_coq_jmeq_data()),hdapp,
HeterogenousEq(args.(0),args.(1),args.(2),args.(3))
else
let (mib,mip) = Global.lookup_inductive ind in
let constr_types = mip.mind_nf_lc in
let nconstr = Array.length mip.mind_consnames in
- if nconstr = 1 then
+ if Int.equal nconstr 1 then
if is_matching coq_refl_leibniz1_pattern constr_types.(0) then
None, hdapp, MonomorphicLeibnizEq(args.(0),args.(1))
else if is_matching coq_refl_leibniz2_pattern constr_types.(0) then
@@ -263,25 +277,41 @@ let match_with_equation t =
else raise NoEquationFound
| _ -> raise NoEquationFound
+(* Note: An "equality type" is any type with a single argument-free
+ constructor: it captures eq, eq_dep, JMeq, eq_true, etc. but also
+ True/unit which is the degenerate equality type (isomorphic to ()=());
+ in particular, True/unit are provable by "reflexivity" *)
+
let is_inductive_equality ind =
let (mib,mip) = Global.lookup_inductive ind in
let nconstr = Array.length mip.mind_consnames in
- nconstr = 1 && constructor_nrealargs (Global.env()) (ind,1) = 0
+ Int.equal nconstr 1 && Int.equal (constructor_nrealargs (ind,1)) 0
let match_with_equality_type t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
- | Ind ind when is_inductive_equality ind -> Some (hdapp,args)
+ | Ind (ind,_) when is_inductive_equality ind -> Some (hdapp,args)
| _ -> None
let is_equality_type t = op2bool (match_with_equality_type t)
+(* Arrows/Implication/Negation *)
+
let coq_arrow_pattern = PATTERN [ ?X1 -> ?X2 ]
let match_arrow_pattern t =
- match matches coq_arrow_pattern t with
- | [(m1,arg);(m2,mind)] -> assert (m1=meta1 & m2=meta2); (arg, mind)
- | _ -> anomaly "Incorrect pattern matching"
+ let result = matches coq_arrow_pattern t in
+ match Id.Map.bindings result with
+ | [(m1,arg);(m2,mind)] ->
+ assert (Id.equal m1 meta1 && Id.equal m2 meta2); (arg, mind)
+ | _ -> anomaly (Pp.str "Incorrect pattern matching")
+
+let match_with_imp_term c=
+ match kind_of_term c with
+ | Prod (_,a,b) when not (dependent (mkRel 1) b) ->Some (a,b)
+ | _ -> None
+
+let is_imp_term c = op2bool (match_with_imp_term c)
let match_with_nottype t =
try
@@ -291,6 +321,8 @@ let match_with_nottype t =
let is_nottype t = op2bool (match_with_nottype t)
+(* Forall *)
+
let match_with_forall_term c=
match kind_of_term c with
| Prod (nam,a,b) -> Some (nam,a,b)
@@ -298,24 +330,17 @@ let match_with_forall_term c=
let is_forall_term c = op2bool (match_with_forall_term c)
-let match_with_imp_term c=
- match kind_of_term c with
- | Prod (_,a,b) when not (dependent (mkRel 1) b) ->Some (a,b)
- | _ -> None
-
-let is_imp_term c = op2bool (match_with_imp_term c)
-
let match_with_nodep_ind t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
| Ind ind ->
- let (mib,mip) = Global.lookup_inductive ind in
+ let (mib,mip) = Global.lookup_pinductive ind in
if Array.length (mib.mind_packets)>1 then None else
let nodep_constr = has_nodep_prod_after mib.mind_nparams in
- if array_for_all nodep_constr mip.mind_nf_lc then
+ if Array.for_all nodep_constr mip.mind_nf_lc then
let params=
- if mip.mind_nrealargs=0 then args else
- fst (list_chop mib.mind_nparams args) in
+ if Int.equal mip.mind_nrealargs 0 then args else
+ fst (List.chop mib.mind_nparams args) in
Some (hdapp,params,mip.mind_nrealargs)
else
None
@@ -327,10 +352,10 @@ let match_with_sigma_type t=
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
| Ind ind ->
- let (mib,mip) = Global.lookup_inductive ind in
- if (Array.length (mib.mind_packets)=1) &&
- (mip.mind_nrealargs=0) &&
- (Array.length mip.mind_consnames=1) &&
+ let (mib,mip) = Global.lookup_pinductive ind in
+ if Int.equal (Array.length (mib.mind_packets)) 1 &&
+ (Int.equal mip.mind_nrealargs 0) &&
+ (Int.equal (Array.length mip.mind_consnames)1) &&
has_nodep_prod_after (mib.mind_nparams+1) mip.mind_nf_lc.(0) then
(*allowing only 1 existential*)
Some (hdapp,args)
@@ -344,9 +369,10 @@ let is_sigma_type t=op2bool (match_with_sigma_type t)
let rec first_match matcher = function
| [] -> raise PatternMatchingFailure
- | (pat,build_set)::l ->
- try (build_set (),matcher pat)
- with PatternMatchingFailure -> first_match matcher l
+ | (pat,check,build_set)::l when check () ->
+ (try (build_set (),matcher pat)
+ with PatternMatchingFailure -> first_match matcher l)
+ | _::l -> first_match matcher l
(*** Equality *)
@@ -355,50 +381,48 @@ let coq_eq_pattern_gen eq = lazy PATTERN [ %eq ?X1 ?X2 ?X3 ]
let coq_eq_pattern = coq_eq_pattern_gen coq_eq_ref
let coq_identity_pattern = coq_eq_pattern_gen coq_identity_ref
let coq_jmeq_pattern = lazy PATTERN [ %coq_jmeq_ref ?X1 ?X2 ?X3 ?X4 ]
-let coq_eq_true_pattern = lazy PATTERN [ %coq_eq_true_ref ?X1 ]
let match_eq eqn eq_pat =
let pat =
try Lazy.force eq_pat
with e when Errors.noncritical e -> raise PatternMatchingFailure
in
- match matches pat eqn with
+ match Id.Map.bindings (matches pat eqn) with
| [(m1,t);(m2,x);(m3,y)] ->
- assert (m1 = meta1 & m2 = meta2 & m3 = meta3);
- PolymorphicLeibnizEq (t,x,y)
+ assert (Id.equal m1 meta1 && Id.equal m2 meta2 && Id.equal m3 meta3);
+ PolymorphicLeibnizEq (t,x,y)
| [(m1,t);(m2,x);(m3,t');(m4,x')] ->
- assert (m1 = meta1 & m2 = meta2 & m3 = meta3 & m4 = meta4);
+ assert (Id.equal m1 meta1 && Id.equal m2 meta2 && Id.equal m3 meta3 && Id.equal m4 meta4);
HeterogenousEq (t,x,t',x')
- | _ -> anomaly "match_eq: an eq pattern should match 3 or 4 terms"
+ | _ -> anomaly ~label:"match_eq" (Pp.str "an eq pattern should match 3 or 4 terms")
+
+let no_check () = true
+let check_jmeq_loaded () = Library.library_is_loaded Coqlib.jmeq_module
let equalities =
- [coq_eq_pattern, build_coq_eq_data;
- coq_jmeq_pattern, build_coq_jmeq_data;
- coq_identity_pattern, build_coq_identity_data]
+ [coq_eq_pattern, no_check, build_coq_eq_data;
+ coq_jmeq_pattern, check_jmeq_loaded, build_coq_jmeq_data;
+ coq_identity_pattern, no_check, build_coq_identity_data]
let find_eq_data eqn = (* fails with PatternMatchingFailure *)
- first_match (match_eq eqn) equalities
+ let d,k = first_match (match_eq eqn) equalities in
+ let hd,u = destInd (fst (destApp eqn)) in
+ d,u,k
let extract_eq_args gl = function
| MonomorphicLeibnizEq (e1,e2) ->
- let t = Tacmach.pf_type_of gl e1 in (t,e1,e2)
+ let t = pf_type_of gl e1 in (t,e1,e2)
| PolymorphicLeibnizEq (t,e1,e2) -> (t,e1,e2)
| HeterogenousEq (t1,e1,t2,e2) ->
- if Tacmach.pf_conv_x gl t1 t2 then (t1,e1,e2)
+ if pf_conv_x gl t1 t2 then (t1,e1,e2)
else raise PatternMatchingFailure
let find_eq_data_decompose gl eqn =
- let (lbeq,eq_args) = find_eq_data eqn in
- (lbeq,extract_eq_args gl eq_args)
-
-let inversible_equalities =
- [coq_eq_pattern, build_coq_inversion_eq_data;
- coq_jmeq_pattern, build_coq_inversion_jmeq_data;
- coq_identity_pattern, build_coq_inversion_identity_data;
- coq_eq_true_pattern, build_coq_inversion_eq_true_data]
+ let (lbeq,u,eq_args) = find_eq_data eqn in
+ (lbeq,u,extract_eq_args gl eq_args)
let find_this_eq_data_decompose gl eqn =
- let (lbeq,eq_args) =
+ let (lbeq,u,eq_args) =
try (*first_match (match_eq eqn) inversible_equalities*)
find_eq_data eqn
with PatternMatchingFailure ->
@@ -407,17 +431,14 @@ let find_this_eq_data_decompose gl eqn =
try extract_eq_args gl eq_args
with PatternMatchingFailure ->
error "Don't know what to do with JMeq on arguments not of same type." in
- (lbeq,eq_args)
-
-open Tacmach
-open Tacticals
+ (lbeq,u,eq_args)
let match_eq_nf gls eqn eq_pat =
- match pf_matches gls (Lazy.force eq_pat) eqn with
+ match Id.Map.bindings (pf_matches gls (Lazy.force eq_pat) eqn) with
| [(m1,t);(m2,x);(m3,y)] ->
- assert (m1 = meta1 & m2 = meta2 & m3 = meta3);
+ assert (Id.equal m1 meta1 && Id.equal m2 meta2 && Id.equal m3 meta3);
(t,pf_whd_betadeltaiota gls x,pf_whd_betadeltaiota gls y)
- | _ -> anomaly "match_eq: an eq pattern should match 3 terms"
+ | _ -> anomaly ~label:"match_eq" (Pp.str "an eq pattern should match 3 terms")
let dest_nf_eq gls eqn =
try
@@ -427,31 +448,24 @@ let dest_nf_eq gls eqn =
(*** Sigma-types *)
-(* Patterns "(existS ?1 ?2 ?3 ?4)" and "(existT ?1 ?2 ?3 ?4)" *)
-let coq_ex_pattern_gen ex = lazy PATTERN [ %ex ?X1 ?X2 ?X3 ?X4 ]
-let coq_existT_pattern = coq_ex_pattern_gen coq_existT_ref
-let coq_exist_pattern = coq_ex_pattern_gen coq_exist_ref
-
-let match_sigma ex ex_pat =
- match matches (Lazy.force ex_pat) ex with
- | [(m1,a);(m2,p);(m3,car);(m4,cdr)] ->
- assert (m1=meta1 & m2=meta2 & m3=meta3 & m4=meta4);
- (a,p,car,cdr)
- | _ ->
- anomaly "match_sigma: a successful sigma pattern should match 4 terms"
-
+let match_sigma ex =
+ match kind_of_term ex with
+ | App (f, [| a; p; car; cdr |]) when is_global (Lazy.force coq_exist_ref) f ->
+ build_sigma (), (snd (destConstruct f), a, p, car, cdr)
+ | App (f, [| a; p; car; cdr |]) when is_global (Lazy.force coq_existT_ref) f ->
+ build_sigma_type (), (snd (destConstruct f), a, p, car, cdr)
+ | _ -> raise PatternMatchingFailure
+
let find_sigma_data_decompose ex = (* fails with PatternMatchingFailure *)
- first_match (match_sigma ex)
- [coq_existT_pattern, build_sigma_type;
- coq_exist_pattern, build_sigma]
+ match_sigma ex
(* Pattern "(sig ?1 ?2)" *)
let coq_sig_pattern = lazy PATTERN [ %coq_sig_ref ?X1 ?X2 ]
let match_sigma t =
- match matches (Lazy.force coq_sig_pattern) t with
+ match Id.Map.bindings (matches (Lazy.force coq_sig_pattern) t) with
| [(_,a); (_,p)] -> (a,p)
- | _ -> anomaly "Unexpected pattern"
+ | _ -> anomaly (Pp.str "Unexpected pattern")
let is_matching_sigma t = is_matching (Lazy.force coq_sig_pattern) t
@@ -486,10 +500,10 @@ let match_eqdec t =
try true,op_or,matches (Lazy.force coq_eqdec_pattern) t
with PatternMatchingFailure ->
false,op_or,matches (Lazy.force coq_eqdec_rev_pattern) t in
- match subst with
+ match Id.Map.bindings subst with
| [(_,typ);(_,c1);(_,c2)] ->
- eqonleft, Libnames.constr_of_global (Lazy.force op), c1, c2, typ
- | _ -> anomaly "Unexpected pattern"
+ eqonleft, Universes.constr_of_global (Lazy.force op), c1, c2, typ
+ | _ -> anomaly (Pp.str "Unexpected pattern")
(* Patterns "~ ?" and "? -> False" *)
let coq_not_pattern = lazy PATTERN [ ~ _ ]