From Velus Require Import Common.
From Velus Require Import Operators.
From Velus Require Import Clocks.
From Velus Require Import Lustre.LSyntax.
From Coq Require Import List.
Import List.ListNotations.
Open Scope list_scope.
From Coq Require Import Morphisms.
From Velus Require Import Environment.
From Velus Require Import Operators.
 Lustre typing 
Module Type LTYPING
       (
Import Ids  : 
IDS)
       (
Import Op   : 
OPERATORS)
       (
Import Syn  : 
LSYNTAX Ids Op).
  
Inductive wt_clock : 
list (
ident * 
type) -> 
clock -> 
Prop :=
  | 
wt_Cbase: 
forall vars,
      
wt_clock vars Cbase
  | 
wt_Con: 
forall vars ck x b,
      
In (
x, 
bool_type) 
vars ->
      
wt_clock vars ck ->
      
wt_clock vars (
Con ck x b).
  
Inductive wt_nclock : 
list (
ident * 
type) -> 
nclock -> 
Prop :=
  | 
wt_Cnamed: 
forall vars id ck,
      
wt_clock vars ck ->
      
wt_nclock vars (
ck, 
id).
  
Section WellTyped.
    
Variable G    : 
global.
    
Variable vars : 
list (
ident * 
type).
    
Inductive wt_exp : 
exp -> 
Prop :=
    | 
wt_Econst: 
forall c,
        
wt_exp (
Econst c)
    | 
wt_Evar: 
forall x ty nck,
        
In (
x, 
ty) 
vars ->
        
wt_nclock vars nck ->
        
wt_exp (
Evar x (
ty, 
nck))
    | 
wt_Eunop: 
forall op e tye ty nck,
        
wt_exp e ->
        
typeof e = [
tye] ->
        
type_unop op tye = 
Some ty ->
        
wt_nclock vars nck ->
        
wt_exp (
Eunop op e (
ty, 
nck))
    | 
wt_Ebinop: 
forall op e1 e2 ty1 ty2 ty nck,
        
wt_exp e1 ->
        
wt_exp e2 ->
        
typeof e1 = [
ty1] ->
        
typeof e2 = [
ty2] ->
        
type_binop op ty1 ty2 = 
Some ty ->
        
wt_nclock vars nck ->
        
wt_exp (
Ebinop op e1 e2 (
ty, 
nck))
    | 
wt_Efby: 
forall e0s es anns,
        
Forall wt_exp e0s ->
        
Forall wt_exp es ->
        
typesof es = 
map fst anns ->
        
typesof e0s = 
map fst anns ->
        
Forall (
wt_nclock vars) (
map snd anns) ->
        
wt_exp (
Efby e0s es anns)
    | 
wt_Earrow: 
forall e0s es anns,
        
Forall wt_exp e0s ->
        
Forall wt_exp es ->
        
typesof es = 
map fst anns ->
        
typesof e0s = 
map fst anns ->
        
Forall (
wt_nclock vars) (
map snd anns) ->
        
wt_exp (
Earrow e0s es anns)
    | 
wt_Ewhen: 
forall es x b tys nck,
        
Forall wt_exp es ->
        
typesof es = 
tys ->
        
In (
x, 
bool_type) 
vars ->
        
wt_nclock vars nck ->
        
wt_exp (
Ewhen es x b (
tys, 
nck))
    | 
wt_Emerge: 
forall x ets efs tys nck,
        
Forall wt_exp ets ->
        
Forall wt_exp efs ->
        
In (
x, 
bool_type) 
vars ->
        
typesof ets = 
tys ->
        
typesof efs = 
tys ->
        
wt_nclock vars nck ->
        
wt_exp (
Emerge x ets efs (
tys, 
nck))
    | 
wt_Eifte: 
forall e ets efs tys nck,
        
wt_exp e ->
        
Forall wt_exp ets ->
        
Forall wt_exp efs ->
        
typeof e = [
bool_type] ->
        
typesof ets = 
tys ->
        
typesof efs = 
tys ->
        
wt_nclock vars nck ->
        
wt_exp (
Eite e ets efs (
tys, 
nck))
    | 
wt_Eapp: 
forall f es anns n,
        
Forall wt_exp es ->
        
find_node f G = 
Some n ->
        
Forall2 (
fun et '(
_, (
t, 
_)) => 
et = 
t) (
typesof es) 
n.(
n_in) ->
        
Forall2 (
fun a '(
_, (
t, 
_)) => 
fst a = 
t) 
anns n.(
n_out) ->
        
Forall (
fun a => 
wt_nclock (
vars++(
idty (
fresh_ins es++
anon_streams anns))) (
snd a)) 
anns ->
        
wt_exp (
Eapp f es None anns)
    | 
wt_EappReset: 
forall f es r anns n,
        
Forall wt_exp es ->
        
find_node f G = 
Some n ->
        
Forall2 (
fun et '(
_, (
t, 
_)) => 
et = 
t) (
typesof es) 
n.(
n_in) ->
        
Forall2 (
fun a '(
_, (
t, 
_)) => 
fst a = 
t) 
anns n.(
n_out) ->
        
Forall (
fun a => 
wt_nclock (
vars++(
idty (
fresh_ins es++
anon_streams anns))) (
snd a)) 
anns ->
        
wt_exp r ->
        
typeof r = [
bool_type] ->
        
