Inductive term : Type :=
| Const : nat -> term
| Id : var -> term
| App : term -> term -> term
| Abs : term -> term.Inductive term : Type :=
| Const : nat -> term
| Id : var -> term
| App : term -> term -> term
| Abs : term -> term.Inductive term : Type :=
| Const : nat -> term
| Id : var -> term
| App : term -> term -> term
| Abs : term -> term.Inductive term : Type :=
| Const : nat -> term
| Id : var -> term
| App : term -> term -> term
| Abs : term -> term.Inductive term : Type :=
| Const : nat -> term
| Id : var -> term
| App : term -> term -> term
| Abs : term -> term.(* Terms that do not have applications *)
Inductive app_free : term -> Prop :=
| ConsNoApp : forall n, app_free (Const n)
| IdNoApp : forall x, app_free (Id x)
| AbsNoApp : forall (t : term),
               app_free t -> app_free (Abs t).(* Terms that do not have applications *)
Inductive app_free : term -> Prop :=
| ConsNoApp : forall n, app_free (Const n)
| IdNoApp : forall x, app_free (Id x)
| AbsNoApp : forall (t : term),
               app_free t -> app_free (Abs t).(* Terms that do not have applications *)
Inductive app_free : term -> Prop :=
| ConsNoApp : forall n, app_free (Const n)
| IdNoApp : forall x, app_free (Id x)
| AbsNoApp : forall (t : term),
               app_free t -> app_free (Abs t).(* Terms that do not have applications *)
Inductive app_free : term -> Prop :=
| ConsNoApp : forall n, app_free (Const n)
| IdNoApp : forall x, app_free (Id x)
| AbsNoApp : forall (t : term),
               app_free t -> app_free (Abs t).(* Number of applications in a term *)
Fixpoint app_no (t : term) : nat :=
  match t with
    | Const _ | Id _ => 0
    | Abs t => app_no t
    | App t1 t2 => 1 + (app_no t1 + app_no t2)
  end.Definition env := list type.Inductive bind : env -> nat -> type -> Prop :=
