diff --git a/_CoqProject b/_CoqProject
index e410b9bf41d57605a5eb7b95194e91440a6970c4..1136854b641f59ee534bf3d5eb965000cc80246c 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -14,3 +14,4 @@ lifetime.v
 type.v
 type_incl.v
 perm.v
+perm_incl.v
diff --git a/perm.v b/perm.v
index c6c254bcef6628b85819c38f6ee7357a310bf79c..9f948d3a1b02739287a773cbe0fa46686f76e3ab 100644
--- a/perm.v
+++ b/perm.v
@@ -1,4 +1,5 @@
 From iris.program_logic Require Import thread_local.
+From iris.proofmode Require Import invariants.
 From lrust Require Export type.
 
 Delimit Scope perm_scope with P.
@@ -8,9 +9,10 @@ Module Perm.
 
 Section perm.
 
-  Context `{lifetimeG Σ}.
+  Context `{heapG Σ, lifetimeG Σ, thread_localG Σ}.
 
-  (* TODO : define valuable expressions ν in order to define ν ◁ τ. *)
+  Definition has_type (v : val) (ty : type) : perm :=
+    λ tid, ty.(ty_own) tid [v].
 
   Definition extract (κ : lifetime) (ρ : perm) : perm :=
     λ tid, (κ ∋ ρ tid)%I.
@@ -27,7 +29,7 @@ Section perm.
   Definition sep (ρ1 ρ2 : perm) : @perm Σ :=
     λ tid, (ρ1 tid ★ ρ2 tid)%I.
 
-  Definition top : @perm Σ :=
+  Global Instance top : Top (@perm Σ) :=
     λ _, True%I.
 
 End perm.
@@ -36,6 +38,9 @@ End Perm.
 
 Import Perm.
 
+Notation "v ◁ ty" := (has_type v ty)
+  (at level 75, right associativity) : perm_scope.
+
 Notation "κ ∋ ρ" := (extract κ ρ)
   (at level 75, right associativity) : perm_scope.
 
@@ -47,8 +52,3 @@ Notation "∃ x .. y , P" :=
   (exist (λ x, .. (exist (λ y, P)) ..)) : perm_scope.
 
 Infix "★" := sep (at level 80, right associativity) : perm_scope.
