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
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
|
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
(* $Id: class.ml,v 1.44.2.3 2004/11/26 18:06:54 herbelin Exp $ *)
open Util
open Pp
open Names
open Nameops
open Term
open Termops
open Inductive
open Declarations
open Entries
open Environ
open Inductive
open Lib
open Classops
open Declare
open Libnames
open Nametab
open Decl_kinds
open Safe_typing
let strength_min4 stre1 stre2 stre3 stre4 =
strength_min ((strength_min (stre1,stre2)),(strength_min (stre3,stre4)))
let id_of_varid c = match kind_of_term c with
| Var id -> id
| _ -> anomaly "class__id_of_varid"
(* lf liste des variable dont depend la coercion f
lc liste des variable dont depend la classe source *)
let rec stre_unif_cond = function
| ([],[]) -> Global
| (v::l,[]) -> variable_strength v
| ([],v::l) -> variable_strength v
| (v1::l1,v2::l2) ->
if v1=v2 then
stre_unif_cond (l1,l2)
else
let stre1 = (variable_strength v1)
and stre2 = (variable_strength v2) in
strength_min (stre1,stre2)
(* Errors *)
type coercion_error_kind =
| AlreadyExists
| NotAFunction
| NoSource of cl_typ option
| ForbiddenSourceClass of cl_typ
| NotUniform
| NoTarget
| WrongTarget of cl_typ * cl_typ
| NotAClass of global_reference
| NotEnoughClassArgs of cl_typ
exception CoercionError of coercion_error_kind
let explain_coercion_error g = function
| AlreadyExists ->
(Printer.pr_global g ++ str" is already a coercion")
| NotAFunction ->
(Printer.pr_global g ++ str" is not a function")
| NoSource (Some cl) ->
(str "Cannot recognize " ++ pr_class cl ++ str " as a source class of "
++ Printer.pr_global g)
| NoSource None ->
(str ": cannot find the source class of " ++ Printer.pr_global g)
| ForbiddenSourceClass cl ->
pr_class cl ++ str " cannot be a source class"
| NotUniform ->
(Printer.pr_global g ++
str" does not respect the inheritance uniform condition");
| NoTarget ->
(str"Cannot find the target class")
| WrongTarget (clt,cl) ->
(str"Found target class " ++ pr_class cl ++
str " instead of " ++ pr_class clt)
| NotAClass ref ->
(str "Type of " ++ Printer.pr_global ref ++
str " does not end with a sort")
| NotEnoughClassArgs cl ->
(str"Wrong number of parameters for " ++ pr_class cl)
(* Verifications pour l'ajout d'une classe *)
let rec arity_sort (ctx,a) = match kind_of_term a with
| Sort (Prop _ | Type _) -> List.length ctx
| _ -> raise Not_found
let check_reference_arity ref =
let t = Global.type_of_global ref in
try arity_sort (Reductionops.splay_prod (Global.env()) Evd.empty t)
with Not_found -> raise (CoercionError (NotAClass ref))
let check_arity = function
| CL_FUN | CL_SORT -> 0
| CL_CONST sp -> check_reference_arity (ConstRef sp)
| CL_SECVAR sp -> check_reference_arity (VarRef sp)
| CL_IND sp -> check_reference_arity (IndRef sp)
(* try_add_class : cl_typ -> strength option -> bool -> unit *)
let strength_of_cl = function
| CL_CONST kn -> constant_strength (sp_of_global (ConstRef kn))
| CL_SECVAR sp -> variable_strength sp
| _ -> Global
let try_add_class cl streopt fail_if_exists =
if not (class_exists cl) then
let p = check_arity cl in
let stre' = strength_of_cl cl in
let stre = match streopt with
| Some stre -> strength_min (stre,stre')
| None -> stre'
in
declare_class (cl,stre,p)
else
if fail_if_exists then errorlabstrm "try_add_new_class"
(pr_class cl ++ str " is already a class")
(* Coercions *)
(* check that the computed target is the provided one *)
let check_target clt = function
| Some cl when cl <> clt -> raise (CoercionError (WrongTarget(clt,cl)))
| _ -> ()
(* condition d'heritage uniforme *)
let uniform_cond nargs lt =
let rec aux = function
| (0,[]) -> true
| (n,t::l) -> (strip_outer_cast t = mkRel n) & (aux ((n-1),l))
| _ -> false
in
aux (nargs,lt)
let id_of_cl = function
| CL_FUN -> id_of_string "FUNCLASS"
| CL_SORT -> id_of_string "SORTCLASS"
| CL_CONST kn -> id_of_label (label kn)
| CL_IND ind ->
let (_,mip) = Global.lookup_inductive ind in
mip.mind_typename
| CL_SECVAR id -> id
let class_of_ref = function
| ConstRef sp -> CL_CONST sp
| IndRef sp -> CL_IND sp
| VarRef id -> CL_SECVAR id
| ConstructRef _ as c ->
errorlabstrm "class_of_ref"
(str "Constructors, such as " ++ Printer.pr_global c ++
str " cannot be used as class")
(*
lp est la liste (inverse'e) des arguments de la coercion
ids est le nom de la classe source
sps_opt est le sp de la classe source dans le cas des structures
retourne:
la classe source
nbre d'arguments de la classe
le constr de la class
la liste des variables dont depend la classe source
l'indice de la classe source dans la liste lp
*)
let get_source lp source =
match source with
| None ->
let (cl1,lv1) =
match lp with
| [] -> raise Not_found
| t1::_ -> find_class_type t1
in
(cl1,lv1,1)
| Some cl ->
let rec aux = function
| [] -> raise Not_found
| t1::lt ->
try
let cl1,lv1 = find_class_type t1 in
if cl = cl1 then cl1,lv1,(List.length lt+1)
else raise Not_found
with Not_found -> aux lt
in aux (List.rev lp)
let get_target t ind =
if (ind > 1) then
CL_FUN
else
fst (find_class_type t)
let prods_of t =
let rec aux acc d = match kind_of_term d with
| Prod (_,c1,c2) -> aux (c1::acc) c2
| Cast (c,_) -> aux acc c
| _ -> (d,acc)
in
aux [] t
let get_strength stre ref cls clt =
let stres = (snd (class_info cls)).cl_strength in
let stret = (snd (class_info clt)).cl_strength in
let stref = strength_of_global ref in
(* 01/00: Supprimé la prise en compte de la force des variables locales. Sens ?
let streunif = stre_unif_cond (s_vardep,f_vardep) in
*)
let streunif = Global in
let stre' = strength_min4 stres stret stref streunif in
strength_min (stre,stre')
(* coercion identité *)
let error_not_transparent source =
errorlabstrm "build_id_coercion"
(pr_class source ++ str " must be a transparent constant")
let build_id_coercion idf_opt source =
let env = Global.env () in
let vs = match source with
| CL_CONST sp -> mkConst sp
| _ -> error_not_transparent source in
let c = match constant_opt_value env (destConst vs) with
| Some c -> c
| None -> error_not_transparent source in
let lams,t = Sign.decompose_lam_assum c in
let val_f =
it_mkLambda_or_LetIn
(mkLambda (Name (id_of_string "x"),
applistc vs (extended_rel_list 0 lams),
mkRel 1))
lams
in
let typ_f =
it_mkProd_wo_LetIn
(mkProd (Anonymous, applistc vs (extended_rel_list 0 lams), lift 1 t))
lams
in
(* juste pour verification *)
let _ =
if not
(Reductionops.is_conv_leq env Evd.empty
(Typing.type_of env Evd.empty val_f) typ_f)
then
error ("cannot be defined as coercion - "^
"maybe a bad number of arguments")
in
let idf =
match idf_opt with
| Some idf -> idf
| None ->
id_of_string ("Id_"^(string_of_class source)^"_"^
(string_of_class (fst (find_class_type t))))
in
let constr_entry = (* Cast is necessary to express [val_f] is identity *)
DefinitionEntry
{ const_entry_body = mkCast (val_f, typ_f);
const_entry_type = Some typ_f;
const_entry_opaque = false } in
let (_,kn) = declare_constant idf (constr_entry,Decl_kinds.IsDefinition) in
ConstRef kn
let check_source = function
| Some (CL_FUN|CL_SORT as s) -> raise (CoercionError (ForbiddenSourceClass s))
| _ -> ()
(*
nom de la fonction coercion
strength de f
nom de la classe source (optionnel)
sp de la classe source (dans le cas des structures)
nom de la classe target (optionnel)
booleen "coercion identite'?"
lorque source est None alors target est None aussi.
*)
let add_new_coercion_core coef stre source target isid =
check_source source;
let env = Global.env () in
let v = constr_of_reference coef in
let vj = Retyping.get_judgment_of env Evd.empty v in
if coercion_exists coef then raise (CoercionError AlreadyExists);
let tg,lp = prods_of (vj.uj_type) in
let llp = List.length lp in
if llp = 0 then raise (CoercionError NotAFunction);
let (cls,lvs,ind) =
try
get_source lp source
with Not_found ->
raise (CoercionError (NoSource source))
in
check_source (Some cls);
if not (uniform_cond (llp-ind) lvs) then
raise (CoercionError NotUniform);
let clt =
try
get_target tg ind
with Not_found ->
raise (CoercionError NoTarget)
in
check_target clt target;
try_add_class cls None false;
try_add_class clt None false;
let stre' = get_strength stre coef cls clt in
declare_coercion coef vj stre' isid cls clt (List.length lvs)
let try_add_new_coercion_core ref b c d e =
try add_new_coercion_core ref b c d e
with CoercionError e ->
errorlabstrm "try_add_new_coercion_core" (explain_coercion_error ref e)
let try_add_new_coercion ref stre =
try_add_new_coercion_core ref stre None None false
let try_add_new_coercion_subclass cl stre =
let coe_ref = build_id_coercion None cl in
try_add_new_coercion_core coe_ref stre (Some cl) None true
let try_add_new_coercion_with_target ref stre ~source ~target =
try_add_new_coercion_core ref stre (Some source) (Some target) false
let try_add_new_identity_coercion id stre ~source ~target =
let ref = build_id_coercion (Some id) source in
try_add_new_coercion_core ref stre (Some source) (Some target) true
let try_add_new_coercion_with_source ref stre ~source =
try_add_new_coercion_core ref stre (Some source) None false
let add_coercion_hook stre ref =
try_add_new_coercion ref stre;
Options.if_verbose message
(string_of_qualid (shortest_qualid_of_global Idset.empty ref)
^ " is now a coercion")
let add_subclass_hook stre ref =
let cl = class_of_ref ref in
try_add_new_coercion_subclass cl stre
(* try_add_new_class : global_reference -> strength -> unit *)
let class_of_global = function
| VarRef sp -> CL_SECVAR sp
| ConstRef sp -> CL_CONST sp
| IndRef sp -> CL_IND sp
| ConstructRef _ as ref -> raise (CoercionError (NotAClass ref))
let try_add_new_class ref stre =
try try_add_class (class_of_global ref) (Some stre) true
with CoercionError e ->
errorlabstrm "try_add_new_class" (explain_coercion_error ref e)
(* fonctions pour le discharge: encore un peu sale mais ça s'améliore *)
type coercion_entry =
global_reference * strength * bool * cl_typ * cl_typ * int
let add_new_coercion (ref,stre,isid,cls,clt,n) =
(* Un peu lourd, tout cela pour trouver l'instance *)
let env = Global.env () in
let v = constr_of_reference ref in
let vj = Retyping.get_judgment_of env Evd.empty v in
declare_coercion ref vj stre isid cls clt n
let count_extra_abstractions hyps ids_to_discard =
let _,n =
List.fold_left
(fun (hyps,n as sofar) id ->
match hyps with
| (hyp,None,_)::rest when id = hyp ->(rest, n+1)
| _ -> sofar)
(hyps,0) ids_to_discard
in n
let defined_in_sec kn olddir =
let _,dir,_ = repr_kn kn in
dir = olddir
(* This moves the global path one step below *)
let process_global olddir = function
| VarRef _ ->
anomaly "process_global only processes global surviving the section"
| ConstRef kn as x ->
if defined_in_sec kn olddir then
let newkn = Lib.make_kn (id_of_label (label kn)) in
ConstRef newkn
else x
| IndRef (kn,i) as x ->
if defined_in_sec kn olddir then
let newkn = Lib.make_kn (id_of_label (label kn)) in
IndRef (newkn,i)
else x
| ConstructRef ((kn,i),j) as x ->
if defined_in_sec kn olddir then
let newkn = Lib.make_kn (id_of_label (label kn)) in
ConstructRef ((newkn,i),j)
else x
let process_class olddir ids_to_discard x =
let (cl,{cl_strength=stre; cl_param=p}) = x in
(* let env = Global.env () in*)
match cl with
| CL_SECVAR _ -> x
| CL_CONST kn ->
if defined_in_sec kn olddir then
let newkn = Lib.make_kn (id_of_label (label kn)) in
let hyps = (Global.lookup_constant kn).const_hyps in
let n = count_extra_abstractions hyps ids_to_discard in
(CL_CONST newkn,{cl_strength=stre;cl_param=p+n})
else
x
| CL_IND (kn,i) ->
if defined_in_sec kn olddir then
let newkn = Lib.make_kn (id_of_label (label kn)) in
let hyps = (Global.lookup_mind kn).mind_hyps in
let n = count_extra_abstractions hyps ids_to_discard in
(CL_IND (newkn,i),{cl_strength=stre;cl_param=p+n})
else
x
| _ -> anomaly "process_class"
let process_cl sec_sp cl =
match cl with
| CL_SECVAR id -> cl
| CL_CONST kn ->
if defined_in_sec kn sec_sp then
let newkn = Lib.make_kn (id_of_label (label kn)) in
CL_CONST newkn
else
cl
| CL_IND (kn,i) ->
if defined_in_sec kn sec_sp then
let newkn = Lib.make_kn (id_of_label (label kn)) in
CL_IND (newkn,i)
else
cl
| _ -> cl
let process_coercion olddir ids_to_discard (coe,coeinfo,cls,clt) =
let hyps = context_of_global_reference coe in
let nargs = count_extra_abstractions hyps ids_to_discard in
(process_global olddir coe,
coercion_strength coeinfo,
coercion_identity coeinfo,
process_cl olddir cls,
process_cl olddir clt,
nargs + coercion_params coeinfo)
|