| BindNow   : forall tau env, bind (tau :: env) 0 tau
| BindLater : forall tau tau' x env,
    bind env x tau -> bind (tau' :: env) (S x) tau.Inductive bind : env -> nat -> type -> Prop :=
| BindNow   : forall tau env, bind (tau :: env) 0 tau
| BindLater : forall tau tau' x env,
    bind env x tau -> bind (tau' :: env) (S x) tau.Inductive bind : env -> nat -> type -> Prop :=
| BindNow   : forall tau env, bind (tau :: env) 0 tau
| BindLater : forall tau tau' x env,
    bind env x tau -> bind (tau' :: env) (S x) tau.Inductive typing (e : env) : term -> type -> Prop :=
| TId :
    forall x tau,
      nth_error e x = Some tau ->
      typing e (Id x) tau
| TConst :
    forall n,
      typing e (Const n) N
| TAbs :
    forall t tau1 tau2,
      typing (tau1 :: e) t tau2 ->
      typing e (Abs t) (Arrow tau1 tau2)
| TApp :
    forall t1 t2 tau1 tau2,
      typing e t1 (Arrow tau1 tau2) ->
      typing e t2 tau1 ->
      typing e (App t1 t2) tau2.Inductive typing (e : env) : term -> type -> Prop :=
| TId :
    forall x tau,
      nth_error e x = Some tau ->
      typing e (Id x) tau
| TConst :
    forall n,
      typing e (Const n) N
| TAbs :
    forall t tau1 tau2,
      typing (tau1 :: e) t tau2 ->
      typing e (Abs t) (Arrow tau1 tau2)
| TApp :
    forall t1 t2 tau1 tau2,
      typing e t1 (Arrow tau1 tau2) ->
      typing e t2 tau1 ->
      typing e (App t1 t2) tau2.Inductive typing (e : env) : term -> type -> Prop :=
| TId :
    forall x tau,
      nth_error e x = Some tau ->
      typing e (Id x) tau
| TConst :
    forall n,
      typing e (Const n) N
| TAbs :
    forall t tau1 tau2,
      typing (tau1 :: e) t tau2 ->
      typing e (Abs t) (Arrow tau1 tau2)
| TApp :
    forall t1 t2 tau1 tau2,
      typing e t1 (Arrow tau1 tau2) ->
      typing e t2 tau1 ->
      typing e (App t1 t2) tau2.Inductive typing (e : env) : term -> type -> Prop :=
| TId :
    forall x tau,
      nth_error e x = Some tau ->
      typing e (Id x) tau
| TConst :
    forall n,
      typing e (Const n) N
| TAbs :
    forall t tau1 tau2,
      typing (tau1 :: e) t tau2 ->
      typing e (Abs t) (Arrow tau1 tau2)
| TApp :
    forall t1 t2 tau1 tau2,
      typing e t1 (Arrow tau1 tau2) ->
      typing e t2 tau1 ->
      typing e (App t1 t2) tau2.Inductive typing (e : env) : term -> type -> Prop :=
| TId :
    forall x tau,
      nth_error e x = Some tau ->
      typing e (Id x) tau
| TConst :
    forall n,
      typing e (Const n) N
| TAbs :
    forall t tau1 tau2,
      typing (tau1 :: e) t tau2 ->
      typing e (Abs t) (Arrow tau1 tau2)
| TApp :
    forall t1 t2 tau1 tau2,
      typing e t1 (Arrow tau1 tau2) ->
      typing e t2 tau1 ->
      typing e (App t1 t2) tau2.Inductive typing' (e : env) : term -> type -> Prop :=
| TId' :
    forall x tau,
      bind e x tau ->
      typing' e (Id x) tau
| TConst' :
    forall n,
      typing' e (Const n) N
| TAbs' :
    forall t tau1 tau2,
      typing' (tau1 :: e) t tau2 ->
      typing' e (Abs t) (Arrow tau1 tau2)
| TApp' :
    forall t1 t2 tau1 tau2,
      typing' e t1 (Arrow tau1 tau2) ->
      typing' e t2 tau1 ->
      typing' e (App t1 t2) tau2.Inductive typing' (e : env) : term -> type -> Prop :=
| TId' :
    forall x tau,
      bind e x tau ->
      typing' e (Id x) tau
| TConst' :
    forall n,
      typing' e (Const n) N
| TAbs' :
    forall t tau1 tau2,
      typing' (tau1 :: e) t tau2 ->
      typing' e (Abs t) (Arrow tau1 tau2)
| TApp' :
    forall t1 t2 tau1 tau2,
      typing' e t1 (Arrow tau1 tau2) ->
      typing' e t2 tau1 ->
      typing' e (App t1 t2) tau2.Inductive typing' (e : env) : term -> type -> Prop :=
| TId' :
    forall x tau,
      bind e x tau ->
      typing' e (Id x) tau
| TConst' :
    forall n,
      typing' e (Const n) N
| TAbs' :
    forall t tau1 tau2,
      typing' (tau1 :: e) t tau2 ->
      typing' e (Abs t) (Arrow tau1 tau2)
| TApp' :
    forall t1 t2 tau1 tau2,
      typing' e t1 (Arrow tau1 tau2) ->
      typing' e t2 tau1 ->
      typing' e (App t1 t2) tau2.Inductive typing' (e : env) : term -> type -> Prop :=
| TId' :
    forall x tau,
      bind e x tau ->
      typing' e (Id x) tau
| TConst' :
    forall n,
      typing' e (Const n) N
| TAbs' :
    forall t tau1 tau2,
      typing' (tau1 :: e) t tau2 ->
      typing' e (Abs t) (Arrow tau1 tau2)
| TApp' :
    forall t1 t2 tau1 tau2,
      typing' e t1 (Arrow tau1 tau2) ->
      typing' e t2 tau1 ->
      typing' e (App t1 t2) tau2.Inductive typing' (e : env) : term -> type -> Prop :=
| TId' :
    forall x tau,
      bind e x tau ->
      typing' e (Id x) tau
| TConst' :
    forall n,
      typing' e (Const n) N
| TAbs' :
    forall t tau1 tau2,
      typing' (tau1 :: e) t tau2 ->
      typing' e (Abs t) (Arrow tau1 tau2)
| TApp' :
    forall t1 t2 tau1 tau2,
      typing' e t1 (Arrow tau1 tau2) ->
      typing' e t2 tau1 ->
      typing' e (App t1 t2) tau2.Instance dec_type (t1 t2 : type) : Dec (t1 = t2).Inductive option_le : option nat -> option nat -> Prop :=
    | opt_le_1 : option_le None None
    | opt_le_2 : forall n, option_le None (Some n)
    | opt_le_3 : forall n m : nat,
                   n <= m -> option_le (Some n) (Some m).Inductive option_le : option nat -> option nat -> Prop :=
    | opt_le_1 : option_le None None
    | opt_le_2 : forall n, option_le None (Some n)
    | opt_le_3 : forall n m : nat,
                   n <= m -> option_le (Some n) (Some m).Inductive option_le : option nat -> option nat -> Prop :=
    | opt_le_1 : option_le None None
    | opt_le_2 : forall n, option_le None (Some n)
    | opt_le_3 : forall n m : nat,
                   n <= m -> option_le (Some n) (Some m).Inductive option_le : option nat -> option nat -> Prop :=
    | opt_le_1 : option_le None None
    | opt_le_2 : forall n, option_le None (Some n)
    | opt_le_3 : forall n m : nat,
                   n <= m -> option_le (Some n) (Some m).(* The following keeps track of the size of largest type that appears in a cut
   in the derivation tree. Needed for verification purposes *)
Inductive typing_max_tau (e : env) : term -> type -> nat -> Prop :=
| TIdMax :
    forall x tau,
      nth_error e x = Some tau ->
      typing_max_tau e (Id x) tau 0
| TConstMax :
    forall n,
      typing_max_tau e (Const n) N 0
| TAbsMax :
    forall t tau1 tau2 m,
      typing_max_tau (tau1 :: e) t tau2 m ->
      typing_max_tau e (Abs t) (Arrow tau1 tau2) m
| TAppMax :
    forall t1 t2 tau1 tau2 m1 m2,
      typing_max_tau e t1 (Arrow tau1 tau2) m1 ->
      typing_max_tau e t2 tau1 m2 ->
      typing_max_tau e (App t1 t2) tau2 (max (type_size tau1) (max m1 m2)).(* The following keeps track of the size of largest type that appears in a cut
   in the derivation tree. Needed for verification purposes *)
Inductive typing_max_tau (e : env) : term -> type -> nat -> Prop :=
| TIdMax :
    forall x tau,
      nth_error e x = Some tau ->
      typing_max_tau e (Id x) tau 0
| TConstMax :
    forall n,
      typing_max_tau e (Const n) N 0
| TAbsMax :
    forall t tau1 tau2 m,
      typing_max_tau (tau1 :: e) t tau2 m ->
      typing_max_tau e (Abs t) (Arrow tau1 tau2) m
| TAppMax :
    forall t1 t2 tau1 tau2 m1 m2,
      typing_max_tau e t1 (Arrow tau1 tau2) m1 ->
      typing_max_tau e t2 tau1 m2 ->
      typing_max_tau e (App t1 t2) tau2 (max (type_size tau1) (max m1 m2)).(* The following keeps track of the size of largest type that appears in a cut
   in the derivation tree. Needed for verification purposes *)
Inductive typing_max_tau (e : env) : term -> type -> nat -> Prop :=
| TIdMax :
    forall x tau,
      nth_error e x = Some tau ->
      typing_max_tau e (Id x) tau 0
| TConstMax :
    forall n,
      typing_max_tau e (Const n) N 0
| TAbsMax :
    forall t tau1 tau2 m,
      typing_max_tau (tau1 :: e) t tau2 m ->
      typing_max_tau e (Abs t) (Arrow tau1 tau2) m
| TAppMax :
    forall t1 t2 tau1 tau2 m1 m2,
      typing_max_tau e t1 (Arrow tau1 tau2) m1 ->
      typing_max_tau e t2 tau1 m2 ->
      typing_max_tau e (App t1 t2) tau2 (max (type_size tau1) (max m1 m2)).(* The following keeps track of the size of largest type that appears in a cut
   in the derivation tree. Needed for verification purposes *)
Inductive typing_max_tau (e : env) : term -> type -> nat -> Prop :=
| TIdMax :
    forall x tau,
      nth_error e x = Some tau ->
      typing_max_tau e (Id x) tau 0
| TConstMax :
    forall n,
      typing_max_tau e (Const n) N 0
| TAbsMax :
    forall t tau1 tau2 m,
      typing_max_tau (tau1 :: e) t tau2 m ->
      typing_max_tau e (Abs t) (Arrow tau1 tau2) m
| TAppMax :
    forall t1 t2 tau1 tau2 m1 m2,
      typing_max_tau e t1 (Arrow tau1 tau2) m1 ->
      typing_max_tau e t2 tau1 m2 ->
      typing_max_tau e (App t1 t2) tau2 (max (type_size tau1) (max m1 m2)).(* The following keeps track of the size of largest type that appears in a cut
   in the derivation tree. Needed for verification purposes *)
Inductive typing_max_tau (e : env) : term -> type -> nat -> Prop :=
| TIdMax :
    forall x tau,
      nth_error e x = Some tau ->
      typing_max_tau e (Id x) tau 0
| TConstMax :
    forall n,
      typing_max_tau e (Const n) N 0
| TAbsMax :
    forall t tau1 tau2 m,
      typing_max_tau (tau1 :: e) t tau2 m ->
      typing_max_tau e (Abs t) (Arrow tau1 tau2) m
| TAppMax :
    forall t1 t2 tau1 tau2 m1 m2,
      typing_max_tau e t1 (Arrow tau1 tau2) m1 ->
      typing_max_tau e t2 tau1 m2 ->
      typing_max_tau e (App t1 t2) tau2 (max (type_size tau1) (max m1 m2)).

Lemma typing_max_tau_correct : forall e t tau, (exists m, typing_max_tau e t tau m) <-> typing e t tau.