Library Waterproof.Util.Since
Require Import Ltac2.Ltac2.
Require Import Ltac2.Message.
Local Ltac2 concat_list (ls : message list) : message :=
List.fold_right concat (of_string "") ls.
Require Import Util.Constr.
Require Import Util.MessagesToUser.
Require Import Waterprove.
Require Import Util.Init.
Require Import Util.TypeCorrector.
Require Import Notations.Sets.
Local Ltac2 get_type (x: constr) : constr := eval unfold type_of in (type_of $x).
Local Ltac2 check_if_not_reference (x : constr) :=
let type_x := get_type x in
match! type_x with
| Prop => ()
| Set => ()
| Type => ()
| _ => throw (concat_list
[of_string "Cannot use reference "; of_constr x; of_string " with `Since`. Try `By "; of_constr x; of_string " ...` instead."])
end.
Local Ltac2 check_if_not_statement (x : constr) :=
let err_msg := concat_list
[of_string "Cannot use statement "; of_constr x; of_string " with `By`. Try `Since "; of_constr x; of_string " ...` instead."]
in
let type_x := get_type x in
match! type_x with
| Prop => throw err_msg
| Set => throw err_msg
| Type => throw err_msg
| _ => ()
end.
Attempts to prove claimed_cause with minimal automation,
and then executes by_tactic with the proof of claimed_cause
as an argument.
Expects that by_tactic can throw a (Waterprove.)FailedToUse error,
those errors are caught; the extra lemma that the automation failed to use
is used in a new error that is thrown.
Ltac2 since_framework (by_tactic : constr -> unit) (claimed_cause : constr) :=
let claimed_cause := correct_type_by_wrapping claimed_cause in
check_if_not_reference claimed_cause;
let id_cause := Fresh.in_goal @_temp in
match Control.case (fun () =>
let unsealed_claimed_cause := eval unfold seal in $claimed_cause in
assert $unsealed_claimed_cause as $id_cause by
(waterprove 1 true Shorten))
with
| Err (FailedToProve _) =>
throw (concat_list
[of_string "State that "; of_constr claimed_cause; of_string " holds";
of_string " before using it in `Since ...`."])
| Err exn => Control.zero exn
| Val _ =>
let cause := Control.hyp id_cause in
match Control.case (fun () =>
by_tactic cause)
with
| Val _ => clear $id_cause
| Err (FailedToUse h) =>
let type_h := (get_type h) in
clear $id_cause;
throw (concat_list
[of_string "Could not verify this follows from "; of_constr type_h; of_string "."])
| Err exn => clear $id_cause; Control.zero exn
end
end.
Ltac2 unseal_lemma (xtr_lemma : constr) : ident :=
let aux_id := Fresh.fresh (Fresh.Free.of_goal ()) @_aux in
let statement_xtr_lemma := Constr.type xtr_lemma in
let unsealed_statement := eval unfold seal in $statement_xtr_lemma in
assert $unsealed_statement as $aux_id;
Control.focus 1 1 (fun () => exact $xtr_lemma);
aux_id.
Wrapper for the main functionality of 'By ...'-tactics,
such that the main fucntionality can be reused in 'Since ...'-tactics.
Checks whether xtr_lemma is not a statement (i.e. not a Prop/Set/Type) and
catches (Waterprove.)FailedToUse errors to turn them into user-readable errors.
Ltac2 wrapper_core_by_tactic (by_tactic : constr -> unit) (xtr_lemma : constr) :=
check_if_not_statement xtr_lemma;
let xtr_lemma_contains_seal :=
match! (Constr.type xtr_lemma) with
| context [seal _ _ ] => true
| _ => false
end in
let (opt_id, aux_lemma) :=
if xtr_lemma_contains_seal then
let aux_id := unseal_lemma xtr_lemma in
(Some aux_id, Control.hyp aux_id)
else (None, xtr_lemma) in
match Control.case (fun () => by_tactic aux_lemma) with
| Val _ => ()
| Err (FailedToUse h) => throw (concat_list
[of_string "Could not verify this follows from "; of_constr h; of_string "."])
| Err exn => Control.zero exn
end;
match opt_id with
| Some id => Std.clear [id]
| _ => ()
end.
check_if_not_statement xtr_lemma;
let xtr_lemma_contains_seal :=
match! (Constr.type xtr_lemma) with
| context [seal _ _ ] => true
| _ => false
end in
let (opt_id, aux_lemma) :=
if xtr_lemma_contains_seal then
let aux_id := unseal_lemma xtr_lemma in
(Some aux_id, Control.hyp aux_id)
else (None, xtr_lemma) in
match Control.case (fun () => by_tactic aux_lemma) with
| Val _ => ()
| Err (FailedToUse h) => throw (concat_list
[of_string "Could not verify this follows from "; of_constr h; of_string "."])
| Err exn => Control.zero exn
end;
match opt_id with
| Some id => Std.clear [id]
| _ => ()
end.