(*** *** The actual tactic *)
(** Often, the target hypotheses declared using the [Transport] class have existential quantifiers, and need to be broken up to get to the actual relational hypotheses we're interested in. The [split_hyp] tactic does that. We also use that opportunity to split up [prod_rel] and [rel_incr] when appropriate. For [prod_rel] this is especially useful when [rel_curry] is involved. Likewise we generally want to split up [rel_incr] as soon as possible, so that the existentially quantified world therein can be used to instantiate evars that have been spawned from that point on.  As a generally useful complement, the [split_hyps] tactic applies the same process to all hypotheses. *)
Ltac split_hyp H :=
lazymatch type of H with
| ex _ =>
destruct H as [? H];
split_hyp H
| _ /\ _ =>
let H1 := fresh in
let H2 := fresh in
destruct H as [H1 H2];
split_hyp H1;
split_hyp H2
| prod_rel ?Rx ?Ry (?x1, ?y1) (?x2, ?y2) =>
change (Rx x1 x2 /\ Ry y1 y2) in H;
split_hyp H
| rel_incr ?acc ?R ?w ?x ?y =>
let w' := fresh w "'" in
let Hw' := fresh "H" w' in
destruct H as (w' & Hw' & H);
split_hyp H
| klr_diam ?l ?R ?w ?x ?y =>
let w' := fresh w "'" in
let Hw' := fresh "H" w' in
destruct H as (w' & Hw' & H);
split_hyp H
| prod_klr ?Rx ?Ry ?w (?x1, ?y1) (?x2, ?y2) =>
change (Rx w x1 x2 /\ Ry w y1 y2) in H;
split_hyp H
| _ =>
idtac
end.
Ltac split_hyps :=
repeat
lazymatch goal with
| H: ex _ |- _ =>
destruct H
| H: _ /\ _ |- _ =>
destruct H
| H: prod_rel ?Rx ?Ry (?x1, ?y1) (?x2, ?y2) |- _ =>
change (Rx x1 x2 /\ Ry y1 y2) in H
| H: klr_diam ?R ?w ?x ?y |- _ =>
let w' := fresh w "'" in
let Hw' := fresh "H" w' in
destruct H as (w' & Hw' & H)
| H: prod_klr ?Rx ?Ry ?w (?x1, ?y1) (?x2, ?y2) |- _ =>
change (Rx w x1 x2 /\ Ry w y1 y2) in H
end.
(** We're now ready to defined the [transport] tactic, which essentially looks up a [Transport] instance and applies it the the hypothesis to be transported, using [RAuto] to solve the relational subgoal. Note that the relation and right-hand side will usually contain existential variables, but the proof search can hopefully proceed by following the structure of the left-hand side. Once the [Transport] instance has been applied, we use [split_hyp] on the modified hypothesis as post-processing.  Because we have many open-ended evars involved, it is easy for trivial relations such as [eq] to kick in and sabotage us, overriding the more interesting properties that we actually want to use and preventing any progress from actually being made. In order to attenuate this issue, we require that [RAuto] yield unconvertible related elements.  Another pitfall we want to avoid is illustrated by the [option_rel] case. When we have a hypothesis of the form [H: m = Some a], but no interesting way to relate [m] to something else, then the search for [(option_rel ?R) m ?n] can end up using [H] itself (because [option_rel eq] is reflexive, hence [subrel_eq] applies). To prevent such cases we need to make sure that the hypothesis being transported is not used to discharge the relational premise, and so we revert it into the conclusing before we proceed, and use the following lemma to work on a goal of that form directly. *)

Lemma transport_in_goal `{Transport} `{!RAuto (R a b)} `{!Unconvertible a b}:
forall (Q: Prop), (PB -> Q) -> (PA -> Q).