Section LINKER_PROG.
Context {F V: Type} {LF: Linker F} {LV: Linker V} (p1 p2: program F V).
Let dm1 := prog_defmap p1.
Let dm2 := prog_defmap p2.
Definition link_prog_check (x: ident) (gd1: globdef F V) :=
match dm2!x with
| None => true
| Some gd2 =>
In_dec peq x p1.(prog_public)
&& In_dec peq x p2.(prog_public)
&& match link gd1 gd2 with Some _ => true | None => false end
end.
Definition link_prog_merge (o1 o2: option (globdef F V)) :=
match o1, o2 with
| None, _ => o2
| _, None => o1
| Some gd1, Some gd2 => link gd1 gd2
end.
Definition link_prog :=
if ident_eq p1.(prog_main) p2.(prog_main)
&& PTree_Properties.for_all dm1 link_prog_check then
Some {| prog_main := p1.(prog_main);
prog_public := p1.(prog_public) ++ p2.(prog_public);
prog_defs := PTree.elements (PTree.combine link_prog_merge dm1 dm2) |}
else
None.

Lemma prog_defmap_elements:
forall (m: PTree.t (globdef F V)) pub mn x,
(prog_defmap {| prog_defs := PTree.elements m; prog_public := pub; prog_main := mn |})!x = m!x.