aboutsummaryrefslogtreecommitdiff
path: root/src/Compilers/TypeInversion.v
blob: ab00a1dc578be666920dc277ae4558f0c72585be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
Require Import Crypto.Compilers.Syntax.
Require Import Crypto.Util.FixCoqMistakes.

Section language.
  Context {base_type_code : Type}.

  Section flat.
    Context (P : flat_type base_type_code -> Type).

    Local Ltac t :=
      let H := fresh in
      intro H; intros;
      match goal with
      | [ p : _ |- _ ] => specialize (H _ p)
      end;
      cbv beta iota in *;
      try specialize (H eq_refl); simpl in *;
      try assumption.

    Definition preinvert_Tbase (Q : forall t, P (Tbase t) -> Type)
      : (forall t (p : P t), match t return P t -> Type with Tbase _ => Q _ | _ => fun _ => True end p)
        -> forall t p, Q t p.
    Proof. t. Defined.

    Definition preinvert_Unit (Q : P Unit -> Type)
      : (forall t (p : P t), match t return P t -> Type with Unit => Q | _ => fun _ => True end p)
        -> forall p, Q p.
    Proof. t. Defined.

    Definition preinvert_Prod (Q : forall A B, P (Prod A B) -> Type)
      : (forall t (p : P t), match t return P t -> Type with Prod _ _ => Q _ _ | _ => fun _ => True end p)
        -> forall A B p, Q A B p.
    Proof. t. Defined.

    Definition preinvert_Prod2 (Q : forall A B, P (Prod (Tbase A) (Tbase B)) -> Type)
      : (forall t (p : P t), match t return P t -> Type with Prod (Tbase _) (Tbase _) => Q _ _ | _ => fun _ => True end p)
        -> forall A B p, Q A B p.
    Proof. t. Defined.

    Definition preinvert_Prod2_same (Q : forall A, P (Prod (Tbase A) (Tbase A)) -> Type)
      : (forall t (p : P t), match t return P t -> Type with
                             | Prod (Tbase A) (Tbase B)
                               => fun p => forall pf : A = B, Q B (eq_rect _ (fun a => P (Prod (Tbase a) (Tbase B))) p _ pf)
                             | _ => fun _ => True
                             end p)
        -> forall A p, Q A p.
    Proof. t. Defined.

    Definition preinvert_Prod3 (Q : forall A B C, P (Tbase A * Tbase B * Tbase C)%ctype -> Type)
      : (forall t (p : P t), match t return P t -> Type with Prod (Prod (Tbase _) (Tbase _)) (Tbase _) => Q _ _ _ | _ => fun _ => True end p)
        -> forall A B C p, Q A B C p.
    Proof. t. Defined.

    Definition preinvert_Prod4 (Q : forall A B C D, P (Tbase A * Tbase B * Tbase C * Tbase D)%ctype -> Type)
      : (forall t (p : P t), match t return P t -> Type with Prod (Prod (Prod (Tbase _) (Tbase _)) (Tbase _)) (Tbase _) => Q _ _ _ _ | _ => fun _ => True end p)
        -> forall A B C D p, Q A B C D p.
    Proof. t. Defined.
  End flat.

  Definition preinvert_Arrow (P : type base_type_code -> Type) (Q : forall A B, P (Arrow A B) -> Type)
    : (forall t (p : P t), match t return P t -> Type with
                           | Arrow A B => Q A B
                           end p)
      -> forall A B p, Q A B p.
  Proof.
    intros H A B p; specialize (H _ p); assumption.
  Defined.

  Section encode_decode.
    Definition flat_type_code (t1 t2 : flat_type base_type_code) : Prop
      := match t1, t2 with
         | Unit, Unit => True
         | Tbase t1, Tbase t2 => t1 = t2
         | Prod A B, Prod A' B' => A = A' /\ B = B'
         | Unit, _
         | Tbase _, _
         | Prod _ _, _
           => False
         end.

    Definition type_code (t1 t2 : type base_type_code) : Prop
      := domain t1 = domain t2 /\ codomain t1 = codomain t2.

    Definition flat_type_encode (x y : flat_type base_type_code) : x = y -> flat_type_code x y.
    Proof. intro p; destruct p, x; repeat constructor. Defined.
    Definition type_encode (x y : type base_type_code) : x = y -> type_code x y.
    Proof. intro p; destruct p, x; repeat constructor. Defined.

    Definition flat_type_decode (x y : flat_type base_type_code) : flat_type_code x y -> x = y.
    Proof.
      destruct x, y; simpl in *; intro H;
        try first [ apply f_equal; assumption
                  | exfalso; assumption
                  | reflexivity
                  | apply f_equal2; destruct H; assumption ].
    Defined.
    Definition type_decode (x y : type base_type_code) : type_code x y -> x = y.
    Proof.
      destruct x, y; simpl; intro H;
        try first [ exfalso; assumption
                  | apply f_equal; assumption
                  | apply f_equal2; destruct H; assumption ].
    Defined.
    Definition path_flat_type_rect {x y : flat_type base_type_code} (Q : x = y -> Type)
               (f : forall p, Q (flat_type_decode x y p))
      : forall p, Q p.
    Proof. intro p; specialize (f (flat_type_encode x y p)); destruct x, p; exact f. Defined.
    Definition path_type_rect {x y : type base_type_code} (Q : x = y -> Type)
               (f : forall p, Q (type_decode x y p))
      : forall p, Q p.
    Proof. intro p; specialize (f (type_encode x y p)); destruct x, p; exact f. Defined.
  End encode_decode.