wt_exp (
Eapp f es (
Some r) 
anns).
    
Section wt_exp_ind2.
      
Variable P : 
exp -> 
Prop.
      
Hypothesis EconstCase:
        
forall c : 
const,
          
P (
Econst c).
      
Hypothesis EvarCase:
        
forall x ty nck,
          
In (
x, 
ty) 
vars ->
          
wt_nclock vars nck ->
          
P (
Evar x (
ty, 
nck)).
      
Hypothesis EunopCase:
        
forall op e tye ty nck,
          
wt_exp e ->
          
P e ->
          
typeof e = [
tye] ->
          
type_unop op tye = 
Some ty ->
          
wt_nclock vars nck ->
          
P (
Eunop op e (
ty, 
nck)).
      
Hypothesis EbinopCase:
        
forall op e1 e2 ty1 ty2 ty nck,
          
wt_exp e1 ->
          
P e1 ->
          
wt_exp e2 ->
          
P e2 ->
          
typeof e1 = [
ty1] ->
          
typeof e2 = [
ty2] ->
          
type_binop op ty1 ty2 = 
Some ty ->
          
wt_nclock vars nck ->
          
P (
Ebinop op e1 e2 (
ty, 
nck)).
      
Hypothesis EfbyCase:
        
forall e0s es anns,
          
Forall wt_exp e0s ->
          
Forall wt_exp es ->
          
Forall P e0s ->
          
Forall P es ->
          
typesof es = 
map fst anns ->
          
typesof e0s = 
map fst anns ->
          
Forall (
wt_nclock vars) (
map snd anns) ->
          
P (
Efby e0s es anns).
      
Hypothesis EarrowCase:
        
forall e0s es anns,
          
Forall wt_exp e0s ->
          
Forall wt_exp es ->
          
Forall P e0s ->
          
Forall P es ->
          
typesof es = 
map fst anns ->
          
typesof e0s = 
map fst anns ->
          
Forall (
wt_nclock vars) (
map snd anns) ->
          
P (
Earrow e0s es anns).
      
Hypothesis EwhenCase:
        
forall es x b tys nck,
          
Forall wt_exp es ->
          
Forall P es ->
          
typesof es = 
tys ->
          
In (
x, 
bool_type) 
vars ->
          
wt_nclock vars nck ->
          
P (
Ewhen es x b (
tys, 
nck)).
      
Hypothesis EmergeCase:
        
forall x ets efs tys nck,
          
Forall wt_exp ets ->
          
Forall P ets ->
          
Forall wt_exp efs ->
          
Forall P efs ->
          
In (
x, 
bool_type) 
vars ->
          
typesof ets = 
tys ->
          
typesof efs = 
tys ->
          
wt_nclock vars nck ->
          
P (
Emerge x ets efs (
tys, 
nck)).
      
Hypothesis EiteCase:
        
forall e ets efs tys nck,
          
wt_exp e ->
          
P e ->
          
Forall wt_exp ets ->
          
Forall P ets ->
          
Forall wt_exp efs ->
          
Forall P efs ->
          
typeof e = [
bool_type] ->
          
typesof ets = 
tys ->
          
typesof efs = 
tys ->
          
wt_nclock vars nck ->
          
P (
Eite e ets efs (
tys, 
nck)).
      
Hypothesis EappCase:
        
forall f es anns n,
          
Forall wt_exp es ->
          
Forall P es ->
          
find_node f G = 
Some n ->
          
Forall2 (
fun et '(
_, (
t, 
_)) => 
et = 
t) (
typesof es) 
n.(
n_in) ->
          
Forall2 (
fun a '(
_, (
t, 
_)) => 
fst a = 
t) 
anns n.(
n_out) ->
          
Forall (
fun a => 
wt_nclock (
vars++(
idty (
fresh_ins es++
anon_streams anns))) (
snd a)) 
anns ->
          
P (
Eapp f es None anns).
      
Hypothesis EappResetCase:
        
forall f es r anns n,
          
Forall wt_exp es ->
          
Forall P es ->
          
find_node f G = 
Some n ->
          
Forall2 (
fun et '(
_, (
t, 
_)) => 
et = 
t) (
typesof es) 
n.(
n_in) ->
          
Forall2 (
fun a '(
_, (
t, 
_)) => 
fst a = 
t) 
anns n.(
n_out) ->
          
Forall (
fun a => 
wt_nclock (
vars++(
idty (
fresh_ins es++
anon_streams anns))) (
snd a)) 
anns ->
          
wt_exp r ->
          
P r ->
          
typeof r = [
bool_type] ->
          
P (
Eapp f es (
Some r) 
anns).
      
Fixpoint wt_exp_ind2 (
e: 
exp) (
H: 
wt_exp e) {
struct H} : 
P e.
Proof.
        destruct H; 
eauto.
        - 
apply EfbyCase; 
auto.
          + 
clear H2. 
induction H; 
auto.
          + 
clear H1. 
induction H0; 
auto.
        - 
apply EarrowCase; 
auto.
          + 
clear H2. 
induction H; 
auto.
          + 
clear H1. 
induction H0; 
auto.
        - 
apply EwhenCase; 
auto.
          
clear H0. 
induction H; 
auto.
        - 
apply EmergeCase; 
auto.
          
clear H2. 
induction H; 
auto.
          
clear H3. 
induction H0; 
auto.
        - 
