Source file sr.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
(** Checking that a rule preserves typing (subject reduction property). *)
open Lplib
open Timed
open Common open Error
open Core open Term open Print
(** Logging function for typing. *)
let log_subj = Logger.make 's' "subj" "subject-reduction"
let log_subj = log_subj.pp
(** [build_meta_type p k] builds the type “Πx1:A1,⋯,xk:Ak,A(k+1)” where the
type “Ai = Mi[x1,⋯,x(i-1)]” is defined as the metavariable “Mi” which has
arity “i-1” and type “Π(x1:A1) ⋯ (x(i-1):A(i-1)), TYPE”, and adds the
metavariables in [p]. *)
let build_meta_type : problem -> int -> term = fun p k ->
assert (k >= 0);
let xs = Array.init k (new_var_ind "x") in
let ts = Array.map mk_Vari xs in
let ty_m = Array.make (k+1) mk_Type in
for i = 0 to k do
for j = (i-1) downto 0 do
ty_m.(i) <- mk_Prod (ty_m.(j), bind_var xs.(j) ty_m.(i))
done
done;
let f i = mk_Meta (LibMeta.fresh p ty_m.(i) i, Array.sub ts 0 i) in
let a = Array.init (k+1) f in
let res = ref a.(k) in
for i = k - 1 downto 0 do
res := mk_Prod (a.(i), bind_var xs.(i) !res)
done;
!res
(** [symb_to_patt pos map names arities t] replaces in [t] every symbol [f]
such that [SymMap.find f map = Some(i)] by [Patt(i,names.(i),_)]. *)
let symb_to_patt : Pos.popt -> int option SymMap.t -> string array
-> int array -> term -> term =
fun pos map names arities ->
let rec symb_to_patt t =
let (h, ts) = get_args t in
let ts = List.map symb_to_patt ts in
let (h, ts) =
match h with
| Symb(f) ->
begin match SymMap.find_opt f map with
| Some None ->
fatal pos "Bug. Introduced symbol [%s] cannot be removed. \
Please contact the developers." f.sym_name
| Some(Some(i)) ->
let (ts1, ts2) = List.cut ts arities.(i) in
(mk_Patt (Some i, names.(i), Array.of_list ts1), ts2)
| None -> (mk_Symb f, ts)
end
| Vari(x) -> (mk_Vari x, ts)
| Type -> (mk_Type , ts)
| Kind -> (mk_Kind , ts)
| Abst(a,b) ->
let (x, t) = unbind b in
let b = bind_var x (symb_to_patt t) in
(mk_Abst (symb_to_patt a, b), ts)
| Prod(a,b) ->
let (x, t) = unbind b in
let b = bind_var x (symb_to_patt t) in
(mk_Prod (symb_to_patt a, b), ts)
| LLet(a,t,b) ->
let (x, u) = unbind b in
let b = bind_var x (symb_to_patt u) in
(mk_LLet (symb_to_patt a, symb_to_patt t, b), ts)
| Meta(_,_) ->
fatal pos "A metavariable could not be instantiated in the RHS."
| Plac _ ->
fatal pos "A placeholder hasn't been instantiated in the RHS."
| Bvar _ -> assert false
| Appl(_,_) -> assert false
| Patt(_,_,_) -> assert false
| Wild -> assert false
| TRef(_) -> assert false
in
add_args h ts
in
symb_to_patt
(** [check_rule r] checks whether the rule [r] preserves typing. *)
let check_rule : Pos.popt -> sym_rule -> sym_rule =
fun pos ((s,({lhs;names;rhs;arities;vars_nb;xvars_nb;_} as r)) as sr) ->
assert (xvars_nb = 0);
if Logger.log_enabled () then log_subj (Color.red "%a") sym_rule sr;
LibMeta.reset_meta_counter();
let p = new_problem() in
let metas =
Array.init vars_nb
(fun i ->
let arity = arities.(i) in
LibMeta.fresh p (build_meta_type p arity) arity)
in
let f m =
let xs = Array.init m.meta_arity (new_var_ind "x") in
let ts = Array.map mk_Vari xs in
Some(bind_mvar xs (mk_Meta (m, ts)))
in
let su = Array.map f metas in
let lhs_with_metas = subst_patt su (add_args (mk_Symb s) lhs)
and rhs_with_metas = subst_patt su rhs in
if Logger.log_enabled () then
log_subj "replace pattern variables by metavariables:@ %a ↪ %a"
term lhs_with_metas term rhs_with_metas;
match Infer.infer_noexn p [] lhs_with_metas with
| None -> fatal pos "The LHS is not typable."
| Some (lhs_with_metas, ty_lhs) ->
if not (Unif.solve_noexn ~type_check:false p) then
fatal pos "The LHS is not typable.";
let norm_constr (c,t,u) = (c, Eval.snf [] t, Eval.snf [] u) in
let lhs_constrs = List.map norm_constr !p.unsolved in
if Logger.log_enabled () then
log_subj "@[<v>LHS type: %a@ LHS constraints: %a@ rule: %a ↪ %a@]"
term ty_lhs constrs lhs_constrs
term lhs_with_metas term rhs_with_metas;
let map = Stdlib.ref SymMap.empty
and m2s = Stdlib.ref MetaMap.empty in
let instantiate m =
match !(m.meta_value) with
| Some _ -> assert false
| None ->
let s =
let name = Pos.none @@ Printf.sprintf "$%d" m.meta_key in
Term.create_sym (Sign.current_path())
Privat Defin Eager false name None !(m.meta_type) []
in
Stdlib.(map := SymMap.add s None !map; m2s := MetaMap.add m s !m2s);
let xs = Array.init m.meta_arity (new_var_ind "x") in
let s = mk_Symb s in
let def = Array.fold_left (fun t x -> mk_Appl (t, mk_Vari x)) s xs in
m.meta_value := Some(bind_mvar xs def)
in
MetaSet.iter instantiate !p.metas;
let f i m =
match MetaMap.find_opt m Stdlib.(!m2s) with
| Some s -> Stdlib.(map := SymMap.add s (Some i) !map)
| None -> ()
in
Array.iteri f metas;
if Logger.log_enabled () then
log_subj "replace LHS metavariables by function symbols:@ %a ↪ %a"
term lhs_with_metas term rhs_with_metas;
let p = new_problem() in
match Infer.check_noexn p [] rhs_with_metas ty_lhs with
| None -> fatal pos "The RHS does not have the same type as the LHS."
| Some rhs_with_metas ->
if not (Unif.solve_noexn p) then
fatal pos "The rewriting rule does not preserve typing.";
let rhs_constrs = List.map norm_constr !p.unsolved in
let matches p t =
let rec matches s l =
match l with
| [] -> ()
| (p,t)::l ->
match unfold p, unfold t with
| Vari x, _ ->
begin match VarMap.find_opt x s with
| Some u ->
if Eval.eq_modulo [] t u then matches s l else raise Exit
| None -> matches (VarMap.add x t s) l
end
| Symb f, Symb g when f == g -> matches s l
| Appl(t1,u1), Appl(t2,u2) -> matches s ((t1,t2)::(u1,u2)::l)
| _ -> raise Exit
in try matches VarMap.empty [p,t]; true with Exit -> false
in
let is_inst ((_c1,t1,u1) as x1) ((_c2,t2,u2) as x2) =
if Logger.log_enabled() then
log_subj "is_inst [%a] [%a]" constr x1 constr x2;
let cons t u = add_args (mk_Symb Unif_rule.equiv) [t; u] in
matches (cons t1 u1) (cons t2 u2) || matches (cons t1 u1) (cons u2 t2)
in
let is_lhs_constr rc = List.exists (fun lc -> is_inst lc rc) lhs_constrs in
let cs = List.filter (fun rc -> not (is_lhs_constr rc)) rhs_constrs in
if cs <> [] then
begin
List.iter (fatal_msg "Cannot solve %a@." constr) cs;
fatal pos "Unable to prove type preservation."
end;
let rhs = symb_to_patt pos Stdlib.(!map) names arities rhs_with_metas in
s, {r with rhs}