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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
open Names
open UVars
open Util
open Constr
open Declarations
open Declareops
open Conversion
open Inductive
open Modops
open Context
open Mod_subst
type namedobject =
| Constant of constant_body
| IndType of inductive * mutual_inductive_body
| IndConstr of constructor * mutual_inductive_body
| Rules
type namedmodule =
| Module of module_body
| Modtype of module_type_body
let add_mib_nameobjects mp l mib map =
let ind = MutInd.make2 mp l in
let add_mip_nameobjects j oib map =
let ip = (ind,j) in
let map =
Array.fold_right_i
(fun i id map ->
Label.Map.add (Label.of_id id) (IndConstr((ip,i+1), mib)) map)
oib.mind_consnames
map
in
Label.Map.add (Label.of_id oib.mind_typename) (IndType (ip, mib)) map
in
Array.fold_right_i add_mip_nameobjects mib.mind_packets map
type labmap = { objs : namedobject Label.Map.t; mods : namedmodule Label.Map.t }
let empty_labmap = { objs = Label.Map.empty; mods = Label.Map.empty }
let get_obj mp map l =
try Label.Map.find l map.objs
with Not_found -> error_no_such_label_sub l (ModPath.to_string mp)
let get_mod mp map l =
try Label.Map.find l map.mods
with Not_found -> error_no_such_label_sub l (ModPath.to_string mp)
let make_labmap mp list =
let add_one (l,e) map =
match e with
| SFBconst cb -> { map with objs = Label.Map.add l (Constant cb) map.objs }
| SFBrules _ -> { map with objs = Label.Map.add l Rules map.objs }
| SFBmind mib -> { map with objs = add_mib_nameobjects mp l mib map.objs }
| SFBmodule mb -> { map with mods = Label.Map.add l (Module mb) map.mods }
| SFBmodtype mtb -> { map with mods = Label.Map.add l (Modtype mtb) map.mods }
in
CList.fold_right add_one list empty_labmap
let check_conv_error error why state poly pb env a1 a2 =
if poly then match Conversion.default_conv pb env a1 a2 with
| Result.Ok () -> fst state
| Result.Error () -> error (IncompatiblePolymorphism (env, a1, a2))
else match Conversion.generic_conv pb ~l2r:false TransparentState.full env state a1 a2 with
| Result.Ok state -> state
| Result.Error None -> error why
| Result.Error (Some e) -> error (IncompatibleUniverses e)
let check_universes error env u1 u2 =
match u1, u2 with
| Monomorphic, Monomorphic -> env
| Polymorphic auctx1, Polymorphic auctx2 ->
if not (UGraph.check_subtype (Environ.universes env) auctx2 auctx1) then
error (IncompatibleConstraints { got = auctx1; expect = auctx2; } )
else
Environ.push_context ~strict:false (UVars.AbstractContext.repr auctx2) env
| Monomorphic, Polymorphic _ -> error (PolymorphicStatusExpected true)
| Polymorphic _, Monomorphic -> error (PolymorphicStatusExpected false)
let check_variance error v1 v2 =
match v1, v2 with
| None, None -> ()
| Some v1, Some v2 ->
if not (Array.for_all2 Variance.check_subtype v2 v1) then
error IncompatibleVariance
| None, Some _ -> error (CumulativeStatusExpected true)
| Some _, None -> error (CumulativeStatusExpected false)
let squash_info_equal s1 s2 = match s1, s2 with
| AlwaysSquashed, AlwaysSquashed -> true
| SometimesSquashed s1, SometimesSquashed s2 -> Sorts.Quality.Set.equal s1 s2
| (AlwaysSquashed | SometimesSquashed _), _ -> false
let check_inductive (cst, ustate) trace env mp1 l info1 mp2 mib2 subst1 subst2 reso1 reso2=
let kn1 = KerName.make mp1 l in
let kn2 = KerName.make mp2 l in
let error why = error_signature_mismatch trace l why in
let check_conv why cst poly pb = check_conv_error error why (cst, ustate) poly pb in
let mib1 =
match info1 with
| IndType ((_,0), mib) -> Declareops.subst_mind_body subst1 mib
| _ -> error (InductiveFieldExpected mib2)
in
let env = check_universes error env mib1.mind_universes mib2.mind_universes in
let () = check_variance error mib1.mind_variance mib2.mind_variance in
let inst = make_abstract_instance (Declareops.inductive_polymorphic_context mib1) in
let mib2 = Declareops.subst_mind_body subst2 mib2 in
let check_inductive_type cst name t1 t2 =
check_conv (NotConvertibleInductiveField name)
cst (inductive_is_polymorphic mib1) CUMUL env t1 t2
in
let check_packet cst p1 p2 =
let check f test why = if not (test (f p1) (f p2)) then error why in
check (fun p -> p.mind_consnames) (Array.equal Id.equal) NotSameConstructorNamesField;
check (fun p -> p.mind_typename) Id.equal NotSameInductiveNameInBlockField;
check (fun p -> p.mind_squashed) (Option.equal squash_info_equal)
(NotConvertibleInductiveField p2.mind_typename);
check (fun p -> p.mind_nrealargs) Int.equal (NotConvertibleInductiveField p2.mind_typename);
let ty1 = type_of_inductive ((mib1, p1), inst) in
let ty2 = type_of_inductive ((mib2, p2), inst) in
let cst = check_inductive_type cst p2.mind_typename ty1 ty2 in
cst
in
let mind = MutInd.make1 kn1 in
let check_cons_types i cst p1 p2 =
Array.fold_left3
(fun cst id t1 t2 -> check_conv (NotConvertibleConstructorField id) cst
(inductive_is_polymorphic mib1) CONV env t1 t2)
cst
p2.mind_consnames
(arities_of_constructors ((mind,i), inst) (mib1, p1))
(arities_of_constructors ((mind,i), inst) (mib2, p2))
in
let check f test why = if not (test (f mib1) (f mib2)) then error (why (f mib2)) in
check (fun mib -> mib.mind_finite<>CoFinite) (==) (fun x -> FiniteInductiveFieldExpected x);
check (fun mib -> mib.mind_ntypes) Int.equal (fun x -> InductiveNumbersFieldExpected x);
assert (List.is_empty mib1.mind_hyps && List.is_empty mib2.mind_hyps);
assert (Array.length mib1.mind_packets >= 1
&& Array.length mib2.mind_packets >= 1);
check (fun mib -> mib.mind_nparams) Int.equal (fun x -> InductiveParamsNumberField x);
begin
let kn2' = kn_of_delta reso2 kn2 in
if KerName.equal kn2 kn2' ||
MutInd.CanOrd.equal (mind_of_delta_kn reso1 kn1)
(subst_mind subst2 (MutInd.make kn2 kn2'))
then ()
else error NotEqualInductiveAliases
end;
(** FIXME: this check looks nonsense *)
check (fun mib -> mib.mind_record <> NotRecord) (==) (fun x -> RecordFieldExpected x);
if mib1.mind_record <> NotRecord then begin
let rec names_prod_letin t = match kind t with
| Prod(n,_,t) -> n.binder_name::(names_prod_letin t)
| LetIn(n,_,_,t) -> n.binder_name::(names_prod_letin t)
| Cast(t,_,_) -> names_prod_letin t
| _ -> []
in
assert (Int.equal (Array.length mib1.mind_packets) 1);
assert (Int.equal (Array.length mib2.mind_packets) 1);
assert (Int.equal (Array.length mib1.mind_packets.(0).mind_user_lc) 1);
assert (Int.equal (Array.length mib2.mind_packets.(0).mind_user_lc) 1);
check (fun mib ->
let nparamdecls = List.length mib.mind_params_ctxt in
let names = names_prod_letin (mib.mind_packets.(0).mind_user_lc.(0)) in
snd (List.chop nparamdecls names)) (List.equal Name.equal)
(fun x -> RecordProjectionsExpected x);
end;
let cst =
Array.fold_left2 check_packet cst mib1.mind_packets mib2.mind_packets
in
let cst =
Array.fold_left2_i check_cons_types cst mib1.mind_packets mib2.mind_packets
in
cst
let check_constant (cst, ustate) trace env l info1 cb2 subst1 subst2 =
let error why = error_signature_mismatch trace l why in
let check_conv why cst poly pb = check_conv_error error why (cst, ustate) poly pb in
let check_type poly cst env t1 t2 =
let err = NotConvertibleTypeField (env, t1, t2) in
check_conv err cst poly CUMUL env t1 t2
in
match info1 with
| IndType _ | IndConstr _ | Rules -> error DefinitionFieldExpected
| Constant cb1 ->
let () = assert (List.is_empty cb1.const_hyps && List.is_empty cb2.const_hyps) in
let cb1 = Declareops.subst_const_body subst1 cb1 in
let cb2 = Declareops.subst_const_body subst2 cb2 in
let env = check_universes error env cb1.const_universes cb2.const_universes in
let poly = Declareops.constant_is_polymorphic cb1 in
let typ1 = cb1.const_type in
let typ2 = cb2.const_type in
let cst = check_type poly cst env typ1 typ2 in
(match cb2.const_body with
| Undef _ | OpaqueDef _ -> cst
| Primitive _ | Symbol _ -> error NotConvertibleBodyField
| Def c2 ->
(match cb1.const_body with
| Primitive _ | Undef _ | OpaqueDef _ | Symbol _ -> error NotConvertibleBodyField
| Def c1 ->
check_conv NotConvertibleBodyField cst poly CONV env c1 c2))
let rec check_modules state trace env msb1 msb2 subst1 subst2 =
let mty1 = module_type_of_module msb1 in
let mty2 = module_type_of_module msb2 in
check_modtypes state trace env mty1 mty2 subst1 subst2 false
and check_signatures (cst, ustate) trace env mp1 sig1 mp2 sig2 subst1 subst2 reso1 reso2 =
let map1 = make_labmap mp1 sig1 in
let check_one_body cst (l,spec2) =
match spec2 with
| SFBconst cb2 ->
check_constant (cst, ustate) trace env l (get_obj mp1 map1 l)
cb2 subst1 subst2
| SFBmind mib2 ->
check_inductive (cst, ustate) trace env mp1 l (get_obj mp1 map1 l)
mp2 mib2 subst1 subst2 reso1 reso2
| SFBrules _ ->
error_signature_mismatch trace l NoRewriteRulesSubtyping
| SFBmodule msb2 ->
begin match get_mod mp1 map1 l with
| Module msb -> check_modules (cst, ustate) (Submodule l :: trace) env msb msb2 subst1 subst2
| _ -> error_signature_mismatch trace l ModuleFieldExpected
end
| SFBmodtype mtb2 ->
let mtb1 = match get_mod mp1 map1 l with
| Modtype mtb -> mtb
| _ -> error_signature_mismatch trace l ModuleTypeFieldExpected
in
let env =
add_module_type mtb2.mod_mp mtb2
(add_module_type mtb1.mod_mp mtb1 env)
in
check_modtypes (cst, ustate) (Submodule l :: trace) env mtb1 mtb2 subst1 subst2 true
in
List.fold_left check_one_body cst sig2
and check_modtypes (cst, ustate) trace env mtb1 mtb2 subst1 subst2 equiv =
if mtb1==mtb2 || mtb1.mod_type == mtb2.mod_type then cst
else
let rec check_structure cst ~nargs env struc1 struc2 equiv subst1 subst2 =
match struc1,struc2 with
| NoFunctor list1,
NoFunctor list2 ->
if equiv then
let subst2 = add_mp mtb2.mod_mp mtb1.mod_mp mtb1.mod_delta subst2 in
let cst = check_signatures (cst, ustate) trace env
mtb1.mod_mp list1 mtb2.mod_mp list2 subst1 subst2
mtb1.mod_delta mtb2.mod_delta
in
let cst = check_signatures (cst, ustate) trace env
mtb2.mod_mp list2 mtb1.mod_mp list1 subst2 subst1
mtb2.mod_delta mtb1.mod_delta
in
cst
else
check_signatures (cst, ustate) trace env
mtb1.mod_mp list1 mtb2.mod_mp list2 subst1 subst2
mtb1.mod_delta mtb2.mod_delta
| MoreFunctor (arg_id1,arg_t1,body_t1),
MoreFunctor (arg_id2,arg_t2,body_t2) ->
let mp2 = MPbound arg_id2 in
let subst1 = join (map_mbid arg_id1 mp2 arg_t2.mod_delta) subst1 in
let env = add_module_type mp2 arg_t2 env in
let cst = check_modtypes (cst, ustate) (FunctorArgument (nargs+1) :: trace) env arg_t2 arg_t1 subst2 subst1 equiv in
let env =
if Modops.is_functor body_t1 then env
else add_module
{mod_mp = mtb1.mod_mp;
mod_expr = ModBodyVal Abstract;
mod_type = subst_signature subst1 body_t1;
mod_type_alg = None;
mod_retroknowledge = ModBodyVal [];
mod_delta = mtb1.mod_delta} env
in
check_structure cst ~nargs:(nargs + 1) env body_t1 body_t2 equiv subst1 subst2
| _ , _ -> error_incompatible_modtypes mtb1 mtb2
in
check_structure cst ~nargs:0 env mtb1.mod_type mtb2.mod_type equiv subst1 subst2
let check_subtypes state env sup super =
let env = add_module_type sup.mod_mp sup env in
check_modtypes state [] env
(strengthen sup sup.mod_mp) super empty_subst
(map_mp super.mod_mp sup.mod_mp sup.mod_delta) false