apply EiteCase; 
auto.
          
clear H3. 
induction H0; 
auto.
          
clear H4. 
induction H1; 
auto.
        - 
eapply EappCase; 
eauto.
          
clear H1 H3. 
induction H; 
eauto.
        - 
eapply EappResetCase; 
eauto.
          
clear H1 H3. 
induction H; 
eauto.
      Qed.
 
    End wt_exp_ind2.
    
Definition wt_equation (
eq : 
equation) : 
Prop :=
      
let (
xs, 
es) := 
eq in
      Forall wt_exp es
      /\ 
Forall2 (
fun x ty=> 
In (
x, 
ty) 
vars) 
xs (
typesof es).
  
End WellTyped.
  
Definition wt_clocks (
vars: 
list (
ident * (
type * 
clock)))
                           : 
list (
ident * (
type * 
clock)) -> 
Prop :=
    
Forall (
fun '(
_, (
_, 
ck)) => 
wt_clock (
idty vars) 
ck).
  
Definition wt_node (
G: 
global) (
n: 
node) : 
Prop
    :=    
wt_clocks n.(
n_in) 
n.(
n_in)
       /\ 
wt_clocks (
n.(
n_in) ++ 
n.(
n_out)) 
n.(
n_out)
       /\ 
wt_clocks (
n.(
n_in) ++ 
n.(
n_out) ++ 
n.(
n_vars)) 
n.(
n_vars)
       /\ 
Forall (
wt_equation G (
idty (
n.(
n_in) ++ 
n.(
n_vars) ++ 
n.(
n_out)))) 
n.(
n_eqs).
  
Inductive wt_global : 
global -> 
Prop :=
  | 
wtg_nil:
      
wt_global []
  | 
wtg_cons: 
forall n ns,
      
wt_global ns ->
      
wt_node ns n ->
      
Forall (
fun n'=> 
n.(
n_name) <> 
n'.(
n_name) :> 
ident) 
ns ->
      
wt_global (
n::
ns).
  
Hint Constructors wt_clock wt_nclock wt_exp wt_global : 
ltyping.
  
Hint Unfold wt_equation : 
ltyping.
  
Lemma wt_global_NoDup:
    
forall g,
      
wt_global g ->
      
NoDup (
map n_name g).
Proof.
    induction g; 
eauto using NoDup.
    
intro WTg. 
simpl. 
constructor.
    2:
apply IHg; 
now inv WTg.
    
intro Hin.
    
inversion_clear WTg as [|? ? ? 
WTn Hn].
    
change (
Forall (
fun n' => (
fun i=> 
a.(
n_name) <> 
i) 
n'.(
n_name)) 
g)%
type in Hn.
    
apply Forall_map in Hn.
    
apply Forall_forall with (1:=
Hn) 
in Hin.
    
now contradiction Hin.
  Qed.
 
  Lemma wt_global_app:
    
forall G G',
      
wt_global (
G' ++ 
G) ->
      
wt_global G.
Proof.
    induction G'; auto.
    simpl. intro Hwt.
    inversion Hwt; auto.
  Qed.
  Lemma wt_find_node:
    
forall G f n,
      
wt_global G ->
      
find_node f G = 
Some n ->
      
exists G', 
wt_node G' 
n.
Proof.
    intros G f n' 
Hwt Hfind.
    
apply find_node_split in Hfind.
    
destruct Hfind as (
bG & 
aG & 
HG).
    
subst. 
apply wt_global_app in Hwt.
    
inversion Hwt. 
eauto.
  Qed.
 
  Lemma wt_clock_add:
    
forall x v env ck,
      ~
InMembers x env ->
      
wt_clock env ck ->
      
wt_clock ((
x, 
v) :: 
env) 
ck.
Proof.
    induction ck; auto with ltyping.
    inversion 2.
    auto with ltyping datatypes.
  Qed.
  Instance wt_clock_Proper:
    
Proper (@
Permutation.Permutation (
ident * 
type) ==> @
eq clock ==> 
iff)
           
wt_clock.
Proof.
    intros env' env Henv ck' ck Hck.
    rewrite Hck; clear Hck ck'.
    induction ck.
    - split; auto with ltyping.
    - destruct IHck.
      split; inversion_clear 1; constructor;
        try rewrite Henv in *;
        auto with ltyping.
  Qed.
  Instance wt_nclock_Proper:
    
Proper (@
Permutation.Permutation (
ident * 
type) ==> @
eq nclock ==> 
iff)
           
wt_nclock.
Proof.
    intros env' env Henv ck' ck Hck.
    rewrite Hck; clear Hck ck'.
    destruct ck;
      split; inversion 1;
        (rewrite Henv in * || rewrite <-Henv in * || idtac);
        auto with ltyping.
  Qed.
  Instance wt_nclock_pointwise_Proper:
    
Proper (@
Permutation.Permutation (
ident * 
type)
                          ==> 
pointwise_relation nclock iff) 
wt_nclock.
Proof.
    intros env' env Henv e.
    now rewrite Henv.
  Qed.
  Instance wt_exp_Proper:
    
Proper (@
eq global ==> @
Permutation.Permutation (
ident * 
type)
                ==> @
eq exp ==> 
iff)
           
wt_exp.
Proof.
    intros G G' 
HG env' 
env Henv e' 
e He.
    
rewrite HG, 
He. 
clear HG He.
    