-
-Notation "⊤" := top : perm_scope.
-
-Definition perm_incl {Σ} (ρ1 ρ2 : @perm Σ) :=
-  ∀ tid, ρ1 tid ⊢ ρ2 tid.
\ No newline at end of file
diff --git a/perm_incl.v b/perm_incl.v
new file mode 100644
index 0000000000000000000000000000000000000000..086bd19823482baa749760cce25ea6b03b99dd5c
--- /dev/null
+++ b/perm_incl.v
@@ -0,0 +1,91 @@
+From iris.algebra Require Import upred_big_op.
+From iris.program_logic Require Import thread_local.
+From lrust Require Export type perm.
+
+Section perm_incl.
+
+  Context `{heapG Σ, lifetimeG Σ, thread_localG Σ}.
+
+  Definition perm_incl (ρ1 ρ2 : perm) :=
+    ∀ tid, ρ1 tid ={⊤}=> ρ2 tid.
+
+  Lemma perm_incl_top ρ : perm_incl ρ ⊤.
+  Proof. iIntros (tid) "H". eauto. Qed.
+
+  Global Instance perm_incl_refl : Reflexive perm_incl.
+  Proof. iIntros (? tid) "H". eauto. Qed.
+
+  Global Instance perm_incl_trans : Transitive perm_incl.
+  Proof.
+    iIntros (??? H12 H23 tid) "H". iVs (H12 with "H") as "H". by iApply H23.
+  Qed.
+
+  Lemma perm_incl_frame_l ρ ρ1 ρ2 :
+    perm_incl ρ1 ρ2 → perm_incl (ρ ★ ρ1) (ρ ★ ρ2).
+  Proof. iIntros (Hρ tid) "[$?]". by iApply Hρ. Qed.
+
+  Lemma perm_incl_frame_r ρ ρ1 ρ2 :
+    perm_incl ρ1 ρ2 → perm_incl (ρ1 ★ ρ) (ρ2 ★ ρ).
+  Proof. iIntros (Hρ tid) "[?$]". by iApply Hρ. Qed.
+
+End perm_incl.
+
+Section duplicable.
+
+  Context `{heapG Σ, lifetimeG Σ, thread_localG Σ}.
+
+  Class Duplicable (ρ : perm) :=
+    perm_incl_duplicable : perm_incl ρ (ρ ★ ρ).
+
+  Lemma has_type_dup v ty : ty.(ty_dup) → Duplicable (v ◁ ty).
+  Proof. iIntros (Hdup tid) "H!==>". by iApply ty_dup_dup. Qed.
+
+  Global Instance lft_incl_dup κ κ' : Duplicable (κ ⊑ κ').
+  Proof. iIntros (tid) "#H!==>". by iSplit. Qed.
+
+  Global Instance sep_dup P Q :
+    Duplicable P → Duplicable Q → Duplicable (P ★ Q).
+  Proof.
+    iIntros (HP HQ tid) "[HP HQ]".
+    iVs (HP with "HP") as "[$$]". by iApply HQ.
+  Qed.
+
+  Global Instance top_dup : Duplicable ⊤.
+  Proof. iIntros (tid) "_!==>". by iSplit. Qed.
+
+End duplicable.
+
+Hint Extern 0 (Duplicable (_ ◁ _)) => apply has_type_dup; exact I.
+
+Section perm_equiv.
+
+  Context `{heapG Σ, lifetimeG Σ, thread_localG Σ}.
+
+  Definition perm_equiv ρ1 ρ2 := perm_incl ρ1 ρ2 ∧ perm_incl ρ2 ρ1.
+
+  Global Instance perm_equiv_refl : Reflexive perm_equiv.
+  Proof. by split. Qed.
+
+  Global Instance perm_equiv_trans : Transitive perm_equiv.
+  Proof. intros x y z [] []. split; by transitivity y. Qed.
+
+  Global Instance perm_equiv_sym : Symmetric perm_equiv.
+  Proof. by intros x y []; split. Qed.
+
+  Global Instance perm_incl_proper :
+    Proper (perm_equiv ==> perm_equiv ==> iff) perm_incl.
+  Proof. intros ??[??]??[??]; split; eauto using perm_incl_trans. Qed.
+
+  Global Instance sep_assoc : Assoc perm_equiv Perm.sep.
+  Proof. intros ???; split. by iIntros (tid) "[$[$$]]". by iIntros (tid) "[[$$]$]". Qed.
+
+  Global Instance sep_comm : Comm perm_equiv Perm.sep.
+  Proof. intros ??; split; by iIntros (tid) "[$$]". Qed.
+
+  Global Instance top_right_id : RightId perm_equiv ⊤ Perm.sep.
+  Proof. intros ρ; split. by iIntros (tid) "[? _]". by iIntros (tid) "$". Qed.
+
+  Global Instance top_left_id : LeftId perm_equiv ⊤ Perm.sep.
+  Proof. intros ρ. by rewrite comm right_id. Qed.
+
+End perm_equiv.
\ No newline at end of file
diff --git a/type.v b/type.v
index c82c9431da7194c15d13fce406092da7a674c922..1440f1231636a812647787c43c1b0c2c28f1bb6b 100644
--- a/type.v
+++ b/type.v
@@ -419,7 +419,7 @@ Section types.
     size_eq : Forall ((= n) ∘ ty_size) tyl.
   Instance LstTySize_nil n : LstTySize n nil := List.Forall_nil _.
   Hint Extern 1 (LstTySize _ (_ :: _)) =>
-    apply List.Forall_cons; [reflexivity|].
+    apply List.Forall_cons; [reflexivity|] : typeclass_instances.
 
   Lemma sum_size_eq n tid i tyl vl {Hn : LstTySize n tyl} :
     ty_own (nth i tyl bot) tid vl ⊢ length vl = n.
@@ -490,32 +490,35 @@ Section types.
       iApply ("Hclose'" with "Hownq").
   Qed.
 
-  Program Definition undef (n : nat) :=
+  Program Definition uninit (n : nat) :=
     ty_of_st {| st_size := n; st_own tid vl := (length vl = n)%I |}.
   Next Obligation. done. Qed.
 
-  Program Definition cont {n : nat} (perm : vec val n → perm (Σ := Σ)):=
+  (* TODO : For now, functions and closures are not Sync nor
+     Send. This means they cannot be called in another thread than the
+     one that created it.
+     We will need Send and Sync closures when dealing with
+     multithreading (spawn needs a Send closure). *)
+  Program Definition cont {n : nat} (ρ : vec val n → @perm Σ) :=
     {| ty_size := 1; ty_dup := false;
-       ty_own tid vl := (∃ f xl e Hcl, vl = [@RecV f xl e Hcl] ★
-          ∀ vl tid, perm vl tid -★ tl_own tid ⊤
-                    -★ WP e (map of_val (vec_to_list vl)) {{λ _, False}})%I;
+       ty_own tid vl := (∃ f, vl = [f] ★
+          ∀ vl, ▷ ρ vl tid -★ tl_own tid ⊤
+                 -★ WP f (map of_val vl) {{λ _, False}})%I;
        ty_shr κ tid N l := True%I |}.
   Next Obligation.
-    iIntros (n perm tid vl) "H". iDestruct "H" as (f xl e Hcl) "[% _]". by subst.
+    iIntros (n ρ tid vl) "H". iDestruct "H" as (f) "[% _]". by subst.
   Qed.
   Next Obligation. done. Qed.
   Next Obligation. intros. by iIntros "_ $". Qed.
   Next Obligation. intros. by iIntros "_ _". Qed.
   Next Obligation. done. Qed.
 
-  Program Definition fn {n : nat} (perm : vec val n → perm (Σ := Σ)):=
+  Program Definition fn {n : nat} (ρ : vec val n → @perm Σ):=
     ty_of_st {| st_size := 1;
-       st_own tid vl := (∃ f xl e Hcl, vl = [@RecV f xl e Hcl] ★
-          ∀ vl tid, {{ perm vl tid ★ tl_own tid ⊤ }}
-                      e (map of_val (vec_to_list vl))
-                    {{λ _, False}})%I |}.
+       st_own tid vl := (∃ f, vl = [f] ★
+          ∀ vl, {{ ▷ ρ vl tid ★ tl_own tid ⊤ }} f (map of_val vl) {{λ _, False}})%I |}.
   Next Obligation.
-    iIntros (n perm tid vl) "H". iDestruct "H" as (f xl e Hcl) "[% _]". by subst.
+    iIntros (n ρ tid vl) "H". iDestruct "H" as (f) "[% _]". by subst.
   Qed.
 
   (* TODO *)
@@ -545,11 +548,13 @@ Notation "&uniq{ κ } ty" := (uniq_borrow κ ty)
   (format "&uniq{ κ } ty", at level 20, right associativity) : lrust_type_scope.
 Notation "&shr{ κ } ty" := (shared_borrow κ ty)
   (format "&shr{ κ } ty", at level 20, right associativity) : lrust_type_scope.
+
+(* FIXME : these notations do not work. *)
 Notation "( ty1 * ty2 * .. * tyn )" :=
   (product (cons ty1 (cons ty2 ( .. (cons tyn nil) .. ))))
-  (format "( ty1 * ty2 * .. * tyn )") : lrust_type_scope.
+  (format "( ty1  *  ty2  *  ..  *  tyn )") : lrust_type_scope.
 Notation "( ty1 + ty2 + .. + tyn )" :=
   (sum (cons ty1 (cons ty2 ( .. (cons tyn nil) .. ))))
-  (format "( ty1 + ty2 + .. + tyn )") : lrust_type_scope.
+  (format "( ty1  +  ty2  +  ..  +  tyn )") : lrust_type_scope.
 
 (* TODO : notation for forall *)
\ No newline at end of file
diff --git a/type_incl.v b/type_incl.v
index fd3dbc5821a381a39d40f95dfc2c13bf49749ab2..126442db4c5fbd624d97e2c4859a213c5e2fb116 100644
--- a/type_incl.v
+++ b/type_incl.v
@@ -1,6 +1,6 @@
 From iris.algebra Require Import upred_big_op.
 From iris.program_logic Require Import thread_local.
-From lrust Require Export type perm.
+From lrust Require Export type perm_incl.
 
 Import Types.
 
@@ -9,111 +9,218 @@ Section ty_incl.
   Context `{heapG Σ, lifetimeG Σ, thread_localG Σ}.
 
   Definition ty_incl (ρ : perm) (ty1 ty2 : type) :=