End language.

Ltac preinvert_one_type e :=
  lazymatch type of e with
  | ?P (Tbase ?T)
    => is_var T;
       move e at top;
       revert dependent T;
       refine (preinvert_Tbase P _ _)
  | ?P (Prod (Tbase ?A) (Tbase ?A))
    => is_var A;
       move e at top; revert dependent A;
       refine (preinvert_Prod2_same P _ _)
  | ?P (Prod (Tbase ?A) (Tbase ?B))
    => is_var A; is_var B;
       move e at top; revert dependent A; intros A e;
       move e at top; revert dependent B; revert A;
       refine (preinvert_Prod2 P _ _)
  | ?P (Prod (Prod (Tbase ?A) (Tbase ?B)) (Tbase ?C))
    => is_var A; is_var B; is_var C;
       move e at top; revert dependent A; intros A e;
       move e at top; revert dependent B; intros B e;
       move e at top; revert dependent C; revert A B;
       refine (preinvert_Prod3 P _ _)
  | ?P (Prod (Prod (Prod (Tbase ?A) (Tbase ?B)) (Tbase ?C)) (Tbase ?D))
    => is_var A; is_var B; is_var C; is_var D;
       move e at top; revert dependent A; intros A e;
       move e at top; revert dependent B; intros B e;
       move e at top; revert dependent C; intros C e;
       move e at top; revert dependent D; revert A B C;
       refine (preinvert_Prod4 P _ _)
  | ?P (Prod ?A ?B)
    => is_var A; is_var B;
       move e at top; revert dependent A; intros A e;
       move e at top; revert dependent B; revert A;
       refine (preinvert_Prod P _ _)
  | ?P Unit
    => revert dependent e;
       refine (preinvert_Unit P _ _)
  | ?P (Arrow ?A ?B)
    => is_var A; is_var B;
       move e at top; revert dependent A; intros A e;
       move e at top; revert dependent B; revert A;
       refine (preinvert_Arrow P _ _)
  end.

Ltac induction_type_in_using H rect :=
  induction H as [H] using (rect _ _ _);
  cbv [flat_type_code type_code] in H;
  let H1 := fresh H in
  let H2 := fresh H in
  try lazymatch type of H with
      | False => exfalso; exact H
      | True => destruct H
      | _ /\ _ => destruct H as [H1 H2]
      end.
Ltac inversion_flat_type_step :=
  lazymatch goal with
  | [ H : _ = Tbase _ |- _ ]
    => induction_type_in_using H @path_flat_type_rect
  | [ H : Tbase _ = _ |- _ ]
    => induction_type_in_using H @path_flat_type_rect
  | [ H : _ = Prod _ _ |- _ ]
    => induction_type_in_using H @path_flat_type_rect
  | [ H : Prod _ _ = _ |- _ ]
    => induction_type_in_using H @path_flat_type_rect
  | [ H : _ = Unit |- _ ]
    => induction_type_in_using H @path_flat_type_rect
  | [ H : Unit = _ |- _ ]
    => induction_type_in_using H @path_flat_type_rect
  end.
Ltac inversion_flat_type := repeat inversion_flat_type_step.

Ltac inversion_type_step :=
  lazymatch goal with
  | [ H : _ = Arrow _ _ |- _ ]
    => induction_type_in_using H @path_type_rect
  | [ H : Arrow _ _ = _ |- _ ]
    => induction_type_in_using H @path_type_rect
  end.
Ltac inversion_type := repeat inversion_type_step.