split; 
intro H;
      
induction H using wt_exp_ind2;
      (
rewrite Henv in * || 
rewrite <-
Henv in * || 
idtac);
      
try match goal with
          | 
H:
Forall (
fun a => 
wt_nclock (
env' ++ 
_) (
snd a)) 
_ |- 
_ =>
            
setoid_rewrite Henv in H
          | 
H:
Forall (
fun a => 
wt_nclock (
env ++ 
_) (
snd a)) 
_ |- 
_ =>
            
setoid_rewrite <-
Henv in H
          end;
      
eauto with ltyping;
      
econstructor; 
eauto.
  Qed.
 
  Instance wt_exp_pointwise_Proper:
    
Proper (@
eq global ==> @
Permutation.Permutation (
ident * 
type)
                                     ==> 
pointwise_relation exp iff) 
wt_exp.
Proof.
    intros G G' HG env' env Henv e.
    now rewrite HG, Henv.
  Qed.
  Instance wt_equation_Proper:
    
Proper (@
eq global ==> @
Permutation.Permutation (
ident * 
type)
                ==> @
eq equation ==> 
iff)
           
wt_equation.
Proof.
Adding variables to the environment preserves typing 
  Section incl.
    
Fact wt_clock_incl : 
forall vars vars' 
cl,
      
incl vars vars' ->
      
wt_clock vars cl ->
      
wt_clock vars' 
cl.
Proof.
      intros vars vars' cl Hincl Hwt.
      induction Hwt.
      - constructor.
      - constructor; auto.
    Qed.
    Local Hint Resolve wt_clock_incl.
    
Fact wt_nclock_incl : 
forall vars vars' 
cl,
        
incl vars vars' ->
        
wt_nclock vars cl ->
        
wt_nclock vars' 
cl.
Proof.
      intros vars vars' cl Hincl Hwt.
      destruct Hwt; constructor; eauto.
    Qed.
    Local Hint Resolve wt_nclock_incl.
    
Lemma wt_exp_incl : 
forall G vars vars' 
e,
        
incl vars vars' ->
        
wt_exp G vars e ->
        
wt_exp G vars' 
e.
Proof.
      intros G vars vars' 
e Hincl Hwt.
      
induction Hwt using wt_exp_ind2;
        
econstructor; 
eauto.
      - 
        
eapply Forall_impl; [| 
eauto].
        
intros; 
eauto.
      - 
        
eapply Forall_impl; [| 
eauto].
        
intros; 
eauto.
      - 
        
eapply Forall_impl; [| 
eauto].
        
intros; 
simpl in *; 
eauto.
        
eapply wt_nclock_incl; 
eauto.
        
eapply incl_appl'; 
eauto.
      - 
        
eapply Forall_impl; [| 
eauto].
        
intros; 
simpl in *; 
eauto.
        
eapply wt_nclock_incl; 
eauto.
        
eapply incl_appl'; 
eauto.
    Qed.
 
    Lemma wt_equation_incl : 
forall G vars vars' 
eq,
        
incl vars vars' ->
        
wt_equation G vars eq ->
        
wt_equation G vars' 
eq.
Proof.
      intros G vars vars' 
eq Hincl Hwt.
      
destruct eq; 
simpl in *. 
destruct Hwt as [
Hwt1 Hwt2].
      
split.
      - 
eapply Forall_impl; [| 
eauto].
        
intros. 
eapply wt_exp_incl; 
eauto.
      - 
eapply Forall2_impl_In; [| 
eauto].
        
intros; 
simpl in H1. 
eauto.
    Qed.
 
  End incl.
The global can also be extended ! 
  Section global_incl.
    
Fact wt_exp_global_incl : 
forall G G' 
vars e,
      
incl G G' ->
      
NoDup (
map n_name G) ->
      
