Substitution
Set Implicit Arguments.
Require Import List Coq.Program.Equality String.
Require Import Definitions Binding Replacement Weakening.
Ltac subst_open_fresh :=
match goal with
| [ |- context [ open_typ ?z (subst_typ ?x ?p ?T) ] ] ⇒
replace (open_typ z (subst_typ x p T)) with
(open_typ_p (subst_path x p (pvar z)) (subst_typ x p T)) by
(unfold subst_path; simpl; unfold subst_var_p;
rewrite If_r, open_var_typ_eq; auto)
| [ |- context [ open_defs ?z (subst_defs ?x ?p ?ds) ] ] ⇒
replace (open_defs z (subst_defs x p ds)) with
(open_defs_p (subst_path x p (pvar z)) (subst_defs x p ds))
by (unfold subst_path; simpl; unfold subst_var_p;
rewrite If_r, open_var_defs_eq; auto)
| [ |- context [ open_trm ?z (subst_trm ?x ?p ?t) ] ] ⇒
replace (open_trm z (subst_trm x p t)) with
(open_trm_p (subst_path x p (pvar z)) (subst_trm x p t))
by (unfold subst_path; simpl; unfold subst_var_p;
rewrite If_r, open_var_trm_eq; auto)
end.
Ltac subst_fresh_solver :=
fresh_constructor;
subst_open_fresh;
match goal with
| [ H: ∀ z, z \notin ?L → ∀ G, _
|- context [_ & subst_ctx ?x ?p ?G2 & ?z ~ subst_typ ?x ?p ?V] ] ⇒
assert (subst_ctx x p G2 & z ~ subst_typ x p V = subst_ctx x p (G2 & z ~ V)) as B
by (unfold subst_ctx; rewrite map_concat, map_single; auto);
rewrite <- concat_assoc; rewrite B;
subst_open_fresh;
rewrite× <- subst_open_commut_trm_p;
rewrite× <- subst_open_commut_typ_p;
rewrite <- open_var_typ_eq, <- open_var_trm_eq;
apply× H; try rewrite× concat_assoc;
rewrite <- B, concat_assoc; unfold subst_ctx;
auto using weaken_ty_trm, ok_push, ok_concat_map
end.
Ltac subst_tydef_solver :=
match goal with
| [ H: ∀ G3 G4 x, _,
Hok: ok _,
Hx: ?x \notin fv_ctx_types _,
Hy: _ & _ ⊢ _ : _ |- _] ⇒
specialize (H _ _ _ eq_refl Hok Hx);
try solve [rewrite subst_open_commut_defs_p in H;
rewrite subst_open_commut_typ_p in H; eauto]
end.
Lemma open_typ_subst: ∀ x y p T,
named_path p →
x ≠ y →
open_typ x (subst_typ y p T) =
subst_typ y p (open_typ x T).
Proof.
intros.
rewrite open_var_typ_eq.
unfold open_typ.
rewrite subst_open_commut_typ.
- f_equal. unfold subst_var_p. case_if×.
- apply H.
Qed.
Substitution preserves tight-boundness in types and declaration
Lemma tight_bounds_subst_mut :
(∀ T, tight_bounds T → ∀ x p, tight_bounds (subst_typ x p T)) ∧
(∀ D, tight_bounds_dec D → ∀ x p, tight_bounds_dec (subst_dec x p D)).
Proof.
apply typ_mutind; intros; subst; simpls; subst; eauto. split×.
Qed.
(∀ T, tight_bounds T → ∀ x p, tight_bounds (subst_typ x p T)) ∧
(∀ D, tight_bounds_dec D → ∀ x p, tight_bounds_dec (subst_dec x p D)).
Proof.
apply typ_mutind; intros; subst; simpls; subst; eauto. split×.
Qed.
...for types only
Lemma tight_bounds_subst x p T :
tight_bounds T → tight_bounds (subst_typ x p T).
Proof.
intros. apply× tight_bounds_subst_mut.
Qed.
tight_bounds T → tight_bounds (subst_typ x p T).
Proof.
intros. apply× tight_bounds_subst_mut.
Qed.
Substitution Lemma
x \notin fv(G1)
G1, G2[p/x] ⊢ p: S[p/x]
―――――――――――――――――――――――――――――
G1, G2[p/x] ⊢ t[p/x]: T[p/x]
x \notin fv(G1)
x ≠ z
G1, G2[p/x] ⊢ p: S[p/x]
―――――――――――――――――――――――――――――
z.bs; G1, G2[p/x] ⊢ d[p/x]: D[p/x]
x \notin fv(G1)
x ≠ z
G1, G2[p/x] ⊢ p: S[p/x]
――――――――――――――――――――――――――――――
z.bs; G1, G2[p/x] ⊢ ds[p/x]: T[p/x]
x \notin fv(G1)
G1, G2[p/x] ⊢ p: S[p/x]
―――――――――――――――――――――――――――――――
G1, G2[p/x] ⊢ T[p/x] <: U[p/x]
Lemma subst_rules: ∀ p S,
(∀ G t T, G ⊢ t : T → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
G1 & (subst_ctx x p G2) ⊢ subst_trm x p t : subst_typ x p T) ∧
(∀ z bs G d D, z; bs; G ⊢ d : D → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
z ≠ x →
z; bs; G1 & (subst_ctx x p G2) ⊢ subst_def x p d : subst_dec x p D) ∧
(∀ z bs G ds T, z; bs; G ⊢ ds :: T → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
z ≠ x →
z; bs; G1 & (subst_ctx x p G2) ⊢ subst_defs x p ds :: subst_typ x p T) ∧
(∀ G T U, G ⊢ T <: U → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
G1 & (subst_ctx x p G2) ⊢ subst_typ x p T <: subst_typ x p U).
Proof.
intros p S.
apply rules_mutind; intros; subst; simpl;
try (subst_fresh_solver || rewrite subst_open_commut_typ_p);
simpl in *; autounfold;
try assert (named_path p) as Hn by apply× typed_paths_named;
eauto 4.
- Case "ty_var"%string.
cases_if.
+ apply binds_middle_eq_inv in b; subst×. destruct× p.
+ eapply subst_fresh_ctx in H1.
apply binds_subst in b; auto.
constructor. rewrite <- H1.
unfold subst_ctx. rewrite <- map_concat.
apply binds_map; auto.
- Case "ty_all_intro"%string.
fresh_constructor.
subst_open_fresh.
destruct p as [p_x p_bs].
match goal with
| [ H: ∀ z, z \notin ?L → ∀ G, _
|- context [_ & subst_ctx ?x ?p ?G2 & ?z ~ subst_typ ?x ?p ?V] ] ⇒
assert (subst_ctx x p G2 & z ~ subst_typ x p V = subst_ctx x p (G2 & z ~ V)) as B
by (unfold subst_ctx; rewrite map_concat, map_single; auto);
rewrite <- concat_assoc; rewrite B;
subst_open_fresh;
rewrite× <- subst_open_commut_trm_p;
rewrite× <- subst_open_commut_typ_p;
rewrite <- open_var_trm_eq, <- open_var_typ_eq;
apply× H; try rewrite× concat_assoc;
rewrite <- B, concat_assoc; unfold subst_ctx;
auto using weaken_ty_trm, ok_push, ok_concat_map
end.
- Case "ty_new_intro"%string.
fresh_constructor.
subst_open_fresh.
match goal with
| [ |- _; _; _ ⊢ _ _ _ :: _ ] ⇒
assert (pvar z = subst_var_p x p z) as Hxyz by (unfold subst_var_p; rewrite~ If_r);
rewrite Hxyz at 1
end.
rewrite <- Hxyz.
subst_open_fresh.
rewrite× <- subst_open_commut_typ_p.
rewrite× <- subst_open_commut_defs_p.
assert (subst_ctx x p G2 & z ~ subst_typ x p (open_typ_p (pvar z) T) =
subst_ctx x p (G2 & z ~ open_typ_p (pvar z) T)) as Heq
by (unfold subst_ctx; rewrite map_concat, map_single; auto).
rewrite <- concat_assoc. rewrite Heq.
destruct p as [p_x p_bs].
assert (∃ p_x0, p_x = avar_f p_x0) as Heq'. {
inversions Hn. destruct_all. inversions H0. eauto.
}
destruct Heq' as [p_x0 Heq']; subst.
assert (z = subst_var x p_x0 z) as Heq'. {
unfolds subst_var; rewrite~ If_r.
}
rewrite <- open_var_typ_eq, <- open_var_defs_eq.
apply× H; try rewrite× concat_assoc.
unfolds subst_ctx. rewrite map_concat. rewrite concat_assoc.
apply× weaken_ty_trm.
- Case "ty_new_elim"%string.
asserts_rewrite (subst_path x p p0 • a = (subst_path x p p0) • a).
destruct p0. apply sel_fields_subst. auto.
- Case "ty_rcd_intro"%string.
assert (subst_path x p p0 • a = (subst_path x p p0) • a) as Heq. {
destruct p0. apply sel_fields_subst.
}
specialize (H _ _ _ eq_refl H1 H2 H3). rewrite Heq in H. eauto.
- Case "ty_let"%string.
fresh_constructor.
subst_open_fresh.
match goal with
| [ H: ∀ z, z \notin ?L → ∀ G, _
|- context [_ & subst_ctx ?x ?p ?G2 & ?z ~ subst_typ ?x ?p ?V] ] ⇒
assert (subst_ctx x p G2 & z ~ subst_typ x p V = subst_ctx x p (G2 & z ~ V)) as B
by (unfold subst_ctx; rewrite map_concat, map_single; auto);
rewrite <- concat_assoc; rewrite B;
rewrite× <- subst_open_commut_trm_p;
rewrite <- open_var_trm_eq;
apply× H; try rewrite× concat_assoc;
rewrite <- B, concat_assoc; unfold subst_ctx;
auto using weaken_ty_trm, ok_push, ok_concat_map
end.
- Case "ty_path_elim"%string.
destruct p0, q.
rewrite sel_fields_subst.
rewrite sel_fields_subst.
eapply ty_path_elim; try (rewrite <- sel_fields_subst); auto.
- Case "ty_rec_intro"%string.
constructor. rewrite× <- subst_open_commut_typ_p.
- Case "ty_def_new"%string.
specialize (H _ _ _ eq_refl H1 H2 H3 H4).
rewrite× subst_open_commut_defs_p in H.
rewrite× subst_open_commut_typ_p in H.
unfolds subst_var.
eapply ty_def_new; eauto.
× replace (μ (subst_typ x0 p T)) with (subst_typ x0 p (μ T)) by auto.
apply tight_bounds_subst. eauto.
× simpl.
replace (p_sel (avar_f x) (b :: bs)) with (subst_path x0 p (p_sel (avar_f x) (b :: bs))); eauto.
simpl. unfold subst_var_p.
case_if×. simpl. rewrite app_nil_r. auto.
- Case "ty_defs_cons"%string.
apply ty_defs_cons.
× eapply H; eauto.
× eapply H0; eauto.
× eapply subst_defs_hasnt_label. apply d0.
- Case "subtyp_sngl_pq"%string.
subst_tydef_solver.
eapply subtyp_sngl_pq; eauto.
eapply repl_typ_subst. apply r.
- Case "subtyp_sngl_qp"%string.
subst_tydef_solver.
eapply subtyp_sngl_qp; eauto.
eapply repl_typ_subst. apply r.
- Case "subtyp_all"%string.
subst_tydef_solver.
eapply (@subtyp_all (L \u \{ x } \u (dom (G1 & (subst_ctx x p G2)) \u (dom (G1 & x ~ S & G2))))). eauto.
intros x0 Hx0.
assert (Hx0inL: x0 \notin L) by auto.
assert (Hxx0: x0 ≠ x) by auto.
assert (Hx0inG: x0 # (G1 & (subst_ctx x p G2))) by auto.
rewrite open_typ_subst; try assumption.
rewrite open_typ_subst; try assumption.
specialize (H0 x0 Hx0inL G1 (G2 & x0 ~ S2) x).
replace (G1 & subst_ctx x p G2 & x0 ~ subst_typ x p S2)
with (G1 & subst_ctx x p (G2 & x0 ~ S2)).
× eapply H0.
+ rewrite concat_assoc. auto.
+ rewrite concat_assoc. constructor.
apply H2. auto.
+ apply H3.
+ unfold subst_ctx. rewrite map_push.
rewrite concat_assoc. fold subst_ctx.
apply weaken_ty_trm.
apply H4. constructor; auto.
× unfold subst_ctx. rewrite map_push.
rewrite concat_assoc. auto.
Qed.
(∀ G t T, G ⊢ t : T → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
G1 & (subst_ctx x p G2) ⊢ subst_trm x p t : subst_typ x p T) ∧
(∀ z bs G d D, z; bs; G ⊢ d : D → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
z ≠ x →
z; bs; G1 & (subst_ctx x p G2) ⊢ subst_def x p d : subst_dec x p D) ∧
(∀ z bs G ds T, z; bs; G ⊢ ds :: T → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
z ≠ x →
z; bs; G1 & (subst_ctx x p G2) ⊢ subst_defs x p ds :: subst_typ x p T) ∧
(∀ G T U, G ⊢ T <: U → ∀ G1 G2 x,
G = G1 & x ~ S & G2 →
ok (G1 & x ~ S & G2) →
x \notin fv_ctx_types G1 →
G1 & (subst_ctx x p G2) ⊢ trm_path p : subst_typ x p S →
G1 & (subst_ctx x p G2) ⊢ subst_typ x p T <: subst_typ x p U).
Proof.
intros p S.
apply rules_mutind; intros; subst; simpl;
try (subst_fresh_solver || rewrite subst_open_commut_typ_p);
simpl in *; autounfold;
try assert (named_path p) as Hn by apply× typed_paths_named;
eauto 4.
- Case "ty_var"%string.
cases_if.
+ apply binds_middle_eq_inv in b; subst×. destruct× p.
+ eapply subst_fresh_ctx in H1.
apply binds_subst in b; auto.
constructor. rewrite <- H1.
unfold subst_ctx. rewrite <- map_concat.
apply binds_map; auto.
- Case "ty_all_intro"%string.
fresh_constructor.
subst_open_fresh.
destruct p as [p_x p_bs].
match goal with
| [ H: ∀ z, z \notin ?L → ∀ G, _
|- context [_ & subst_ctx ?x ?p ?G2 & ?z ~ subst_typ ?x ?p ?V] ] ⇒
assert (subst_ctx x p G2 & z ~ subst_typ x p V = subst_ctx x p (G2 & z ~ V)) as B
by (unfold subst_ctx; rewrite map_concat, map_single; auto);
rewrite <- concat_assoc; rewrite B;
subst_open_fresh;
rewrite× <- subst_open_commut_trm_p;
rewrite× <- subst_open_commut_typ_p;
rewrite <- open_var_trm_eq, <- open_var_typ_eq;
apply× H; try rewrite× concat_assoc;
rewrite <- B, concat_assoc; unfold subst_ctx;
auto using weaken_ty_trm, ok_push, ok_concat_map
end.
- Case "ty_new_intro"%string.
fresh_constructor.
subst_open_fresh.
match goal with
| [ |- _; _; _ ⊢ _ _ _ :: _ ] ⇒
assert (pvar z = subst_var_p x p z) as Hxyz by (unfold subst_var_p; rewrite~ If_r);
rewrite Hxyz at 1
end.
rewrite <- Hxyz.
subst_open_fresh.
rewrite× <- subst_open_commut_typ_p.
rewrite× <- subst_open_commut_defs_p.
assert (subst_ctx x p G2 & z ~ subst_typ x p (open_typ_p (pvar z) T) =
subst_ctx x p (G2 & z ~ open_typ_p (pvar z) T)) as Heq
by (unfold subst_ctx; rewrite map_concat, map_single; auto).
rewrite <- concat_assoc. rewrite Heq.
destruct p as [p_x p_bs].
assert (∃ p_x0, p_x = avar_f p_x0) as Heq'. {
inversions Hn. destruct_all. inversions H0. eauto.
}
destruct Heq' as [p_x0 Heq']; subst.
assert (z = subst_var x p_x0 z) as Heq'. {
unfolds subst_var; rewrite~ If_r.
}
rewrite <- open_var_typ_eq, <- open_var_defs_eq.
apply× H; try rewrite× concat_assoc.
unfolds subst_ctx. rewrite map_concat. rewrite concat_assoc.
apply× weaken_ty_trm.
- Case "ty_new_elim"%string.
asserts_rewrite (subst_path x p p0 • a = (subst_path x p p0) • a).
destruct p0. apply sel_fields_subst. auto.
- Case "ty_rcd_intro"%string.
assert (subst_path x p p0 • a = (subst_path x p p0) • a) as Heq. {
destruct p0. apply sel_fields_subst.
}
specialize (H _ _ _ eq_refl H1 H2 H3). rewrite Heq in H. eauto.
- Case "ty_let"%string.
fresh_constructor.
subst_open_fresh.
match goal with
| [ H: ∀ z, z \notin ?L → ∀ G, _
|- context [_ & subst_ctx ?x ?p ?G2 & ?z ~ subst_typ ?x ?p ?V] ] ⇒
assert (subst_ctx x p G2 & z ~ subst_typ x p V = subst_ctx x p (G2 & z ~ V)) as B
by (unfold subst_ctx; rewrite map_concat, map_single; auto);
rewrite <- concat_assoc; rewrite B;
rewrite× <- subst_open_commut_trm_p;
rewrite <- open_var_trm_eq;
apply× H; try rewrite× concat_assoc;
rewrite <- B, concat_assoc; unfold subst_ctx;
auto using weaken_ty_trm, ok_push, ok_concat_map
end.
- Case "ty_path_elim"%string.
destruct p0, q.
rewrite sel_fields_subst.
rewrite sel_fields_subst.
eapply ty_path_elim; try (rewrite <- sel_fields_subst); auto.
- Case "ty_rec_intro"%string.
constructor. rewrite× <- subst_open_commut_typ_p.
- Case "ty_def_new"%string.
specialize (H _ _ _ eq_refl H1 H2 H3 H4).
rewrite× subst_open_commut_defs_p in H.
rewrite× subst_open_commut_typ_p in H.
unfolds subst_var.
eapply ty_def_new; eauto.
× replace (μ (subst_typ x0 p T)) with (subst_typ x0 p (μ T)) by auto.
apply tight_bounds_subst. eauto.
× simpl.
replace (p_sel (avar_f x) (b :: bs)) with (subst_path x0 p (p_sel (avar_f x) (b :: bs))); eauto.
simpl. unfold subst_var_p.
case_if×. simpl. rewrite app_nil_r. auto.
- Case "ty_defs_cons"%string.
apply ty_defs_cons.
× eapply H; eauto.
× eapply H0; eauto.
× eapply subst_defs_hasnt_label. apply d0.
- Case "subtyp_sngl_pq"%string.
subst_tydef_solver.
eapply subtyp_sngl_pq; eauto.
eapply repl_typ_subst. apply r.
- Case "subtyp_sngl_qp"%string.
subst_tydef_solver.
eapply subtyp_sngl_qp; eauto.
eapply repl_typ_subst. apply r.
- Case "subtyp_all"%string.
subst_tydef_solver.
eapply (@subtyp_all (L \u \{ x } \u (dom (G1 & (subst_ctx x p G2)) \u (dom (G1 & x ~ S & G2))))). eauto.
intros x0 Hx0.
assert (Hx0inL: x0 \notin L) by auto.
assert (Hxx0: x0 ≠ x) by auto.
assert (Hx0inG: x0 # (G1 & (subst_ctx x p G2))) by auto.
rewrite open_typ_subst; try assumption.
rewrite open_typ_subst; try assumption.
specialize (H0 x0 Hx0inL G1 (G2 & x0 ~ S2) x).
replace (G1 & subst_ctx x p G2 & x0 ~ subst_typ x p S2)
with (G1 & subst_ctx x p (G2 & x0 ~ S2)).
× eapply H0.
+ rewrite concat_assoc. auto.
+ rewrite concat_assoc. constructor.
apply H2. auto.
+ apply H3.
+ unfold subst_ctx. rewrite map_push.
rewrite concat_assoc. fold subst_ctx.
apply weaken_ty_trm.
apply H4. constructor; auto.
× unfold subst_ctx. rewrite map_push.
rewrite concat_assoc. auto.
Qed.
The substitution lemma for term typing.
Lemma subst_ty_trm: ∀ p S G x t T,
G & x ~ S ⊢ t : T →
ok (G & x ~ S) →
x \notin fv_ctx_types G →
G ⊢ trm_path p : subst_typ x p S →
G ⊢ subst_trm x p t : subst_typ x p T.
Proof.
introv Ht Hok Hx Hp.
apply (proj41 (subst_rules p S)) with (G1:=G) (G2:=empty) (x:=x) in Ht.
unfold subst_ctx in Ht. rewrite map_empty, concat_empty_r in Ht.
apply Ht. rewrite× concat_empty_r. rewrite× concat_empty_r. assumption.
unfold subst_ctx. rewrite map_empty, concat_empty_r. assumption.
Qed.
G & x ~ S ⊢ t : T →
ok (G & x ~ S) →
x \notin fv_ctx_types G →
G ⊢ trm_path p : subst_typ x p S →
G ⊢ subst_trm x p t : subst_typ x p T.
Proof.
introv Ht Hok Hx Hp.
apply (proj41 (subst_rules p S)) with (G1:=G) (G2:=empty) (x:=x) in Ht.
unfold subst_ctx in Ht. rewrite map_empty, concat_empty_r in Ht.
apply Ht. rewrite× concat_empty_r. rewrite× concat_empty_r. assumption.
unfold subst_ctx. rewrite map_empty, concat_empty_r. assumption.
Qed.
Substitute a variable in the environment that is used for opening
with a path of the same type
z fresh
G, z: U ⊢ t^z : T^z
G ⊢ p: U
――――――――――――――――――――――
G ⊢ t^p : T^p
G, z: U ⊢ t^z : T^z
G ⊢ p: U
――――――――――――――――――――――
G ⊢ t^p : T^p
Lemma subst_var_path: ∀ G z T U t p,
ok G →
z # G →
z \notin (fv_ctx_types G \u fv_typ U \u fv_typ T \u fv_trm t) →
G & z ~ U ⊢ open_trm z t : open_typ z T →
G ⊢ trm_path p : U →
G ⊢ open_trm_p p t : open_typ_p p T.
Proof.
introv Hok Hnz Hnz' Hz Hx. rewrite subst_intro_typ with (x:=z). rewrite subst_intro_trm with (x:=z).
eapply subst_ty_trm; auto. eapply Hz.
rewrite subst_fresh_typ. all: eauto using typed_paths_named.
Qed.
ok G →
z # G →
z \notin (fv_ctx_types G \u fv_typ U \u fv_typ T \u fv_trm t) →
G & z ~ U ⊢ open_trm z t : open_typ z T →
G ⊢ trm_path p : U →
G ⊢ open_trm_p p t : open_typ_p p T.
Proof.
introv Hok Hnz Hnz' Hz Hx. rewrite subst_intro_typ with (x:=z). rewrite subst_intro_trm with (x:=z).
eapply subst_ty_trm; auto. eapply Hz.
rewrite subst_fresh_typ. all: eauto using typed_paths_named.
Qed.
Substitute a fresh opening variable with a path of the same type:
if ∀ fresh x, G, x: T ⊢ u^x: U and G ⊢ p: T then G ⊢ u^p : U^p
if ∀ fresh x, G, x: T ⊢ u^x: U and G ⊢ p: T then G ⊢ u^p : U^p
Lemma subst_fresh_var_path : ∀ L G T u U p,
ok G →
(∀ x : var, x \notin L → G & x ~ T ⊢ open_trm x u : U) →
G ⊢ trm_path p : T →
G ⊢ open_trm_p p u : U.
Proof.
introv Hok Hu Hp. pick_fresh y.
rewrite subst_intro_trm with (x:=y); auto.
rewrite <- subst_fresh_typ with (x := y) (p := p); auto.
eapply subst_ty_trm; eauto. rewrite~ subst_fresh_typ.
apply× typed_paths_named.
Qed.
ok G →
(∀ x : var, x \notin L → G & x ~ T ⊢ open_trm x u : U) →
G ⊢ trm_path p : T →
G ⊢ open_trm_p p u : U.
Proof.
introv Hok Hu Hp. pick_fresh y.
rewrite subst_intro_trm with (x:=y); auto.
rewrite <- subst_fresh_typ with (x := y) (p := p); auto.
eapply subst_ty_trm; eauto. rewrite~ subst_fresh_typ.
apply× typed_paths_named.
Qed.
Renaming
if G1, z: T, G2 ⊢ t: U then G1, x: T[x/z], G2[x/z] ⊢ t[x/z]: U[x/z]
Lemma rename_ty_trm x z G1 T G2 t U:
z \notin fv_ctx_types G1 →
G1 & z ~ T & G2 ⊢ t : U →
ok (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2) →
G1 & x ~ subst_typ z (pvar x) T & subst_ctx z (pvar x) G2 ⊢ subst_trm z (pvar x) t : subst_typ z (pvar x) U.
Proof.
intros Hz Ht Hok.
assert (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2 ⊢ t : U). {
rewrite <- concat_assoc in ×. apply× weaken_rules.
}
eapply subst_rules.
apply H. eauto. eauto.
rewrite fv_ctx_types_push_eq. apply notin_union; split×.
apply× fresh_subst_typ_dec. simpl. intros Hin. rewrite in_singleton in Hin. subst.
rewrite <- concat_assoc in Hok.
apply ok_middle_inv_r in Hok. simpl_dom. apply notin_union in Hok as [C%notin_singleton _]. false×.
constructor. apply× binds_concat_left_ok. apply ok_remove in Hok.
apply× ok_concat_map.
Qed.
z \notin fv_ctx_types G1 →
G1 & z ~ T & G2 ⊢ t : U →
ok (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2) →
G1 & x ~ subst_typ z (pvar x) T & subst_ctx z (pvar x) G2 ⊢ subst_trm z (pvar x) t : subst_typ z (pvar x) U.
Proof.
intros Hz Ht Hok.
assert (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2 ⊢ t : U). {
rewrite <- concat_assoc in ×. apply× weaken_rules.
}
eapply subst_rules.
apply H. eauto. eauto.
rewrite fv_ctx_types_push_eq. apply notin_union; split×.
apply× fresh_subst_typ_dec. simpl. intros Hin. rewrite in_singleton in Hin. subst.
rewrite <- concat_assoc in Hok.
apply ok_middle_inv_r in Hok. simpl_dom. apply notin_union in Hok as [C%notin_singleton _]. false×.
constructor. apply× binds_concat_left_ok. apply ok_remove in Hok.
apply× ok_concat_map.
Qed.
Replace the this variable with a fresh variable for definition typing:
: if z.bs; G1, z: T, G2 ⊢ ds: U then x.bs; G1, x: T[x/z], G2[x/z] ⊢ ds[x/z]: U[x/z]
: if z.bs; G1, z: T, G2 ⊢ ds: U then x.bs; G1, x: T[x/z], G2[x/z] ⊢ ds[x/z]: U[x/z]
Lemma rename_def_defs :
(∀ z bs G d D, z; bs; G ⊢ d : D → ∀ G1 T G2 x,
G = G1 & z ~ T & G2 →
z \notin fv_ctx_types G1 →
ok (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2) →
x; bs; G1 & x ~ subst_typ z (pvar x) T & subst_ctx z (pvar x) G2 ⊢
subst_def z (pvar x) d : subst_dec z (pvar x) D) ∧
(∀ z bs G ds U, z; bs; G ⊢ ds :: U → ∀ G1 T G2 x,
G = G1 & z ~ T & G2 →
z \notin fv_ctx_types G1 →
ok (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2) →
x; bs; G1 & x ~ subst_typ z (pvar x) T & subst_ctx z (pvar x) G2 ⊢
subst_defs z (pvar x) ds :: subst_typ z (pvar x) U).
Proof.
apply ty_def_mutind; intros; subst.
- constructor.
- pose proof (rename_ty_trm H0 t0 H1).
constructor×.
- specialize (H _ _ _ _ eq_refl H1 H2). simpl in ×. apply× ty_def_new.
eapply tight_bounds_subst in t. eauto.
rewrite subst_open_commut_defs_p in H; try repeat eexists.
rewrite subst_open_commut_typ_p in H; try repeat eexists.
unfold subst_path, subst_avar, subst_var_p in H. case_if.
simpl in H. rewrite List.app_nil_r in H. simpl. auto.
- pose proof (rename_ty_trm H0 t H1). econstructor; eauto.
- constructor×.
- specialize (H0 _ _ _ _ eq_refl H2 H3). specialize (H _ _ _ _ eq_refl H2 H3).
econstructor; eauto. apply× subst_defs_hasnt. rewrite× <- subst_label_of_def.
Qed.
(∀ z bs G d D, z; bs; G ⊢ d : D → ∀ G1 T G2 x,
G = G1 & z ~ T & G2 →
z \notin fv_ctx_types G1 →
ok (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2) →
x; bs; G1 & x ~ subst_typ z (pvar x) T & subst_ctx z (pvar x) G2 ⊢
subst_def z (pvar x) d : subst_dec z (pvar x) D) ∧
(∀ z bs G ds U, z; bs; G ⊢ ds :: U → ∀ G1 T G2 x,
G = G1 & z ~ T & G2 →
z \notin fv_ctx_types G1 →
ok (G1 & x ~ subst_typ z (pvar x) T & z ~ T & G2) →
x; bs; G1 & x ~ subst_typ z (pvar x) T & subst_ctx z (pvar x) G2 ⊢
subst_defs z (pvar x) ds :: subst_typ z (pvar x) U).
Proof.
apply ty_def_mutind; intros; subst.
- constructor.
- pose proof (rename_ty_trm H0 t0 H1).
constructor×.
- specialize (H _ _ _ _ eq_refl H1 H2). simpl in ×. apply× ty_def_new.
eapply tight_bounds_subst in t. eauto.
rewrite subst_open_commut_defs_p in H; try repeat eexists.
rewrite subst_open_commut_typ_p in H; try repeat eexists.
unfold subst_path, subst_avar, subst_var_p in H. case_if.
simpl in H. rewrite List.app_nil_r in H. simpl. auto.
- pose proof (rename_ty_trm H0 t H1). econstructor; eauto.
- constructor×.
- specialize (H0 _ _ _ _ eq_refl H2 H3). specialize (H _ _ _ _ eq_refl H2 H3).
econstructor; eauto. apply× subst_defs_hasnt. rewrite× <- subst_label_of_def.
Qed.
Replace the opening and this variable in definition typing
Lemma rename_defs G x T ds z :
x \notin fv_typ T →
x \notin fv_defs ds →
x \notin fv_ctx_types G →
ok (G & z ~ subst_typ x (pvar z) (open_typ x T) & x ~ open_typ x T) →
x; nil; G & x ~ open_typ x T ⊢ open_defs x ds :: open_typ x T →
z; nil; G & z ~ open_typ z T ⊢ open_defs z ds :: open_typ z T.
Proof.
intros Hn Hn' Hn'' Hok Hx.
assert (G & z ~ open_typ z T = G & z ~ open_typ z T & empty) as Heq by rewrite× concat_empty_r.
assert (G & x ~ open_typ x T = G & x ~ open_typ x T & empty) as Heq' by rewrite× concat_empty_r.
rewrite Heq. rewrite Heq' in Hx. clear Heq Heq'.
assert (open_typ z T = subst_typ x (pvar z) (open_typ x T)) as Heq. {
rewrite open_var_typ_eq. rewrite× <- subst_intro_typ. repeat eexists.
}
repeat rewrite Heq.
assert (open_defs z ds = subst_defs x (pvar z) (open_defs x ds)) as Heq'. {
rewrite open_var_defs_eq. rewrite× <- subst_intro_defs. repeat eexists.
}
repeat rewrite Heq'.
clear Heq Heq'.
assert (empty = subst_ctx x (pvar z) empty) as Heq. {
unfold subst_ctx. rewrite× map_empty.
}
rewrite Heq.
apply× rename_def_defs.
rewrite concat_empty_r. auto.
Qed.
x \notin fv_typ T →
x \notin fv_defs ds →
x \notin fv_ctx_types G →
ok (G & z ~ subst_typ x (pvar z) (open_typ x T) & x ~ open_typ x T) →
x; nil; G & x ~ open_typ x T ⊢ open_defs x ds :: open_typ x T →
z; nil; G & z ~ open_typ z T ⊢ open_defs z ds :: open_typ z T.
Proof.
intros Hn Hn' Hn'' Hok Hx.
assert (G & z ~ open_typ z T = G & z ~ open_typ z T & empty) as Heq by rewrite× concat_empty_r.
assert (G & x ~ open_typ x T = G & x ~ open_typ x T & empty) as Heq' by rewrite× concat_empty_r.
rewrite Heq. rewrite Heq' in Hx. clear Heq Heq'.
assert (open_typ z T = subst_typ x (pvar z) (open_typ x T)) as Heq. {
rewrite open_var_typ_eq. rewrite× <- subst_intro_typ. repeat eexists.
}
repeat rewrite Heq.
assert (open_defs z ds = subst_defs x (pvar z) (open_defs x ds)) as Heq'. {
rewrite open_var_defs_eq. rewrite× <- subst_intro_defs. repeat eexists.
}
repeat rewrite Heq'.
clear Heq Heq'.
assert (empty = subst_ctx x (pvar z) empty) as Heq. {
unfold subst_ctx. rewrite× map_empty.
}
rewrite Heq.
apply× rename_def_defs.
rewrite concat_empty_r. auto.
Qed.