(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Separate compilation and syntactic linking *)
(** This file follows "approach A" from the paper "Lightweight Verification of Separate Compilation" by Kang, Kim, Hur, Dreyer and Vafeiadis, POPL 2016. *)
(** * Syntactic linking *)
(** A syntactic element [A] supports syntactic linking if it is equipped with the following: - a partial binary operator [link] that produces the result of linking two elements, or fails if they cannot be linked (e.g. two definitions that are incompatible); - a preorder [linkorder] with the meaning that [linkorder a1 a2] holds if [a2] can be obtained by linking [a1] with some other syntactic element. *)
Class Linker (A: Type) := {
link: A -> A -> option A;
linkorder: A -> A -> Prop;
linkorder_refl: forall x, linkorder x x;
linkorder_trans: forall x y z, linkorder x y -> linkorder y z -> linkorder x z;
link_linkorder: forall x y z, link x y = Some z -> linkorder x z /\ linkorder y z
}.
(** Linking function definitions.  External functions of the [EF_external] kind can link with internal function definitions; the result of linking is the internal definition.  Two external functions can link if they are identical. *)
Definition link_fundef {F: Type} (fd1 fd2: fundef F) :=
match fd1, fd2 with
| Internal _, Internal _ => None
| External ef1, External ef2 =>
if external_function_eq ef1 ef2 then Some (External ef1) else None
| Internal f, External ef =>
match ef with EF_external id sg => Some (Internal f) | _ => None end
| External ef, Internal f =>
match ef with EF_external id sg => Some (Internal f) | _ => None end
end.
Inductive linkorder_fundef {F: Type}: fundef F -> fundef F -> Prop :=
| linkorder_fundef_refl: forall fd, linkorder_fundef fd fd
| linkorder_fundef_ext_int: forall f id sg, linkorder_fundef (External (EF_external id sg)) (Internal f).
Instance Linker_fundef (F: Type): Linker (fundef F) := {
link := link_fundef;
linkorder := linkorder_fundef
}.

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) |}.