NoDup (
map n_name G') ->
      
wt_exp G vars e ->
      
wt_exp G' 
vars e.
Proof.
    Fact wt_equation_global_incl : 
forall G G' 
vars e,
      
incl G G' ->
      
NoDup (
map n_name G) ->
      
NoDup (
map n_name G') ->
      
wt_equation G vars e ->
      
wt_equation G' 
vars e.
Proof.
      intros G G' 
vars [
xs es] 
Hincl Hndup1 Hndup2 [
Hwt1 Hwt2].
      
constructor; 
auto.
      
eapply Forall_impl; [|
eauto]. 
intros; 
eauto using wt_exp_global_incl.
    Qed.
 
    Fact wt_node_global_incl : 
forall G G' 
e,
      
incl G G' ->
      
NoDup (
map n_name G) ->
      
NoDup (
map n_name G') ->
      
wt_node G e ->
      
wt_node G' 
e.
Proof.
Now that we know this, we can deduce a weaker version of wt_global using Forall: 
    Lemma wt_global_Forall : 
forall G,
        
wt_global G ->
        
Forall (
wt_node G) 
G.
Proof.
  End global_incl.
  
Local Hint Resolve wt_clock_incl incl_appl incl_refl.
  
Lemma wt_exp_clockof:
    
forall G env e,
      
wt_exp G env e ->
      
Forall (
wt_clock (
env++
idty (
fresh_in e))) (
clockof e).
Proof.
    intros * 
Hwt.
    
apply Forall_forall. 
intros ck Hin.
    
inv Hwt; 
simpl in *.
    - 
destruct Hin as [
Hin|]; [|
contradiction].
      
rewrite <-
Hin; 
auto with ltyping.
    - 
destruct Hin as [
Hin|]; [|
contradiction].
      
rewrite <-
Hin.
      
destruct nck; 
unfold clock_of_nclock; 
simpl in *;
        
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end.
      
rewrite app_nil_r; 
auto.
    - 
destruct Hin as [
Hin|]; [|
contradiction].
      
rewrite <-
Hin.
      
destruct nck; 
unfold clock_of_nclock; 
simpl in *;
        
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
destruct Hin as [
Hin|]; [|
contradiction].
      
rewrite <-
Hin.
      
destruct nck; 
unfold clock_of_nclock; 
simpl in *;
        
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
match goal with H:
Forall (
wt_nclock _) 
_ |- 
_ =>
                      
rewrite Forall_map in H end.
      
apply in_map_iff in Hin.
      
destruct Hin as ((
ty & 
nck) & 
Hck & 
Hin).
      
apply Forall_forall with (1:=
H3) 
in Hin.
      
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *; 
subst;
        
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
match goal with H:
Forall (
wt_nclock _) 
_ |- 
_ =>
                      
rewrite Forall_map in H end.
      
apply in_map_iff in Hin.
      
destruct Hin as ((
ty & 
nck) & 
Hck & 
Hin).
      
apply Forall_forall with (1:=
H3) 
in Hin.
      
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *; 
subst;
        
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *;
        
apply in_map_iff in Hin; 
destruct Hin as (? & 
Hs & 
Hin); 
subst;
          
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *;
        
apply in_map_iff in Hin; 
destruct Hin as (? & 
Hs & 
Hin); 
subst;
          
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *;
        
apply in_map_iff in Hin; 
destruct Hin as (? & 
Hs & 
Hin); 
subst;
          
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
apply in_map_iff in Hin.
      
destruct Hin as (
x & 
Hs & 
Hin).
      
match goal with H:
Forall _ anns |- 
_ =>
                      
apply Forall_forall with (1:=
H) 
in Hin end.
      
destruct x as (
ty, 
nck).
      
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *;
        
subst; 
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end; 
eauto.
    - 
apply in_map_iff in Hin.
      
destruct Hin as (
x & 
Hs & 
Hin).
      
match goal with H:
Forall _ anns |- 
_ =>
                      
apply Forall_forall with (1:=
H) 
in Hin end.
      
destruct x as (
ty, 
nck).
      
destruct nck; 
unfold clock_of_nclock in *; 
simpl in *;
        
subst; 
match goal with H:
wt_nclock _ _ |- 
_ => 
inv H end.
      
eapply wt_clock_incl; [| 
eauto].
      
eapply incl_appr'. 
unfold idty; 
repeat rewrite map_app.
      
eapply incl_appr'. 
eapply incl_appr. 
reflexivity.
  Qed.
 
 Validation 
  Module MyOpAux := 
OperatorsAux Op.
  
Fixpoint check_clock (
venv : 
Env.t type) (
ck : 
clock) : 
bool :=
    
match ck with
    | 
Cbase => 
true
    | 
Con ck' 
x b =>
      
match Env.find x venv with
      | 
None => 
false
      | 
Some xt => (
xt ==
b bool_type) && 
check_clock venv ck'
      
end
    end.
  
Definition check_nclock (
venv : 
Env.t type) (
nck : 
nclock) : 
bool :=
    
check_clock venv (
fst nck).
  
Lemma check_clock_correct:
    
forall venv ck,
      
check_clock venv ck = 
true ->
      
wt_clock (
Env.elements venv) 
ck.
Proof.
  Lemma check_nclock_correct:
    
forall venv nck,
      
check_nclock venv nck = 
true ->
      
wt_nclock (
Env.elements venv) 
nck.
Proof.
  Local Hint Resolve check_nclock_correct.
  
Section ValidateExpression.
    
Variable G : 
global.
    
Variable venv : 
Env.t type.
    
Open Scope option_monad_scope.
    
Definition check_paired_types2 (
t1 : 
type) (
tc : 
ann) : 
bool :=
      
let '(
t, 
c) := 
tc in
      (
t1 ==
b t) && (
check_nclock venv c).
    
Definition check_paired_types3 (
t1 t2 : 
type) (
tc : 
ann) : 
bool :=
      
let '(
t, 
c) := 
tc in
      (
t1 ==
b t) && (
t2 ==
b t) && (
check_nclock venv c).
    
Definition check_reset (
rt : 
option (
option (
list type))) : 
bool :=
      
match rt with
      | 
None => 
true
      | 
Some (
Some [
ty]) => 
ty ==
b bool_type
      | 
_ => 
false
      end.
    
Function check_var (
x : 
ident) (
ty : 
type) : 
bool :=
      
match Env.find x venv with
      | 
None => 
false
      | 
Some xt => 
ty ==
b xt
      end.
    
Fixpoint check_exp (
e : 
exp) : 
option (
list type) :=
      
match e with
      | 
Econst c => 
Some ([
type_const c])
      | 
Evar x (
xt, 
nck) =>
        
if check_var x xt && 
check_nclock venv nck then Some [
xt] 
else None
      | 
Eunop op e (
xt, 
nck) =>
        
do te <- 
assert_singleton (
check_exp e);
        
do t <- 
type_unop op te;
        
if (
xt ==
b t) && 
check_nclock venv nck then Some [
xt] 
else None
      | 
Ebinop op e1 e2 (
xt, 
nck) =>
        
do te1 <- 
assert_singleton (
check_exp e1);
        
do te2 <- 
assert_singleton (
check_exp e2);
        
do t <- 
type_binop op te1 te2;
        
if (
xt ==
b t) && 
check_nclock venv nck then Some [
xt] 
else None
      | 
Efby e0s es anns =>
        
do t0s <- 
oconcat (
map check_exp e0s);
        
do ts <- 
oconcat (
map check_exp es);
        
if forall3b check_paired_types3 t0s ts anns
        then Some (
map fst anns) 
else None
      | 
Earrow e0s es anns =>
        
do t0s <- 
oconcat (
map check_exp e0s);
        
do ts <- 
oconcat (
map check_exp es);
        
if forall3b check_paired_types3 t0s ts anns
        then Some (
map fst anns) 
else None
      | 
Ewhen es x b (
tys, 
nck) =>
        
do ts <- 
oconcat (
map check_exp es);
        
if check_var x bool_type && (
forall2b equiv_decb ts tys) && (
check_nclock venv nck)
        
then Some tys else None
      | 
Emerge x e1s e2s (
tys, 
nck) =>
        
do t1s <- 
oconcat (
map check_exp e1s);
        
do t2s <- 
oconcat (
map check_exp e2s);
        
if check_var x bool_type
             && (
forall3b equiv_decb3 t1s t2s tys)
             && (
check_nclock venv nck)
        
then Some tys else None
      | 
Eite e e1s e2s (
tys, 
nck) =>
        
do t1s <- 
oconcat (
map check_exp e1s);
        
do t2s <- 
oconcat (
map check_exp e2s);
        
do xt <- 
assert_singleton (
check_exp e);
        
if (
xt ==
b bool_type)
             && (
forall3b equiv_decb3 t1s t2s tys)
             && (
check_nclock venv nck)
        
then Some tys else None
      | 
Eapp f es ro anns =>
        
do n <- 
find_node f G;
        
do ts <- 
oconcat (
map check_exp es);
        
if (
forall2b (
fun et '(
_, (
t, 
_)) => 
et ==
b t) 
ts n.(
n_in))
             && (
forall2b (
fun '(
ot, 
oc) '(
_, (
t, 
_)) =>
                             
