aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/cc/CC.v36
-rw-r--r--contrib/cc/README18
-rw-r--r--contrib/cc/ccalgo.ml203
-rw-r--r--contrib/cc/ccalgo.mli67
-rw-r--r--contrib/cc/ccproof.ml118
-rw-r--r--contrib/cc/ccproof.mli48
-rw-r--r--contrib/cc/cctac.ml4161
7 files changed, 651 insertions, 0 deletions
diff --git a/contrib/cc/CC.v b/contrib/cc/CC.v
new file mode 100644
index 0000000000..7bd3497872
--- /dev/null
+++ b/contrib/cc/CC.v
@@ -0,0 +1,36 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* $id$ *)
+
+Require Export Eqdep_dec.
+
+(* Congruence lemma *)
+
+Theorem Congr_nodep: (A,B:Type)(f,g:A->B)(x,y:A)f==g->x==y->(f x)==(g y).
+Intros A B f g x y eq1 eq2;Rewrite eq1;Rewrite eq2;Reflexivity.
+Defined.
+
+Theorem Congr_dep:
+ (A:Type; P:(A->Type); f,g:((a:A)(P a)); x:A)f==g->(f x)==(g x).
+Intros A P f g x e;Rewrite e;Reflexivity.
+Defined.
+
+(* Basic application : try to prove that goal is equal to one hypothesis *)
+
+Lemma convert_goal : (A,B:Prop)B->(A==B)->A.
+Intros A B H E;Rewrite E;Assumption.
+Save.
+
+Tactic Definition CCsolve :=
+ Match Context With
+ [ H: ?1 |- ?2] ->
+ (Assert (?2==?1);[CC|
+ Match Reverse Context With
+ [ H: ?1;Heq: (?2==?1)|- ?2] ->(Rewrite Heq;Exact H)]).
+
diff --git a/contrib/cc/README b/contrib/cc/README
new file mode 100644
index 0000000000..f19820d32b
--- /dev/null
+++ b/contrib/cc/README
@@ -0,0 +1,18 @@
+
+cctac: congruence-closure for coq
+
+author: Pierre Corbineau, Stage de DEA au LSV, ENS Cachan
+
+Files :
+
+- ccalgo.ml : congruence closure algorithm
+- ccproof.ml : proof generation code
+- cctac.ml4 : the tactic itself
+- CC.v : a few lemmas to handle eq/eqT conversions and congruence
+
+Known Bugs : CC tactic can fail due to type dependencies.
+
+Related documents:
+ Peter J. Downey, Ravi Sethi, and Robert E. Tarjan.
+ Variations on the common subexpression problem.
+ JACM, 27(4):758-771, October 1980.
diff --git a/contrib/cc/ccalgo.ml b/contrib/cc/ccalgo.ml
new file mode 100644
index 0000000000..93b60531b2
--- /dev/null
+++ b/contrib/cc/ccalgo.ml
@@ -0,0 +1,203 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* $Id$ *)
+
+(* This file implements the basic congruence-closure algorithm by *)
+(* Downey,Sethi and Tarjan. *)
+
+open Names
+open Term
+
+let init_size=251
+
+type term=Symb of constr|Appli of term*term
+
+
+(* Basic Union-Find algo w/o path compression *)
+
+module UF = struct
+ type tag=Congr|Ax of identifier
+
+ type cl=Rep of int*(int list)|Eqto of int*(int*int*tag)
+
+ type vertex=Leaf|Node of (int*int)
+
+ type t=(int ref)*((int,(cl*vertex*term)) Hashtbl.t)
+
+ let empty ()=(((ref 0),(Hashtbl.create init_size)):t)
+
+ let add_lst i t ((a,m):t)=
+ match Hashtbl.find m i with
+ ((Rep(l,lst)),v,trm)->Hashtbl.replace m i ((Rep((l+1),(t::lst))),v,trm)
+ | _ ->failwith "add_lst: not a representative"
+
+ let rec find ((a,m):t) i=
+ let (cl,_,_)=Hashtbl.find m i in
+ match cl with
+ Rep(_,_) -> i
+ | Eqto(j,_) ->find (a,m) j
+
+ let list ((a,m):t) i=
+ match Hashtbl.find m i with
+ ((Rep(_,lst)),_,_)-> lst
+ | _ ->failwith "list: not a class"
+
+ let size ((a,m):t) i=
+ match Hashtbl.find m i with
+ ((Rep (l,_)),_,_) -> l
+ | _ ->failwith "size: not a class"
+
+ let signature ((a,m):t) i=
+ let (_,v,_)=Hashtbl.find m i in
+ match v with
+ Node(j,k)->(find (a,m) j,find (a,m) k)
+ | _ ->failwith "signature: not a node"
+
+ let nodes ((a,m):t)= (* cherche les noeuds binaires *)
+ Hashtbl.fold (fun i (_,v,_) l->match v with Node (_,_)->i::l|_->l) m []
+
+ let rec add t (a,m) syms =
+ try Hashtbl.find syms t with Not_found ->
+ match t with
+ Symb s ->
+ let b= !a in incr a;
+ Hashtbl.add m b ((Rep (0,[])),Leaf,t);
+ Hashtbl.add syms t b;
+ b
+ | Appli (t1,t2) ->
+ let i1=add t1 (a,m) syms and i2=add t2 (a,m) syms in
+ let b= !a in incr a;
+ add_lst (find (a,m) i1) b (a,m);
+ add_lst (find (a,m) i2) b (a,m);
+ Hashtbl.add m b ((Rep (0,[])),(Node(i1,i2)),t);
+ Hashtbl.add syms t b;
+ b
+
+ let union ((a,m):t) i1 i2 t=
+ let (cl1,v1,t1)=(Hashtbl.find m i1) and
+ (cl2,v2,t2)=(Hashtbl.find m i2) in
+ match cl1,cl1 with
+ ((Rep (l1,lst1)),(Rep (l2,lst2))) ->
+ Hashtbl.replace m i2 ((Eqto (i1,t)),v2,t2);
+ Hashtbl.replace m i1 ((Rep((l2+l1),(lst2@lst1))),v1,t1)
+ | _ ->failwith "union: not classes"
+
+
+end
+
+(* Signature table *)
+
+module ST=struct
+
+(* l: sign -> term r: term -> sign *)
+
+ type t = ((int*int,int) Hashtbl.t) * ((int,int*int) Hashtbl.t)
+
+ let empty ()=((Hashtbl.create init_size),(Hashtbl.create init_size))
+
+ let enter t sign ((l,r) as st:t)=
+ if Hashtbl.mem l sign then
+ failwith "enter: signature already entered"
+ else
+ Hashtbl.replace l sign t;
+ Hashtbl.replace r t sign
+
+ let query sign ((l,r):t)=Hashtbl.find l sign
+
+ let delete t ((l,r) as st:t)=
+ try let sign=Hashtbl.find r t in
+ Hashtbl.remove l sign;
+ Hashtbl.remove r t
+ with
+ Not_found -> ()
+
+ let rec delete_list l st=
+ match l with
+ []->()
+ | t::q -> delete t st;delete_list q st
+
+end
+
+let rec combine_rec uf st=function
+ []->[]
+ | v::pending->
+ let combine=(combine_rec uf st pending) in
+ let s=UF.signature uf v in
+ try (v,(ST.query s st))::combine with
+ Not_found->
+ ST.enter v s st;combine
+
+let rec process_rec uf st=function
+ []->[]
+ | (v,w)::combine->
+ let pending=process_rec uf st combine in
+ let i=UF.find uf v
+ and j=UF.find uf w in
+ if (i==j)|| ((Hashtbl.hash i)=(Hashtbl.hash j) && (i=j)) then
+ pending
+ else
+ if (UF.size uf i)<(UF.size uf j) then
+ let l=UF.list uf i in
+ UF.union uf j i (v,w,UF.Congr);
+ ST.delete_list l st;
+ l@pending
+ else
+ let l=UF.list uf j in
+ UF.union uf i j (w,v,UF.Congr);
+ ST.delete_list l st;
+ l@pending
+
+let rec cc_rec uf st=function
+ []->()
+ | pending->
+ let combine=combine_rec uf st pending in
+ let pending0=process_rec uf st combine in
+ (cc_rec uf st pending0)
+
+let cc uf=(cc_rec uf (ST.empty ()) (UF.nodes uf))
+
+let rec make_uf syms=function
+ []->(UF.empty ())
+ | (ax,(v,w))::q->
+ let uf=make_uf syms q in
+ let i1=UF.add v uf syms in
+ let i2=UF.add w uf syms in
+ UF.union uf (UF.find uf i2) (UF.find uf i1) (i1,i2,(UF.Ax ax));
+ uf
+
+let decide_prb (axioms,(v,w))=
+ let syms=Hashtbl.create init_size in
+ let uf=make_uf syms axioms in
+ let i1=UF.add v uf syms in
+ let i2=UF.add w uf syms in
+ cc uf;
+ (UF.find uf i1)=(UF.find uf i2)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/cc/ccalgo.mli b/contrib/cc/ccalgo.mli
new file mode 100644
index 0000000000..6f55d85418
--- /dev/null
+++ b/contrib/cc/ccalgo.mli
@@ -0,0 +1,67 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* $Id$ *)
+
+val init_size : int
+
+type term = Symb of Term.constr | Appli of term * term
+
+module UF :
+ sig
+ type tag = Congr | Ax of Names.identifier
+ and cl =
+ Rep of int * int list
+ | Eqto of int * (int * int * tag)
+ and vertex = Leaf | Node of (int * int)
+ and t = int ref * (int, cl * vertex * term) Hashtbl.t
+ val empty : unit -> t
+ val add_lst : int -> int -> t -> unit
+ val find : t -> int -> int
+ val list : t -> int -> int list
+ val size : t -> int -> int
+ val signature : t -> int -> int * int
+ val nodes : t -> int list
+ val add :
+ term ->
+ int ref * (int, cl * vertex * term) Hashtbl.t ->
+ (term, int) Hashtbl.t -> int
+ val union :
+ t -> int -> int -> int * int * tag -> unit
+ end
+
+module ST :
+ sig
+ type t =
+ (int * int, int) Hashtbl.t *
+ (int, int * int) Hashtbl.t
+ val empty :
+ unit -> ('a, 'b) Hashtbl.t * ('c, 'd) Hashtbl.t
+ val enter : int -> int * int -> t -> unit
+ val query : int * int -> t -> int
+ val delete : int -> t -> unit
+ val delete_list : int list -> t -> unit
+ end
+
+val combine_rec :
+ UF.t -> ST.t -> int list -> (int * int) list
+
+val process_rec :
+ UF.t -> ST.t -> (int * int) list -> int list
+
+val cc_rec : UF.t -> ST.t -> int list -> unit
+
+val cc : UF.t -> unit
+
+val make_uf :
+ (term, int) Hashtbl.t ->
+ (Names.identifier * (term * term)) list -> UF.t
+
+val decide_prb :
+ (Names.identifier * (term * term)) list * (term * term) ->
+ bool
diff --git a/contrib/cc/ccproof.ml b/contrib/cc/ccproof.ml
new file mode 100644
index 0000000000..26e2299179
--- /dev/null
+++ b/contrib/cc/ccproof.ml
@@ -0,0 +1,118 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* $Id$ *)
+
+(* This file uses the (non-compressed) union-find structure to generate *)
+(* proof-trees that will be transformed into proof-terms in cctac.ml4 *)
+
+open Names
+open Ccalgo
+
+type proof=
+ Ax of identifier
+ | Refl of term
+ | Trans of proof*proof
+ | Sym of proof
+ | Congr of proof*proof
+
+let rec up_path uf i l=
+ let (cl,_,_)=(Hashtbl.find uf i) in
+ match cl with
+ UF.Eqto(j,t)->up_path uf j (((i,j),t)::l)
+ | UF.Rep(_,_)->l
+
+let rec min_path=function
+ ([],l2)->([],l2)
+ | (l1,[])->(l1,[])
+ | (((c1,t1)::q1),((c2,t2)::q2)) as cpl->
+ if c1=c2 then
+ min_path (q1,q2)
+ else
+ cpl
+
+let pcongr=function
+ ((Refl t1),(Refl t2))->Refl (Appli (t1,t2))
+ | (p1,p2) -> Congr (p1,p2)
+
+let rec ptrans=function
+ ((Refl _),p)->p
+ | (p,(Refl _))->p
+ | (Trans(p1,p2),p3)->ptrans(p1,ptrans (p2,p3))
+ | (Congr(p1,p2),Congr(p3,p4))->pcongr(ptrans(p1,p3),ptrans(p2,p4))
+ | (Congr(p1,p2),Trans(Congr(p3,p4),p5))->
+ ptrans(pcongr(ptrans(p1,p3),ptrans(p2,p4)),p5)
+ | (p1,p2)->Trans (p1,p2)
+
+let rec psym=function
+ Refl p->Refl p
+ | Sym p->p
+ | Ax s-> Sym(Ax s)
+ | Trans (p1,p2)-> ptrans ((psym p2),(psym p1))
+ | Congr (p1,p2)-> pcongr ((psym p1),(psym p2))
+
+let pcongr=function
+ ((Refl t1),(Refl t2))->Refl (Appli (t1,t2))
+ | (p1,p2) -> Congr (p1,p2)
+
+let build_proof ((a,m):UF.t) i j=
+ let rec equal_proof i j=
+ let (li,lj)=min_path ((up_path m i []),(up_path m j [])) in
+ ptrans ((path_proof i li),(psym (path_proof j lj)))
+ and arrow_proof ((i,j),t)=
+ let (i0,j0,t0)=t in
+ let pi=(equal_proof i i0) in
+ let pj=psym (equal_proof j j0) in
+ let pij=
+ match t0 with
+ UF.Ax s->Ax s
+ | UF.Congr->(congr_proof i0 j0)
+ in ptrans(ptrans (pi,pij),pj)
+ and path_proof i=function
+ []->let (_,_,t)=Hashtbl.find m i in Refl t
+ | (((_,j),_) as x)::q->ptrans ((path_proof j q),(arrow_proof x))
+ and congr_proof i j=
+ let (_,vi,_)=(Hashtbl.find m i) and (_,vj,_)=(Hashtbl.find m j) in
+ match (vi,vj) with
+ ((UF.Node(i1,i2)),(UF.Node(j1,j2)))->
+ pcongr ((equal_proof i1 j1),(equal_proof i2 j2))
+ | _ -> failwith "congr_proof: couldn't find subterms"
+ in
+ (equal_proof i j)
+
+let rec type_proof uf axioms p=
+ match p with
+ Ax s->List.assoc s axioms
+ | Refl t->(t,t)
+ | Trans (p1,p2)->
+ let (s1,t1)=type_proof uf axioms p1
+ and (t2,s2)=type_proof uf axioms p2 in
+ if t1=t2 then (s1,s2) else failwith "invalid transitivity"
+ | Sym p->let (t1,t2)=type_proof uf axioms p in (t2,t1)
+ | Congr (p1,p2)->
+ let (i1,j1)=(type_proof uf axioms p1)
+ and (i2,j2)=(type_proof uf axioms p2) in
+ ((Appli (i1,i2)),(Appli (j1,j2)))
+
+let cc_proof (axioms,(v,w))=
+ let syms=Hashtbl.create init_size in
+ let uf=make_uf syms axioms in
+ let i1=(UF.add v uf syms) in
+ let i2=(UF.add w uf syms) in
+ cc uf;
+ if (UF.find uf i1)=(UF.find uf i2) then
+ let p=(build_proof uf i1 i2) in
+ (if (v,w)=(type_proof uf axioms p) then Some (p,uf,axioms)
+ else failwith "Proof check failed !!")
+ else
+ None;;
+
+
+
+
+
diff --git a/contrib/cc/ccproof.mli b/contrib/cc/ccproof.mli
new file mode 100644
index 0000000000..a699af6941
--- /dev/null
+++ b/contrib/cc/ccproof.mli
@@ -0,0 +1,48 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* $Id$ *)
+
+open Ccalgo
+
+type proof =
+ Ax of Names.identifier
+ | Refl of term
+ | Trans of proof * proof
+ | Sym of proof
+ | Congr of proof * proof
+
+val up_path :
+ (int, UF.cl * 'a * 'b) Hashtbl.t ->
+ int ->
+ ((int * int) * (int * int * UF.tag)) list ->
+ ((int * int) * (int * int * UF.tag)) list
+
+val min_path :
+ ('a * 'b) list * ('a * 'c) list ->
+ ('a * 'b) list * ('a * 'c) list
+
+val pcongr : proof * proof -> proof
+val ptrans : proof * proof -> proof
+val psym : proof -> proof
+val pcongr : proof * proof -> proof
+
+val build_proof : UF.t -> int -> int -> proof
+
+val type_proof :
+ 'a ->
+ (Names.identifier * (term * term)) list ->
+ proof -> term * term
+
+val cc_proof :
+ (Names.identifier * (term * term)) list *
+ (term * term) ->
+ (proof * UF.t *
+ (Names.identifier * (term * term)) list)
+ option
+
diff --git a/contrib/cc/cctac.ml4 b/contrib/cc/cctac.ml4
new file mode 100644
index 0000000000..f7a9e723fa
--- /dev/null
+++ b/contrib/cc/cctac.ml4
@@ -0,0 +1,161 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(*i camlp4deps: "parsing/grammar.cma kernel/names.cmo parsing/ast.cmo parsing/g_tactic.cmo parsing/g_ltac.cmo parsing/g_constr.cmo" i*)
+
+(* $Id$ *)
+
+(* This file is the interface between the c-c algorithm and Coq *)
+
+open Evd
+open Proof_type
+open Names
+open Libnames
+open Nameops
+open Term
+open Tacmach
+open Tactics
+open Tacticals
+open Ccalgo
+open Tacinterp
+open Ccproof
+open Pp
+open Util
+open Format
+
+exception Not_an_eq
+
+let fail()=raise Not_an_eq
+
+let constr_of_string s () =
+ Declare.constr_of_reference (Nametab.locate (qualid_of_string s))
+
+let eq2eqT_theo = constr_of_string "Coq.Logic.Eqdep_dec.eq2eqT"
+let eqT2eq_theo = constr_of_string "Coq.Logic.Eqdep_dec.eqT2eq"
+let congr_theo = constr_of_string "Coq.cc.CC.Congr_nodep"
+let congr_dep_theo = constr_of_string "Coq.cc.CC.Congr_dep"
+
+let fresh_id1=id_of_string "eq1" and fresh_id2=id_of_string "eq2"
+
+let t_make_app=(Array.fold_left (fun s t->Appli (s,t)))
+
+(* decompose member of equality in an applicative format *)
+
+let rec decompose_term t=
+ match kind_of_term t with
+ App (f,args)->let targs=Array.map decompose_term args in
+ (t_make_app (Symb f) targs)
+ | _->(Symb t)
+
+(* decompose equality in members and type *)
+
+let eq_type_of_term term=
+ match kind_of_term term with
+ App (f,args)->
+ (try
+ let ref = Declare.reference_of_constr f in
+ if (ref=Coqlib.glob_eq || ref=Coqlib.glob_eqT) &&
+ (Array.length args)=3
+ then (args.(0),args.(1),args.(2))
+ else fail()
+ with
+ Not_found -> fail ())
+ | _ ->fail ()
+
+(* read an equality *)
+
+let read_eq term=
+ let (_,t1,t2)=eq_type_of_term term in
+ ((decompose_term t1),(decompose_term t2))
+
+(* rebuild a term from applicative format *)
+
+let rec make_term=function
+ Symb s->s
+ | Appli (s1,s2)->make_app [(make_term s2)] s1
+and make_app l=function
+ Symb s->mkApp (s,(Array.of_list l))
+ | Appli (s1,s2)->make_app ((make_term s2)::l) s1
+
+(* store all equalities from the context *)
+
+let rec read_hyps=function
+ []->[]
+ | (id,_,e)::hyps->let q=(read_hyps hyps) in
+ try (id,(read_eq e))::q with Not_an_eq -> q
+
+(* build a problem ( i.e. read the goal as an equality ) *)
+
+let make_prb gl=
+ let concl=gl.evar_concl in
+ let hyps=gl.evar_hyps in
+ (read_hyps hyps),(read_eq concl)
+
+(* apply tac, followed (or not) by aplication of theorem theo *)
+
+let st_wrap theo tac=
+ tclORELSE tac (tclTHEN (apply theo) tac)
+
+(* generate an adhoc tactic following the proof tree *)
+
+let rec proof_tac uf axioms=function
+ Ax id->(fun gl->(st_wrap (eq2eqT_theo ()) (exact_check (mkVar id)) gl))
+ | Refl t->reflexivity
+ | Trans (p1,p2)->let t=(make_term (snd (type_proof uf axioms p1))) in
+ (tclTHENS (transitivity t)
+ [(proof_tac uf axioms p1);(proof_tac uf axioms p2)])
+ | Sym p->tclTHEN symmetry (proof_tac uf axioms p)
+ | Congr (p1,p2)->
+ (fun gl->
+ let (s1,t1)=(type_proof uf axioms p1) and
+ (s2,t2)=(type_proof uf axioms p2) in
+ let ts1=(make_term s1) and tt1=(make_term t1)
+ and ts2=(make_term s2) and tt2=(make_term t2) in
+ let typ1=pf_type_of gl ts1 and typ2=pf_type_of gl ts2 in
+ let (typb,_,_)=(eq_type_of_term gl.it.evar_concl) in
+ let act=mkApp ((congr_theo ()),[|typ2;typb;ts1;tt1;ts2;tt2|]) in
+ tclORELSE
+ (tclTHENS
+ (apply act)
+ [(proof_tac uf axioms p1);(proof_tac uf axioms p2)])
+ (tclTHEN
+ (let p=mkLambda(destProd typ1) in
+ let acdt=mkApp((congr_dep_theo ()),[|typ2;p;ts1;tt1;ts2|]) in
+ apply acdt) (proof_tac uf axioms p1))
+ gl)
+
+(* wrap everything *)
+
+let cc_tactic gl_sg=
+ Library.check_required_library ["Coq";"cc";"CC"];
+ let gl=gl_sg.it in
+ let prb=try make_prb gl with Not_an_eq ->
+ errorlabstrm "CC" [< str "Couldn't match goal with an equality" >] in
+ match (cc_proof prb) with
+ None->errorlabstrm "CC" [< str "CC couldn't solve goal" >]
+ | Some (p,uf,axioms)->let tac=proof_tac uf axioms p in
+ (tclORELSE (st_wrap (eqT2eq_theo ()) tac)
+ (fun _->errorlabstrm "CC"
+ [< str "CC doesn't know how to handle dependent equality." >]) gl_sg)
+
+(* Tactic registration *)
+
+TACTIC EXTEND CC
+ [ "CC" ] -> [ cc_tactic ]
+END
+
+
+
+
+
+
+
+
+
+
+