(** In many cases, the context for [match_program_gen] is the source program or
  source compilation unit itself.  We provide a specialized definition for this case. *)

Definition match_program {F1 V1 F2 V2: Type} {LF: Linker F1} {LV: Linker V1}
                         (match_fundef: program F1 V1 -> F1 -> F2 -> Prop)
                         (match_varinfo: V1 -> V2 -> Prop)
                         (p1: program F1 V1) (p2: program F2 V2) : Prop :=
  match_program_gen match_fundef match_varinfo p1 p1 p2.

(* Specifications: *)
Lemma match_program_main: forall {F1 V1 F2 V2: Type} {LF: Linker F1} {LV: Linker V1} {match_fundef: program F1 V1 -> F1 -> F2 -> Prop} {match_varinfo: V1 -> V2 -> Prop} {p1: program F1 V1} {p2: program F2 V2}, match_program match_fundef match_varinfo p1 p2 -> p2.(prog_main) = p1.(prog_main).
Theorem match_transform_partial_program2: forall {C F1 V1 F2 V2: Type} {LC: Linker C} {LF: Linker F1} {LV: Linker V1} (match_fundef: C -> F1 -> F2 -> Prop) (match_varinfo: V1 -> V2 -> Prop) (transf_fun: ident -> F1 -> res F2) (transf_var: ident -> V1 -> res V2) (ctx: C) (p: program F1 V1) (tp: program F2 V2), transform_partial_program2 transf_fun transf_var p = OK tp -> (forall i f tf, transf_fun i f = OK tf -> match_fundef ctx f tf) -> (forall i v tv, transf_var i v = OK tv -> match_varinfo v tv) -> match_program_gen match_fundef match_varinfo ctx p tp.
Theorem match_transform_partial_program_contextual: forall {A B V: Type} {LA: Linker A} {LV: Linker V} (match_fundef: program A V -> A -> B -> Prop) (transf_fun: A -> res B) (p: program A V) (tp: program B V), transform_partial_program transf_fun p = OK tp -> (forall f tf, transf_fun f = OK tf -> match_fundef p f tf) -> match_program match_fundef eq p tp.
Theorem match_transform_program_contextual: forall {A B V: Type} {LA: Linker A} {LV: Linker V} (match_fundef: program A V -> A -> B -> Prop) (transf_fun: A -> B) (p: program A V), (forall f, match_fundef p f (transf_fun f)) -> match_program match_fundef eq p (transform_program transf_fun p).
Theorem match_transform_partial_program: forall {A B V: Type} {LA: Linker A} {LV: Linker V} (transf_fun: A -> res B) (p: program A V) (tp: program B V), transform_partial_program transf_fun p = OK tp -> match_program (fun cu f tf => transf_fun f = OK tf) eq p tp.
Theorem match_transform_program: forall {A B V: Type} {LA: Linker A} {LV: Linker V} (transf: A -> B) (p: program A V), match_program (fun cu f tf => tf = transf f) eq p (transform_program transf p).
Lemma link_match_globvar: forall v1 tv1 v2 tv2 v, link v1 v2 = Some v -> match_globvar match_varinfo v1 tv1 -> match_globvar match_varinfo v2 tv2 -> exists tv, link tv1 tv2 = Some tv /\ match_globvar match_varinfo v tv.
Lemma link_match_globdef: forall ctx1 ctx2 ctx g1 tg1 g2 tg2 g, linkorder ctx1 ctx -> linkorder ctx2 ctx -> link g1 g2 = Some g -> match_globdef match_fundef match_varinfo ctx1 g1 tg1 -> match_globdef match_fundef match_varinfo ctx2 g2 tg2 -> exists tg, link tg1 tg2 = Some tg /\ match_globdef match_fundef match_varinfo ctx g tg.
Lemma match_globdef_linkorder: forall ctx ctx' g tg, match_globdef match_fundef match_varinfo ctx g tg -> linkorder ctx ctx' -> match_globdef match_fundef match_varinfo ctx' g tg.
Theorem link_match_program: forall ctx1 ctx2 ctx p1 p2 tp1 tp2 p, link p1 p2 = Some p -> match_program_gen match_fundef match_varinfo ctx1 p1 tp1 -> match_program_gen match_fundef match_varinfo ctx2 p2 tp2 -> linkorder ctx1 ctx -> linkorder ctx2 ctx -> exists tp, link tp1 tp2 = Some tp /\ match_program_gen match_fundef match_varinfo ctx p tp.