check_nclock (
Env.adds' (
idty (
fresh_ins es++
anon_streams anns)) 
venv) 
oc
                             && (
ot ==
b t)) 
anns n.(
n_out))
             && 
check_reset (
option_map check_exp ro)
        
then Some (
map fst anns)
        
else None
      end.
    
Definition check_rhs (
e : 
exp) : 
option (
list type) :=
      
match e with
      | 
Eapp f es ro anns =>
        
do n <- 
find_node f G;
        
do ts <- 
oconcat (
map check_exp es);
        
if (
forall2b (
fun et '(
_, (
t, 
_)) => 
et ==
b t) 
ts n.(
n_in))
             && (
forall2b (
fun '(
ot, 
oc) '(
_, (
t, 
_)) =>
                             
check_nclock (
Env.adds' (
idty (
fresh_ins es)) 
venv) 
oc
                             && (
ot ==
b t)) 
anns n.(
n_out))
             && 
check_reset (
option_map check_exp ro)
        
then Some (
map fst anns)
        
else None
      | 
e => 
check_exp e
      end.
    
Definition check_equation (
eq : 
equation) : 
bool :=
      
let '(
xs, 
es) := 
eq in
      match oconcat (
map check_rhs es) 
with
      | 
None => 
false
      | 
Some tys => 
forall2b check_var xs tys
      end.
    
Lemma check_var_correct:
      
forall x ty,
        
check_var x ty = 
true <-> 
In (
x, 
ty) (
Env.elements venv).
Proof.
    Local Hint Resolve check_var_correct.
    
Lemma check_paired_types2_correct:
      
forall tys1 anns,
        
forall2b check_paired_types2 tys1 anns = 
true ->
        
tys1 = 
map fst anns
        /\ 
Forall (
wt_nclock (
Env.elements venv)) (
map snd anns).
Proof.
    Lemma check_paired_types3_correct:
      
forall tys1 tys2 anns,
        
forall3b check_paired_types3 tys1 tys2 anns = 
true ->
        
tys1 = 
map fst anns
        /\ 
tys2 = 
map fst anns
        /\ 
Forall (
wt_nclock (
Env.elements venv)) (
map snd anns).
Proof.
    Lemma oconcat_map_check_exp':
      
forall {
f} 
es tys,
        (
forall e tys,
            
In e es ->
            
NoDupMembers (
Env.elements venv++
idty (
fresh_in e)) ->
            
f e = 
Some tys ->
            
wt_exp G (
Env.elements venv) 
e /\ 
typeof e = 
tys) ->
        
NoDupMembers (
Env.elements venv++
idty (
fresh_ins es)) ->
        
oconcat (
map f es) = 
Some tys ->
        
Forall (
wt_exp G (
Env.elements venv)) 
es
        /\ 
typesof es = 
tys.
Proof.
      induction es as [|
e es IH]; 
intros tys WTf ND CE. 
now inv CE; 
auto.
      
simpl in CE. 
destruct (
f e) 
eqn:
Ce; [|
now omonadInv CE].
      
