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 link_prog_succeeds:
p1.(prog_main) = p2.(prog_main) ->
(forall id gd1 gd2,
dm1!id = Some gd1 -> dm2!id = Some gd2 ->
In id p1.(prog_public) /\ In id p2.(prog_public) /\ link gd1 gd2 <> None) ->
link_prog =
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) |}.