-    ∀ tid,
-      ρ tid ⊢
-      (□ ∀ tid vl, ty1.(ty_own) tid vl → ty2.(ty_own) tid vl) ∧
-      (□ ∀ κ tid E l, ty1.(ty_shr) κ tid E l →
-                      ty2.(ty_shr) κ tid E l
+    ∀ tid, ρ tid ={⊤}=>
+      (□ ∀ vl, ty1.(ty_own) tid vl → ty2.(ty_own) tid vl) ★
+      (□ ∀ κ E l, ty1.(ty_shr) κ tid E l →
        (* [ty_incl] needs to prove something about the length of the
           object when it is shared. We place this property under the
-          hypothesis that [ty2.(ty_shr)] holds, so that the [!]  type
+          hypothesis that [ty2.(ty_shr)] holds, so that the [!] type
           is still included in any other. *)
-                    ★ ty1.(ty_size) = ty2.(ty_size)).
+                  ty2.(ty_shr) κ tid E l ★ ty1.(ty_size) = ty2.(ty_size)).
 
-  Lemma ty_incl_refl ρ ty : ty_incl ρ ty ty.
-  Proof. iIntros (tid0) "_". iSplit; iIntros "!#"; eauto. Qed.
+  Global Instance ty_incl_refl ρ : Reflexive (ty_incl ρ).
+  Proof.
+    iIntros (ty tid) "_!==>". iSplit; iIntros "!#"; eauto.
+  Qed.
 
