Source file infer.ml
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
(** Generating constraints for type inference and type checking. *)
open Timed
open Common
open Error
open Term
open Print
open Debug
open Lplib
(** Logging function for typing. *)
let log_infr = Logger.make 'i' "infr" "type inference/checking"
let log_infr = log_infr.pp
(** Given a meta [m] of type [Πx1:a1,..,Πxn:an,b], [set_to_prod d p m] sets
[m] to a product term of the form [Πy:m1[x1;..;xn],m2[x1;..;xn;y]] with
[m1] and [m2] fresh metavariables, and adds these metavariables to [p].
[d] is the call depth used for debug. *)
let set_to_prod : int -> problem -> meta -> unit = fun d p m ->
let n = m.meta_arity in
let env, s = Env.of_prod_nth [] n !(m.meta_type) in
let vs = Env.vars env in
let xs = Array.map _Vari vs in
let u1 = Env.to_prod env _Type in
let m1 = LibMeta.fresh p u1 n in
let a = _Meta m1 xs in
let y = new_tvar "y" in
let env' = Env.add y (_Meta m1 xs) None env in
let u2 = Env.to_prod env' (lift s) in
let m2 = LibMeta.fresh p u2 (n+1) in
let b = Bindlib.bind_var y (_Meta m2 (Array.append xs [|_Vari y|])) in
let r = _Prod a b in
if Logger.log_enabled () then
log_infr (Color.red "%a%a ≔ %a") D.depth d
pp_meta m pp_term (Bindlib.unbox r);
LibMeta.set p m (Bindlib.unbox (Bindlib.bind_mvar vs r))
(** [conv d p c a b] adds the the constraint [(c,a,b)] in [p], if [a] and
[b] are not convertible. [d] is the call depth used for debug. *)
let conv : int -> problem -> ctxt -> term -> term -> unit = fun d p c a b ->
if not (Eval.pure_eq_modulo c a b) then begin
let cstr = (c,a,b) in
if Logger.log_enabled () then
log_infr (Color.mag "%aadd %a") D.depth d pp_constr cstr;
p := {!p with to_solve = cstr::!p.to_solve}
end
(** Exception that may be raised by type inference. *)
exception NotTypable
(** [infer d p c t] tries to infer a type for the term [t] in context [c],
possibly adding new unification constraints in [p]. The set of
metavariables of [p] are updated if some metavariables are instantiated or
created. The returned type is well-sorted if the recorded constraints are
satisfied. [c] must be well sorted. [d] is the call depth used for debug.
@raise NotTypable when the term is not typable (when encountering an
abstraction over a kind). *)
let rec infer : int -> problem -> ctxt -> term -> term = fun d p c t ->
let return v =
if Logger.log_enabled () then log_infr "%agot %a" D.depth d pp_term v; v
in
if Logger.log_enabled () then
log_infr "%ainfer %a%a" D.depth d pp_ctxt c pp_term t;
match unfold t with
| Patt(_,_,_) -> assert false
| TEnv(_,_) -> assert false
| Kind -> assert false
| Wild -> assert false
| TRef(_) -> assert false
| Type -> return mk_Kind
| Vari x -> (try return (Ctxt.type_of x c) with Not_found -> assert false)
| Symb s -> return !(s.sym_type)
| Prod(a,b) ->
check (d+1) p c a mk_Type;
let _,b,c' = Ctxt.unbind c a None b in
let s = infer (d+1) p c' b in
begin match unfold s with
| (Type | Kind) as s -> s
| _ -> conv d p c' s mk_Type; mk_Type
end
| Abst(a,t) ->
check (d+1) p c a mk_Type;
let x,t,c' = Ctxt.unbind c a None t in
let b = infer (d+1) p c' t in
begin match unfold b with
| Kind ->
wrn None "Abstraction on [%a] is not allowed." Print.pp_term t;
raise NotTypable
| _ -> return (mk_Prod(a, Bindlib.unbox (Bindlib.bind_var x (lift b))))
end
| Appl(t,u) ->
let rec get_prod f typ =
match unfold typ with
| Prod(a,b) -> (a,b)
| Meta(m,_) -> set_to_prod d p m; get_prod f typ
| _ -> f typ
in
let get_prod_whnf =
get_prod (fun typ ->
let a = LibMeta.make p c mk_Type in
let b = LibMeta.make_codomain p c a in
conv d p c typ (mk_Prod(a,b)); (a,b)) in
let get_prod =
get_prod (fun typ -> get_prod_whnf (Eval.whnf c typ)) in
let a, b = get_prod (infer (d+1) p c t) in
check (d+1) p c u a;
return (Bindlib.subst b u)
| LLet(a,t,u) ->
check (d+1) p c a mk_Type;
check (d+1) p c t a;
let x,u,c' = Ctxt.unbind c a (Some t) u in
let b = infer (d+1) p c' u in
begin match unfold b with
| Kind ->
wrn None "Abstraction on [%a] is not allowed." Print.pp_term u;
raise NotTypable
| _ ->
let s = infer (d+1) p c' b in
begin match unfold s with
| Type | Kind -> ()
| _ -> conv d p c' s mk_Type
end;
let b = Bindlib.unbox (Bindlib.bind_var x (lift b)) in
return (mk_LLet(a,t,b))
end
| Meta(m,ts) ->
let s = Term.create_sym (Sign.current_path()) Privat Const
Eager true ("?" ^ LibMeta.name m) !(m.meta_type) [] in
if Logger.log_enabled () then
log_infr "%areplace meta by fresh symbol" D.depth d;
infer d p c
(Array.fold_left (fun acc t -> mk_Appl(acc,t)) (mk_Symb s) ts)
(** [check d c t a] checks that the term [t] has type [a] in context [c],
possibly adding new unification constraints in [p]. [c] must be
well-formed and [a] well-sorted. [d] is the call depth used for debug.
@raise NotTypable when the term is not typable (when encountering an
abstraction over a kind). *)
and check : int -> problem -> ctxt -> term -> term -> unit = fun d p c t a ->
if Logger.log_enabled () then
log_infr "%acheck %a" D.depth d pp_typing (c, t, a);
conv d p c (infer (d+1) p c t) a
let infer =
let open Stdlib in let r = ref mk_Kind in fun d p c t ->
Debug.(record_time Typing (fun () -> r := infer d p c t)); !r
let check d p c t a = Debug.(record_time Typing (fun () -> check d p c t a))
(** [infer_noexn p c t] returns [None] if the type of [t] in context [c]
cannot be inferred, or [Some a] where [a] is some type of [t] in the
context [c], possibly adding new constraints in [p]. The metavariables of
[p] are updated when a metavariable is instantiated or created. [c] must
be well sorted. *)
let infer_noexn : problem -> ctxt -> term -> term option = fun p c t ->
try
if Logger.log_enabled () then
log_hndl (Color.blu "infer_noexn %a%a") pp_ctxt c pp_term t;
let a = time_of "infer" (fun () -> infer 0 p c t) in
if Logger.log_enabled () then
log_hndl (Color.blu "@[<v2>@[result of infer_noexn:@ %a@]%a@]")
pp_term a
(fun fmt constraints -> if constraints <> [] then
Format.fprintf fmt ";@ @[constraints:@ %a@]" pp_constrs constraints)
!p.to_solve;
Some a
with NotTypable -> None
(** [check_noexn p c t a] tells whether the term [t] has type [a] in the
context [c], possibly adding new constraints in |p]. The metavariables of
[p] are updated when a metavariable is instantiated or created. The context
[c] and the type [a] must be well sorted. *)
let check_noexn : problem -> ctxt -> term -> term -> bool = fun p c t a ->
try
if Logger.log_enabled () then
log_hndl (Color.blu "check_noexn %a") pp_typing (c, t, a);
time_of "check" (fun () -> check 0 p c t a);
if Logger.log_enabled () && !p.to_solve <> [] then
log_hndl (Color.blu "result of check_noexn:%a") pp_constrs !p.to_solve;
true
with NotTypable -> false
(** Given a meta [m] of type [Πx1:a1,..,Πxn:an,b], [set_to_prod p m] sets
[m] to a product term of the form [Πy:m1[x1;..;xn],m2[x1;..;xn;y]] with
[m1] and [m2] fresh metavariables, and adds these metavariables to [p]. *)
let set_to_prod = set_to_prod 0