destruct (
oconcat (
map f es)) 
as [
tes|]; [|
now omonadInv CE].
      
omonadInv CE. 
simpl.
      
apply WTf in Ce as (
Ce1 & ->); 
auto with datatypes.
      
destruct (
IH tes) 
as (? & ->); 
auto.
      
intros * 
Ies ND' 
Fe. 
apply WTf in Fe; 
auto with datatypes.
      + 
unfold fresh_ins, 
idty in *; 
simpl in *. 
rewrite map_app in *.
        
rewrite Permutation_swap in ND. 
apply NoDupMembers_app_r in ND; 
auto.
      + 
unfold fresh_ins, 
idty in *; 
simpl in *. 
rewrite map_app in *.
        
rewrite app_assoc in ND. 
apply NoDupMembers_app_l in ND; 
auto.
    Qed.
 
    Import Permutation.
    
Local Hint Constructors wt_exp.
    
Lemma check_exp_correct:
      
forall e tys,
        
NoDupMembers (
Env.elements venv++(
idty (
fresh_in e))) ->
        
check_exp e = 
Some tys ->
        
wt_exp G (
Env.elements venv) 
e
        /\ 
typeof e = 
tys.
Proof with
    Corollary oconcat_map_check_exp:
      
forall es tys,
        
NoDupMembers (
Env.elements venv++
idty (
fresh_ins es)) ->
        
oconcat (
map check_exp es) = 
Some tys ->
        
Forall (
wt_exp G (
Env.elements venv)) 
es
        /\ 
typesof es = 
tys.
Proof.
      intros.
      
eapply oconcat_map_check_exp'; 
eauto.
      
intros. 
eapply check_exp_correct; 
eauto.
    Qed.
 
    Lemma check_rhs_correct:
      
forall e tys,
        
NoDupMembers (
Env.elements venv++(
idty (
anon_in e))) ->
        
check_rhs e = 
Some tys ->
        
wt_exp G (
Env.elements venv) 
e
        /\ 
typeof e = 
tys.
Proof with
    Corollary oconcat_map_check_rhs:
      
forall es tys,
        
NoDupMembers (
Env.elements venv++
idty (
anon_ins es)) ->
        
oconcat (
map check_rhs es) = 
Some tys ->
        
Forall (
wt_exp G (
Env.elements venv)) 
es
        /\ 
typesof es = 
tys.
Proof.
    Lemma check_equation_correct:
      
forall eq,
        
NoDupMembers (
Env.elements venv++(
idty (
anon_in_eq eq))) ->
        
check_equation eq = 
true ->
        
wt_equation G (
Env.elements venv) 
eq.
Proof.
  End ValidateExpression.
  
Section ValidateGlobal.
    
Definition check_node (
G : 
global) (
n : 
node) :=
      
forallb (
check_clock (
Env.from_list (
idty (
n_in n)))) (
List.map (
fun '(
_, (
_, 
ck)) => 
ck) (
n_in n)) &&
      
forallb (
check_clock (
Env.from_list (
idty (
n_in n ++ 
n_out n)))) (
List.map (
fun '(
_, (
_, 
ck)) => 
ck) (
n_out n)) &&
      
forallb (
check_clock (
Env.from_list (
idty (
n_in n ++ 
n_out n ++ 
n_vars n)))) (
List.map (
fun '(
_, (
_, 
ck)) => 
ck) (
n_vars n)) &&
      
forallb (
check_equation G (
Env.from_list (
idty (
n_in n ++ 
n_vars n ++ 
n_out n)))) (
n_eqs n).
    
Definition check_global (
G : 
global) :=
      
check_nodup (
List.map n_name G) &&
      (
fix aux G := 
match G with
                    | [] => 
true
                    | 
hd::
tl => 
check_node tl hd && 
aux tl
                    end) 
G.
    
Lemma check_node_correct : 
forall G n,
        
check_node G n = 
true ->
        
wt_node G n.
Proof.
    Lemma check_global_correct : 
forall G,
        
check_global G = 
true ->
        
wt_global G.
Proof.
  End ValidateGlobal.
  
Section interface_eq.
    
Hint Constructors wt_exp.
    
Fact iface_eq_wt_exp : 
forall G G' 
vars e,
        
global_iface_eq G G' ->
        
wt_exp G vars e ->
        
wt_exp G' 
vars e.
Proof with
 eauto.
      
induction e using exp_ind2; 
intros Heq Hwt; 
inv Hwt...
      1-5:
econstructor...
      1-9:
rewrite Forall_forall in *...
     - 
        
assert (
Forall (
wt_exp G' 
vars) 
es) 
as Hwt by (
rewrite Forall_forall in *; 
eauto).
        
specialize (
Heq f).
        
