aboutsummaryrefslogtreecommitdiffhomepage
path: root/tactics/contradiction.ml
blob: 565f30cfb12b95f1ec25c9a262dae72bce6e201f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
(************************************************************************)
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2012     *)
(*   \VV/  **************************************************************)
(*    //   *      This file is distributed under the terms of the       *)
(*         *       GNU Lesser General Public License Version 2.1        *)
(************************************************************************)

open Errors
open Term
open Hipattern
open Tacmach
open Tacticals
open Tactics
open Coqlib
open Reductionops
open Misctypes
open Proofview.Notations

(* Absurd *)

let absurd c gls =
  let env = pf_env gls and sigma = project gls in
  let j = Retyping.get_judgment_of env sigma c in
  let sigma, j = Coercion.inh_coerce_to_sort Loc.ghost env sigma j in
  let c = j.Environ.utj_val in
  (tclTHENS
     (tclTHEN (elim_type (build_coq_False ())) (cut c))
     ([(tclTHENS
          (cut (mkApp(build_coq_not (),[|c|])))
	  ([(tclTHEN (Proofview.V82.of_tactic intros)
	       ((fun gl ->
		   let ida = pf_nth_hyp_id gl 1
                   and idna = pf_nth_hyp_id gl 2 in
                   exact_no_check (mkApp(mkVar idna,[|mkVar ida|])) gl)));
            tclIDTAC]));
       tclIDTAC])) { gls with Evd.sigma; }
let absurd c = Proofview.V82.tactic (absurd c)

(* Contradiction *)

let filter_hyp f tac =
  let rec seek = function
    | [] -> raise Not_found
    | (id,_,t)::rest when f t -> tac id
    | _::rest -> seek rest in
  Goal.hyps >>- fun hyps ->
  seek (Environ.named_context_of_val hyps)

let contradiction_context =
  Goal.env >>- fun env ->
  Goal.defs >>- fun sigma ->
  let rec seek_neg l = match l with
    | [] ->  Proofview.tclZERO (UserError ("" , Pp.str"No such contradiction"))
    | (id,_,typ)::rest ->
	let typ = whd_betadeltaiota env sigma typ in
	if is_empty_type typ then
	  simplest_elim (mkVar id)
	else match kind_of_term typ with
	  | Prod (na,t,u) when is_empty_type u ->
	      (Proofview.tclORELSE
                 begin
                   Tacmach.New.pf_apply is_conv_leq >>- fun is_conv_leq ->
	           filter_hyp (fun typ -> is_conv_leq typ t)
		     (fun id' -> simplest_elim (mkApp (mkVar id,[|mkVar id'|])))
                 end
                 begin function
	           | Not_found -> seek_neg rest
                   | e -> Proofview.tclZERO e
                 end)
	  | _ -> seek_neg rest in
  Goal.hyps >>- fun hyps ->
  let hyps = Environ.named_context_of_val hyps in
  seek_neg hyps

let is_negation_of env sigma typ t =
  match kind_of_term (whd_betadeltaiota env sigma t) with
    | Prod (na,t,u) -> is_empty_type u && is_conv_leq env sigma typ t
    | _ -> false

let contradiction_term (c,lbind as cl) =
  Goal.env >>- fun env ->
  Goal.defs >>- fun sigma ->
  Tacmach.New.pf_apply Typing.type_of >>- fun type_of ->
  let typ = type_of c in
  let _, ccl = splay_prod env sigma typ in
  if is_empty_type ccl then
    Tacticals.New.tclTHEN (elim false cl None) (Proofview.V82.tactic (tclTRY assumption))
  else
    Proofview.tclORELSE
      begin
        if lbind = NoBindings then
	  filter_hyp (is_negation_of env sigma typ)
	    (fun id -> simplest_elim (mkApp (mkVar id,[|c|])))
        else
	  Proofview.tclZERO Not_found
      end
      begin function
        | Not_found -> Proofview.tclZERO (Errors.UserError ("",Pp.str"Not a contradiction."))
        | e -> Proofview.tclZERO e
      end

let contradiction = function
  | None -> Tacticals.New.tclTHEN intros contradiction_context
  | Some c -> contradiction_term c