(* Autor(s): Andrej Dudenhefner (1) Yannick Forster (1) Affiliation(s): (1) Saarland University, Saarbrücken, Germany *)
From Undecidability.SystemF.Util Require Import Facts poly_type_facts term_facts.
Arguments funcomp {X Y Z} _ _ / _.
(* Church-style System F Type Assignment Predicate *)
Inductive typing : environment -> term -> poly_type -> Prop :=
| typing_var {Gamma x t} :
nth_error Gamma x = Some t -> typing Gamma (var x) t
| typing_app {Gamma P Q s t} :
typing Gamma P (poly_arr s t) -> typing Gamma Q s -> typing Gamma (app P Q) t
| typing_abs {Gamma P s t} :
typing (s :: Gamma) P t -> typing Gamma (abs s P) (poly_arr s t)
| typing_ty_app {Gamma P s t} :
typing Gamma P (poly_abs s) -> typing Gamma (ty_app P t) (subst_poly_type (scons t poly_var) s)
| typing_ty_abs {Gamma P s} :
typing (map (ren_poly_type S) Gamma) P s -> typing Gamma (ty_abs P) (poly_abs s).
Fact typing_many_argument_subterm {Gamma P As t} : typing Gamma (many_argument_app P As) t ->
exists t', typing Gamma P t'.

(* generation lemma for non-eta long s -> t derivations *)
Lemma typing_normal_form_poly_arrE {Gamma P s t}: normal_form P -> typing Gamma P (poly_arr s t) ->
exists Q, normal_form Q /\ term_size Q <= term_size P + 2 /\ typing (s :: Gamma) Q t.