-  Lemma ty_incl_trans ρ ty1 ty2 ty3 :
-    ty_incl ρ ty1 ty2 → ty_incl ρ ty2 ty3 → ty_incl ρ ty1 ty3.
+  Lemma ty_incl_trans ρ θ ty1 ty2 ty3 :
+    ty_incl ρ ty1 ty2 → ty_incl θ ty2 ty3 → ty_incl (ρ ★ θ) ty1 ty3.
   Proof.
-    iIntros (H12 H23 tid0) "H".
-    iDestruct (H12 with "H") as "[#H12 #H12']".
-    iDestruct (H23 with "H") as "[#H23 #H23']".
-    iSplit; iIntros "{H}!#*H1".
+    iIntros (H12 H23 tid) "[H1 H2]".
+    iVs (H12 with "H1") as "[#H12 #H12']".
+    iVs (H23 with "H2") as "[#H23 #H23']".
+    iVsIntro; iSplit; iIntros "!#*H1".
     - by iApply "H23"; iApply "H12".
-    - iDestruct ("H12'" $! _ _ _ _ with "H1") as "[H2 %]".
-      iDestruct ("H23'" $! _ _ _ _ with "H2") as "[$ %]".
+    - iDestruct ("H12'" $! _ _ _ with "H1") as "[H2 %]".
+      iDestruct ("H23'" $! _ _ _ with "H2") as "[$ %]".
       iPureIntro. congruence.
   Qed.
 
-  Lemma ty_weaken ρ θ ty1 ty2 :
+  Lemma ty_incl_weaken ρ θ ty1 ty2 :
     perm_incl ρ θ → ty_incl θ ty1 ty2 → ty_incl ρ ty1 ty2.