remember (
find_node f G') 
as find.
        
destruct Heq.
        + 
congruence.
        + 
inv H6.
          
destruct H1 as [? [? [? ?]]].
          
apply wt_Eapp with (
n:=
sy)...
          * 
congruence.
          * 
congruence.
      - 
        
assert (
Forall (
wt_exp G' 
vars) 
es) 
as Hwt by (
rewrite Forall_forall in *; 
eauto).
        
assert (
wt_exp G' 
vars r) 
as Hwt' 
by (
rewrite Forall_forall in *; 
eauto).
        
specialize (
Heq f).
        
remember (
find_node f G') 
as find.
        
destruct Heq.
        + 
congruence.
        + 
inv H6.
          
destruct H1 as [? [? [? ?]]].
          
apply wt_EappReset with (
n:=
sy)...
          * 
congruence.
          * 
congruence.
    Qed.
 
    Fact iface_eq_wt_equation : 
forall G G' 
vars equ,
        
global_iface_eq G G' ->
        
wt_equation G vars equ ->
        
wt_equation G' 
vars equ.
Proof.
      intros G G' 
vars [
xs es] 
Heq Hwt.
      
simpl in *. 
destruct Hwt.
      
split.
      + 
rewrite Forall_forall in *. 
intros x Hin.
        
eapply iface_eq_wt_exp; 
eauto.
      + 
assumption.
    Qed.
 
    Lemma iface_eq_wt_node : 
forall G G' 
n,
        
global_iface_eq G G' ->
        
wt_node G n ->
        
wt_node G' 
n.
Proof.
  End interface_eq.
 wt implies wl 
  Hint Constructors wl_exp.
  
Fact wt_exp_wl_exp : 
forall G vars e,
      
wt_exp G vars e ->
      
wl_exp G e.
Proof with
 eauto.
    
induction e using exp_ind2; 
intro Hwt; 
inv Hwt; 
auto.
    - 
      
constructor...
      
rewrite <- 
length_typeof_numstreams. 
rewrite H3. 
reflexivity.
    - 
      
constructor...
      + 
rewrite <- 
length_typeof_numstreams. 
rewrite H5. 
reflexivity.
      + 
rewrite <- 
length_typeof_numstreams. 
rewrite H6. 
reflexivity.
    - 
      
constructor...
      + 
rewrite Forall_forall in *...
      + 
rewrite Forall_forall in *...
      + 
rewrite typesof_annots in *.
        
erewrite <- 
map_length, 
H7, 
map_length...
      + 
rewrite typesof_annots in *.
        
erewrite <- 
map_length, 
H6, 
map_length...
    - 
      
constructor...
      + 
rewrite Forall_forall in *...
      + 
rewrite Forall_forall in *...
      + 
rewrite typesof_annots in *.
        
erewrite <- 
map_length, 
H7, 
map_length...
      + 
rewrite typesof_annots in *.
        
erewrite <- 
map_length, 
H6, 
map_length...
    - 
      
constructor...
      + 
rewrite Forall_forall in *...
      + 
rewrite typesof_annots. 
rewrite map_length...
    - 
      
constructor...
      + 
rewrite Forall_forall in *...
      + 
rewrite Forall_forall in *...
      + 
rewrite typesof_annots. 
rewrite map_length...
      + 
rewrite <- 
H9, 
typesof_annots, 
map_length...
    - 
      
constructor...
      + 
rewrite Forall_forall in *...
      + 
rewrite Forall_forall in *...
      + 
rewrite <- 
length_typeof_numstreams, 
H8...
      + 
rewrite typesof_annots, 
map_length...
      + 
rewrite <- 
H10, 
typesof_annots, 
map_length...
    - 
      
econstructor...
      + 
rewrite Forall_forall in *...
      + 
apply Forall2_length in H7. 
rewrite typesof_annots, 
map_length in H7...
      + 
apply Forall2_length in H8...
    - 
      
econstructor...
      + 
rewrite Forall_forall in *...
      + 
rewrite <- 
length_typeof_numstreams, 
H11...
      + 
apply Forall2_length in H7. 
rewrite typesof_annots, 
map_length in H7...
      + 
apply Forall2_length in H8...
  Qed.
 
  Hint Resolve wt_exp_wl_exp.
  
Corollary Forall_wt_exp_wl_exp : 
forall G vars es,
      
Forall (
wt_exp G vars) 
es ->
      
Forall (
wl_exp G) 
es.
Proof.
  Hint Resolve Forall_wt_exp_wl_exp.
  
Fact wt_equation_wl_equation : 
forall G vars equ,
      
wt_equation G vars equ ->
      
wl_equation G equ.
Proof with
  Hint Resolve wt_equation_wl_equation.
  
Fact wt_node_wl_node : 
forall G n,
      
wt_node G n ->
      
wl_node G n.
Proof with
  Hint Resolve wt_node_wl_node.
  
Fact wt_global_wl_global : 
forall G,
      
wt_global G ->
      
wl_global G.
Proof with
 eauto.
    intros G Hwt.
    induction Hwt; constructor...
  Qed.
  Hint Resolve wt_global_wl_global.
Other useful stuff 
  Lemma wt_clock_Is_free_in : 
forall x env ck,
      
wt_clock env ck ->
      
Is_free_in_clock x ck ->
      
InMembers x env.
Proof.
    induction ck; 
intros Hwt Hfree;
      
inv Hwt; 
inv Hfree; 
eauto using In_InMembers.
  Qed.
 
  Corollary wt_nclock_Is_free_in : 
forall x env name ck,
      
wt_nclock env (
ck, 
name) ->
      
Is_free_in_clock x ck ->
      
InMembers x env.
Proof.
End LTYPING.
Module LTypingFun
       (
Ids  : 
IDS)
       (
Op   : 
OPERATORS)
       (
Syn  : 
LSYNTAX Ids Op)
       <: 
LTYPING Ids Op Syn.
  
Include LTYPING Ids Op Syn.
End LTypingFun.