summaryrefslogtreecommitdiff
path: root/toplevel/class.ml
diff options
context:
space:
mode:
Diffstat (limited to 'toplevel/class.ml')
-rw-r--r--toplevel/class.ml460
1 files changed, 460 insertions, 0 deletions
diff --git a/toplevel/class.ml b/toplevel/class.ml
new file mode 100644
index 00000000..429469b1
--- /dev/null
+++ b/toplevel/class.ml
@@ -0,0 +1,460 @@
+(************************************************************************)
+(* 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.2 2004/07/16 19:31:47 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 a = match kind_of_term a with
+ | Sort (Prop _ | Type _) -> 0
+ | Prod (_,_,c) -> (arity_sort c) +1
+ | LetIn (_,_,_,c) -> arity_sort c (* Utile ?? *)
+ | Cast (c,_) -> arity_sort c
+ | _ -> raise Not_found
+
+let check_reference_arity ref =
+ try arity_sort (Global.type_of_global ref)
+ 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)