Ltac qcancel P :=
lazymatch P with
| sepcon ?A ?B =>
match goal with |- _ |-- ?Q =>
try match Q with context [A] =>
let a := fresh "A" in set (a:=A);
rewrite ?(pull_left_special0 a), ?(pull_left_special a);
apply cancel_left;
clear a
end;
qcancel B
end
| ?A =>
try match goal with |- _ |-- ?Q =>
lazymatch Q with context [A] =>
let a := fresh "A" in set (a:=A);
rewrite ?(pull_left_special0 a), ?(pull_left_special a);
rewrite ?(pull_left_special0 A), ?(pull_left_special A);
apply cancel_left;
clear a
end
end
end.
Ltac is_Type_or_type T :=
match type of T with
| Type => idtac
| type => idtac
end.

(* Specifications: *)
Lemma fun_equal: forall {A B} (f g : A -> B) (x y : A),
f = g -> x = y -> f x = g y.
Lemma delete_nth_SEP: forall R n R0,
nth_error R n = Some R0 ->
fold_right_sepcon R |-- R0 * fold_right_sepcon (delete_nth n R).
Lemma syntactic_cancel_solve1: forall F,
fold_right_sepcon F |-- fold_right_sepcon nil * fold_right_sepcon F.
Lemma syntactic_cancel_solve2: forall G,
fold_right_sepcon G |-- fold_right_sepcon nil * TT.
Lemma syntactic_cancel_spec1: forall G1 L1 G2 L2 F,
syntactic_cancel G1 L1 G2 L2 ->
fold_right_sepcon G2 |-- fold_right_sepcon L2 * F ->
fold_right_sepcon G1 |-- fold_right_sepcon L1 * F.
Lemma syntactic_cancel_spec2: forall G1 L1 G2 L2 G3 L3 F,
syntactic_cancel G1 L1 G2 L2 ->
syntactic_cancel G2 L2 G3 L3 ->
fold_right_sepcon G3 |-- fold_right_sepcon L3 * F ->
fold_right_sepcon G1 |-- fold_right_sepcon L1 * F.
Lemma syntactic_cancel_solve3:
fold_right_sepcon nil |-- fold_right_sepcon nil.
Lemma syntactic_cancel_spec3: forall G1 L1 G2 L2,
syntactic_cancel G1 L1 G2 L2 ->
fold_right_sepcon G2 |-- fold_right_sepcon L2 ->
fold_right_sepcon G1 |-- fold_right_sepcon L1.