-  Proof. iIntros (Hρθ Hθ tid) "H". iApply Hθ. by iApply Hρθ. Qed.
+  Proof. iIntros (Hρθ Hρ' tid) "H". iVs (Hρθ with "H"). by iApply Hρ'. Qed.
+
+  Global Instance ty_incl_trans' ρ: Duplicable ρ → Transitive (ty_incl ρ).
+  Proof. intros ??????. eauto using ty_incl_weaken, ty_incl_trans. Qed.
 
   Lemma ty_incl_bot ρ ty : ty_incl ρ ! ty.
-  Proof. iIntros (tid0) "_". iSplit; iIntros "!#*/=[]". Qed.
+  Proof. iIntros (tid) "_!==>". iSplit; iIntros "!#*/=[]". Qed.
 
   Lemma ty_incl_own ρ ty1 ty2 q :
     ty_incl ρ ty1 ty2 → ty_incl ρ (own q ty1) (own q ty2).
   Proof.
-    iIntros (Hincl tid0) "H/=". iDestruct (Hincl with "H") as "[#Howni #Hshri]".
-    iClear "H". iSplit; iIntros "!#*H".
+    iIntros (Hincl tid) "H/=". iVs (Hincl with "H") as "[#Howni #Hshri]".
+    iVsIntro. iSplit; iIntros "!#*H".
     - iDestruct "H" as (l) "(%&H†&Hmt)". subst. iExists _. iSplit. done.
       iDestruct "Hmt" as (vl') "[Hmt Hown]". iNext.
       iDestruct (ty_size_eq with "Hown") as %<-.
-      iDestruct ("Howni" $! _ _ with "Hown") as "Hown".
+      iDestruct ("Howni" $! _ with "Hown") as "Hown".
       iDestruct (ty_size_eq with "Hown") as %<-. iFrame.
       iExists _. by iFrame.
     - iDestruct "H" as (l') "[Hfb #Hvs]". iSplit; last done. iExists l'. iFrame.
       iIntros (q') "!#Hκ".
       iVs ("Hvs" $! _ with "Hκ") as "Hvs'". iIntros "!==>!>".
       iVs "Hvs'" as "[Hshr $]". iVsIntro.
-      by iDestruct ("Hshri" $! _ _ _ _ with "Hshr") as "[$ _]".
+      by iDestruct ("Hshri" $! _ _ _ with "Hshr") as "[$ _]".
   Qed.
 
-  Lemma lft_incl_ty_incl_uniq_borrow ρ ty κ1 κ2 :
-    perm_incl ρ (κ1 ⊑ κ2) → ty_incl ρ (&uniq{κ2}ty) (&uniq{κ1}ty).
+  Lemma lft_incl_ty_incl_uniq_borrow ty κ1 κ2 :
+    ty_incl (κ1 ⊑ κ2) (&uniq{κ2}ty) (&uniq{κ1}ty).
   Proof.
-    iIntros (Hκκ' tid0) "H". iDestruct (Hκκ' with "H") as "#Hκκ'". iClear "H".
-    iSplit; iIntros "!#*H".
+    iIntros (tid) "#Hincl!==>". iSplit; iIntros "!#*H".
     - iDestruct "H" as (l) "[% Hown]". subst. iExists _. iSplit. done.
-      by iApply (lft_borrow_incl with "Hκκ'").
+      by iApply (lft_borrow_incl with "Hincl").
     - admit. (* TODO : fix the definition before *)
   Admitted.
 
-  Lemma lft_incl_ty_incl_shared_borrow ρ ty κ1 κ2 :
-    perm_incl ρ (κ1 ⊑ κ2) → ty_incl ρ (&shr{κ2}ty) (&shr{κ1}ty).
+  Lemma lft_incl_ty_incl_shared_borrow ty κ1 κ2 :
+    ty_incl (κ1 ⊑ κ2) (&shr{κ2}ty) (&shr{κ1}ty).
   Proof.
-    iIntros (Hκκ' tid0) "H". iDestruct (Hκκ' with "H") as "#Hκκ'". iClear "H".
-    iSplit; iIntros "!#*H".
+    iIntros (tid) "#Hincl!==>". iSplit; iIntros "!#*H".
     - iDestruct "H" as (l) "[% Hown]". subst. iExists _. iSplit. done.
-      by iApply (ty.(ty_shr_mono) with "Hκκ'").
+      by iApply (ty.(ty_shr_mono) with "Hincl").
     - iDestruct "H" as (vl) "#[Hfrac Hty]". iSplit; last done.
       iExists vl. iFrame "#". iNext.
       iDestruct "Hty" as (l0) "[% Hty]". subst. iExists _. iSplit. done.
-      by iApply (ty_shr_mono with "Hκκ' Hty").
+      by iApply (ty_shr_mono with "Hincl Hty").
   Qed.
 
   Lemma ty_incl_prod ρ tyl1 tyl2 :
-    Forall2 (ty_incl ρ) tyl1 tyl2 → ty_incl ρ (product tyl1) (product tyl2).
+    Duplicable ρ → Forall2 (ty_incl ρ) tyl1 tyl2 →
+    ty_incl ρ (product tyl1) (product tyl2).
   Proof.
-    rewrite {2}/ty_incl /product /=. iIntros (HFA tid0) "Hρ". iSplit.
-    - assert (Himpl : ρ tid0 ⊢
-         □ (∀ tid vll, length tyl1 = length vll →
+    intros Hρ HFA. eapply ty_incl_weaken. apply Hρ.
+    iIntros (tid) "[Hρ1 Hρ2]". iSplitL "Hρ1".
+    - assert (Himpl : ρ tid ={⊤}=>
+         □ (∀ vll, length tyl1 = length vll →
                ([★ list] tyvl ∈ combine tyl1 vll, ty_own (tyvl.1) tid (tyvl.2))
              → ([★ list] tyvl ∈ combine tyl2 vll, ty_own (tyvl.1) tid (tyvl.2)))).
       { induction HFA as [|ty1 ty2 tyl1 tyl2 Hincl HFA IH].
-        - iIntros "_!#* _ _". by rewrite big_sepL_nil.
-        - iIntros "Hρ". iDestruct (IH with "Hρ") as "#Hqimpl".
-          iDestruct (Hincl with "Hρ") as "[#Hhimpl _]". iIntros "!#*%".
-          destruct vll as [|vlh vllq]. discriminate. rewrite !big_sepL_cons.
+        - iIntros "_!==>!#* _ _". by rewrite big_sepL_nil.
+        - iIntros "Hρ". iVs (Hρ with "Hρ") as "[Hρ1 Hρ2]".
+          iVs (IH with "Hρ1") as "#Hqimpl". iVs (Hincl with "Hρ2") as "[#Hhimpl _]".
+          iIntros "!==>!#*%". destruct vll as [|vlh vllq]. done. rewrite !big_sepL_cons.
           iIntros "[Hh Hq]". iSplitL "Hh". by iApply "Hhimpl".
           iApply ("Hqimpl" with "[] Hq"). iPureIntro. simpl in *. congruence. }
-      iDestruct (Himpl with "Hρ") as "#Himpl". iIntros "{Hρ}!#*H".
+      iVs (Himpl with "Hρ1") as "#Himpl". iIntros "!==>!#*H".
       iDestruct "H" as (vll) "(%&%&H)". iExists _. iSplit. done. iSplit.
       by rewrite -(Forall2_length _ _ _ HFA). by iApply ("Himpl" with "[] H").
-    - iRevert "Hρ". generalize O.
+    - rewrite /product /=. iRevert "Hρ2". generalize O.
       change (ndot (A:=nat)) with (λ N i, N .@ (0+i)%nat). generalize O.
       induction HFA as [|ty1 ty2 tyl1 tyl2 Hincl HFA IH].
-      + iIntros (i offs) "_!#* _". rewrite big_sepL_nil. eauto.
-      + iIntros (i offs) "Hρ". iDestruct (IH with "[] Hρ") as "#Hqimpl". done.
-        iDestruct (Hincl with "Hρ") as "[_ #Hhimpl]". iIntros "!#*".
+      + iIntros (i offs) "_!==>!#*_/=". rewrite big_sepL_nil. eauto.
+      + iIntros (i offs) "Hρ". iVs (Hρ with "Hρ") as "[Hρ1 Hρ2]".
+        iVs (IH with "[] Hρ1") as "#Hqimpl".
+        done. (* TODO : get rid of this done by doing induction in the proof mode. *)
+        iVs (Hincl with "Hρ2") as "[_ #Hhimpl]". iIntros "!==>!#*".
         rewrite !big_sepL_cons. iIntros "[Hh Hq]".
         setoid_rewrite <-Nat.add_succ_comm.
-        iDestruct ("Hhimpl" $! _ _ _ _ with "Hh") as "[$ %]".
+        iDestruct ("Hhimpl" $! _ _ _ with "Hh") as "[$ %]".
         replace ty2.(ty_size) with ty1.(ty_size) by done.
-        iDestruct ("Hqimpl" $! _ _ _ _ with "Hq") as "[$ %]".
+        iDestruct ("Hqimpl" $! _ _ _ with "Hq") as "[$ %]".
         iIntros "!%/=". congruence.
   Qed.
 
+  Lemma ty_incl_prod_cons_l ρ ty tyl :
+    ty_incl ρ (product (ty :: tyl)) (product [ty ; product tyl]).
+  Proof.
+    iIntros (tid) "_!==>". iSplit; iIntros "!#/=".
+    - iIntros (vl) "H". iDestruct "H" as ([|vlh vllq]) "(%&%&H)". done. subst.
+      iExists [_;_]. iSplit. by rewrite /= app_nil_r. iSplit. done.
+      rewrite !big_sepL_cons big_sepL_nil right_id. iDestruct "H" as "[$ H]".
+      iExists _. repeat iSplit; try done. iPureIntro. simpl in *; congruence.
+    - iIntros (κ E l) "H". iSplit; last (iPureIntro; lia).
+      rewrite !big_sepL_cons big_sepL_nil right_id. iDestruct "H" as "[$ H]".
+      (* FIXME : namespaces do not match. *)
+      admit.
+  Admitted.
+
+  (* TODO *)
+  Lemma ty_incl_prod_flatten ρ tyl1 tyl2 tyl3 :
+    ty_incl ρ (product (tyl1 ++ product tyl2 :: tyl3))
+              (product (tyl1 ++ tyl2 ++ tyl3)).
+  Admitted.
+
+  Lemma ty_incl_sum ρ n tyl1 tyl2 (_ : LstTySize n tyl1) (_ : LstTySize n tyl2) :
+    Duplicable ρ →
+    Forall2 (ty_incl ρ) tyl1 tyl2 → ty_incl ρ (sum tyl1) (sum tyl2).
+  Proof.
+    iIntros (DUP FA tid) "Hρ". rewrite /sum /=.
+    iVs (DUP with "Hρ") as "[Hρ1 Hρ2]". iSplitR "Hρ2".
+    - assert (Hincl : ρ tid ={⊤}=>
+         (□ ∀ i vl, (nth i tyl1 !%T).(ty_own) tid vl
+                  → (nth i tyl2 !%T).(ty_own) tid vl)).
+      { clear -FA DUP. induction FA as [|ty1 ty2 tyl1 tyl2 Hincl _ IH].
+        - iIntros "_!==>*!#". eauto.
+        - iIntros "Hρ". iVs (DUP with "Hρ") as "[Hρ1 Hρ2]".
+          iVs (IH with "Hρ1") as "#IH". iVs (Hincl with "Hρ2") as "[#Hh _]".
+          iIntros "!==>*!#*Hown". destruct i as [|i]. by iApply "Hh". by iApply "IH". }
+      iVs (Hincl with "Hρ1") as "#Hincl". iIntros "!==>!#*H".
+      iDestruct "H" as (i vl') "[% Hown]". subst. iExists _, _. iSplit. done.
+        by iApply "Hincl".
+    - assert (Hincl : ρ tid ={⊤}=>
+         (□ ∀ i κ E l, (nth i tyl1 !%T).(ty_shr) κ tid E l
+                     → (nth i tyl2 !%T).(ty_shr) κ tid E l)).
+      { clear -FA DUP. induction FA as [|ty1 ty2 tyl1 tyl2 Hincl _ IH].
+        - iIntros "_!==>*!#". eauto.
+        - iIntros "Hρ". iVs (DUP with "Hρ") as "[Hρ1 Hρ2]".
+          iVs (IH with "Hρ1") as "#IH". iVs (Hincl with "Hρ2") as "[_ #Hh]".
+          iIntros "!==>*!#*Hown". destruct i as [|i]; last by iApply "IH".
+          by iDestruct ("Hh" $! _ _ _ with "Hown") as "[$ _]". }
+      iVs (Hincl with "Hρ2") as "#Hincl". iIntros "!==>!#*H". iSplit; last done.
+      iDestruct "H" as (i) "[??]". iExists _. iSplit. done. by iApply "Hincl".
+  Qed.
+
+  Lemma ty_incl_uninit_split ρ n1 n2 :
+    ty_incl ρ (uninit (n1+n2)) (product [uninit n1; uninit n2]).
+  Proof.
+    iIntros (tid) "_!==>". iSplit; iIntros "!#*H".
+    - iDestruct "H" as %Hlen. iExists [take n1 vl; drop n1 vl].
+      repeat iSplit. by rewrite /= app_nil_r take_drop. done.
+      rewrite big_sepL_cons big_sepL_singleton. iSplit; iPureIntro.
+      apply take_length_le. lia. rewrite drop_length. lia.
+    - iSplit; last (iPureIntro; simpl; lia). iDestruct "H" as (vl) "[#Hf #Hlen]".
+      rewrite /= big_sepL_cons big_sepL_singleton. iSplit.
+      + iExists (take n1 vl). iSplit.
+        (* FIXME : cannot split the fractured borrow. *)
+        admit.
+        iNext. iDestruct "Hlen" as %Hlen. rewrite /= take_length_le //. lia.
+      + iExists (drop n1 vl). iSplit.
+        (* FIXME : cannot split the fractured borrow. *)
+        admit.
+        iNext. iDestruct "Hlen" as %Hlen. rewrite /= drop_length. iPureIntro. lia.
+  Admitted.
+
+  Lemma ty_incl_uninit_combine ρ n1 n2 :
+    ty_incl ρ (product [uninit n1; uninit n2]) (uninit (n1+n2)).
+  Proof.
+  (* FIXME : idem : cannot combine the fractured borrow. *)
+  Admitted.
+
+  (* Lemma ty_incl_cont_frame {n} ρ ρ1 ρ2 : *)
+  (*   Duplicable ρ → (∀ vl : vec val n, perm_incl (ρ ★ ρ2 vl) (ρ1 vl)) → *)
+  (*   ty_incl ρ (cont ρ1) (cont ρ2). *)
+  (* Proof. *)
+  (*   iIntros (? Hρ1ρ2 tid) "Hρ". *)
+  (*   iVs (inv_alloc lrustN _ (ρ tid) with "[Hρ]") as "#INV". by auto. *)
+  (*   iIntros "!==>". iSplit; iIntros "!#*H"; last by auto. *)
+  (*   iDestruct "H" as (f xl e ?) "[% Hwp]". subst. iExists _, _, _, _. iSplit. done. *)
+  (*   iIntros (vl) "Htl Hown". *)
+  (*   iApply pvs_wp. iInv lrustN as "Hρ" "Hclose". *)
+
+  (*   iSplit; last by iIntros "{Hρ}!#*_"; auto. *)
+  (*   (* FIXME : I do not know how to prove this. Should we put this *)
+  (*      under a view modality and then put Hρ in an invariant? *) *)
+  (*   admit. *)
+  (* Admitted. *)
+
+  (* Lemma ty_incl_fn_frame {n} ρ ρ1 ρ2 : *)
+  (*   Duplicable ρ → (∀ vl : vec val n, perm_incl (ρ ★ ρ2 vl) (ρ1 vl)) → *)
+  (*   ty_incl ρ (fn ρ1) (fn ρ2). *)
+  (*   (* FIXME : idem. *) *)
+  (*   admit. *)
+  (* Admitted. *)
+
+  (* TODO : forall, when we will have figured out the right definition. *)
+
 End ty_incl.
\ No newline at end of file