(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
(* The following definitions are used by the function [assumptions] which gives as an output the set of all axioms and sections variables on which a given term depends
in a context (expectingly the Global context) *)
(* Initial author: Arnaud Spiwack
Module-traversing code: Pierre Letouzey *)
open Util open Names open Declarations open Mod_declarations
module NamedDecl = Context.Named.Declaration
(** For a constant c in a module sealed by an interface (M:T and not M<:T), [Global.lookup_constant] may return a [constant_body] without body. We fix this by looking in the implementation
of the module *)
let modcache = ref (MPmap.empty : structure_body MPmap.t)
let rec search_mod_label lab = function
| [] -> raise Not_found
| (l, SFBmodule mb) :: _ when Label.equal l lab -> mb
| _ :: fields -> search_mod_label lab fields
let rec search_cst_label lab = function
| [] -> raise Not_found
| (l, SFBconst cb) :: _ when Label.equal l lab -> cb
| _ :: fields -> search_cst_label lab fields
let rec search_mind_label lab = function
| [] -> raise Not_found
| (l, SFBmind mind) :: _ when Label.equal l lab -> mind
| _ :: fields -> search_mind_label lab fields
(* TODO: using [empty_delta_resolver] below is probably slightly incorrect. But: a) I don't see currently what should be used instead b) this shouldn't be critical for Print Assumption. At worse some constants will have a canonical name which is non-canonical, leading to failures in [Global.lookup_constant], but our own [lookup_constant] should work.
*)
let rec fields_of_functor f subs mp0 args = function
| NoFunctor a -> f subs mp0 args a
| MoreFunctor (mbid,_,e) -> letopen Mod_subst in match args with
| [] -> assert false(* we should only encounter applied functors *)
| mpa :: args -> let subs = join (map_mbid mbid mpa (empty_delta_resolver mpa) (*TODO*)) subs in
fields_of_functor f subs mp0 args e
let rec lookup_module_in_impl mp = match mp with
| MPfile _ -> Global.lookup_module mp
| MPbound _ -> Global.lookup_module mp
| MPdot (mp',lab') -> if ModPath.equal mp' (Global.current_modpath ()) then
Global.lookup_module mp else let fields = memoize_fields_of_mp mp' in
search_mod_label lab' fields
and memoize_fields_of_mp mp = try MPmap.find mp !modcache with Not_found -> let l = fields_of_mp mp in
modcache := MPmap.add mp l !modcache;
l
and fields_of_mp mp = letopen Mod_subst in let mb = lookup_module_in_impl mp in let fields,inner_mp,subs = fields_of_mb empty_subst mp mb [] in let delta_mb = mod_delta mb in let subs = (* XXX this code makes little sense, adding a delta_mb to subs if the root does not coincide with mp used to be equivalent to a no-op and now fails with an assertion failure. More likely than not, this means that we have
no idea about what we are doing. *) if ModPath.equal inner_mp mp then subs elseif has_root_delta_resolver mp delta_mb then
add_mp inner_mp mp delta_mb subs else
add_mp inner_mp mp (empty_delta_resolver mp) subs in
Modops.subst_structure subs mp fields
and fields_of_mb subs mp mb args = match Mod_declarations.mod_expr mb with
| Algebraic expr -> fields_of_expression subs mp args (mod_type mb) expr
| Struct sign -> let sign = Modops.annotate_struct_body sign (mod_type mb) in
fields_of_signature subs mp args sign
| Abstract|FullStruct -> fields_of_signature subs mp args (mod_type mb)
(** The Abstract case above corresponds to [Declare Module] *)
and fields_of_signature x =
fields_of_functor
(fun subs mp0 args struc ->
assert (List.is_empty args);
(struc, mp0, subs)) x
and fields_of_expr subs mp0 args = function
| MEident mp -> let mp = Mod_subst.subst_mp subs mp in let mb = lookup_module_in_impl mp in
fields_of_mb subs mp mb args
| MEapply (me1,mp2) -> fields_of_expr subs mp0 (mp2::args) me1
| MEwith _ -> assert false(* no 'with' in [mod_expr] *)
and fields_of_expression subs mp args mty me = let me = Modops.annotate_module_expression me mty in
fields_of_functor fields_of_expr subs mp args me
let lookup_constant_in_impl cst fallback = try let mp,lab = KerName.repr (Constant.canonical cst) in let fields = memoize_fields_of_mp mp in (* A module found this way is necessarily closed, in particular
our constant cannot be in an opened section : *)
search_cst_label lab fields with Not_found -> (* Either: - The module part of the constant isn't registered yet : we're still in it, so the [constant_body] found earlier (if any) was a true axiom.
- The label has not been found in the structure. This is an error *) match fallback with
| Some cb -> cb
| None ->
CErrors.anomaly
Pp.(str "Print Assumption: unknown constant "
++ Constant.print cst ++ str ".")
let lookup_constant cst = let env = Global.env() in ifnot (Environ.mem_constant cst env) then lookup_constant_in_impl cst None else let cb = Environ.lookup_constant cst env in if Declareops.constant_has_body cb then cb else lookup_constant_in_impl cst (Some cb)
let lookup_mind_in_impl mind = try let mp,lab = KerName.repr (MutInd.canonical mind) in let fields = memoize_fields_of_mp mp in
search_mind_label lab fields with Not_found ->
CErrors.anomaly
Pp.(str "Print Assumption: unknown inductive "
++ MutInd.print mind ++ str ".")
let lookup_mind mind = let env = Global.env() in if Environ.mem_mind mind env then Environ.lookup_mind mind env else lookup_mind_in_impl mind
(** Graph traversal of an object, collecting on the way the dependencies of
traversed objects *)
let label_of = letopen GlobRef in function
| ConstRef kn -> Constant.label kn
| IndRef (kn,_)
| ConstructRef ((kn,_),_) -> MutInd.label kn
| VarRef id -> Label.of_id id
let fold_with_full_binders g f n acc c = letopen Context.Rel.Declaration in letopen Constr in match kind c with
| Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _ | Construct _ | Int _ | Float _ | String _ -> acc
| Cast (c,_, t) -> f n (f n acc c) t
| Prod (na,t,c) -> f (g (LocalAssum (na,t)) n) (f n acc t) c
| Lambda (na,t,c) -> f (g (LocalAssum (na,t)) n) (f n acc t) c
| LetIn (na,b,t,c) -> f (g (LocalDef (na,b,t)) n) (f n (f n acc b) t) c
| App (c,l) -> Array.fold_left (f n) (f n acc c) l
| Proj (_,_,c) -> f n acc c
| Evar _ -> assert false
| Case (ci, u, pms, p, iv, c, bl) -> let mib = lookup_mind (fst ci.ci_ind) in let (ci, (p,_), iv, c, bl) = Inductive.expand_case_specif mib (ci, u, pms, p, iv, c, bl) in
Array.fold_left (f n) (f n (fold_invert (f n) (f n acc p) iv) c) bl
| Fix (_,(lna,tl,bl)) -> let n' = CArray.fold_left2_i (fun i c n t -> g (LocalAssum (n,lift i t)) c) n lna tl in let fd = Array.map2 (fun t b -> (t,b)) tl bl in
Array.fold_left (fun acc (t,b) -> f n' (f n acc t) b) acc fd
| CoFix (_,(lna,tl,bl)) -> let n' = CArray.fold_left2_i (fun i c n t -> g (LocalAssum (n,lift i t)) c) n lna tl in let fd = Array.map2 (fun t b -> (t,b)) tl bl in
Array.fold_left (fun acc (t,b) -> f n' (f n acc t) b) acc fd
| Array(_u,t,def,ty) -> f n (f n (Array.fold_left (f n) acc t) def) ty
let get_constant_body access kn = let cb = lookup_constant kn in match cb.const_body with
| Undef _ | Primitive _ | Symbol _ -> None
| Def c -> Some c
| OpaqueDef o -> match Global.force_proof access o with
| c, _ -> Some c
| exception e when CErrors.noncritical e -> None (* missing delayed body, e.g. in vok mode *)
let rec traverse access current ctx accu t = letopen GlobRef in letopen Constr in match Constr.kind t with
| Var id -> let body () = id |> Global.lookup_named |> NamedDecl.get_value in
traverse_object access accu body (VarRef id)
| Const (kn, _) -> let body () = get_constant_body access kn in
traverse_object access accu body (ConstRef kn)
| Ind ((mind, _) as ind, _) ->
traverse_inductive access accu mind (IndRef ind)
| Construct (((mind, _), _) as cst, _) ->
traverse_inductive access accu mind (ConstructRef cst)
| Meta _ | Evar _ -> assert false
| Case (_, _, _, (([|_|], oty),_), _, c, [||]) when Vars.noccurn 1 oty -> (* non dependent match on an inductive with no constructors *) beginmatch Constr.kind c with
| Const (kn, _) when not (Declareops.constant_has_body (lookup_constant kn)) -> let (curr, data, ax2ty) = accu in let obj = ConstRef kn in let already_in = GlobRef.Map_env.mem obj data in let data = ifnot already_in then GlobRef.Map_env.add obj None data else data in let ty = (current, ctx, Vars.subst1 mkProp oty) in let ax2ty = trylet l = GlobRef.Map_env.find obj ax2ty in GlobRef.Map_env.add obj (ty::l) ax2ty with Not_found -> GlobRef.Map_env.add obj [ty] ax2ty in
(GlobRef.Set_env.add obj curr, data, ax2ty)
| _ ->
fold_with_full_binders
Context.Rel.add (traverse access current) ctx accu t end
| _ -> fold_with_full_binders
Context.Rel.add (traverse access current) ctx accu t
and traverse_object access (curr, data, ax2ty) body obj = let data, ax2ty = let already_in = GlobRef.Map_env.mem obj data in if already_in then data, ax2ty elsematch body () (* Beware: this can be very costly *) with
| None ->
GlobRef.Map_env.add obj None data, ax2ty
| Some body -> let contents,data,ax2ty =
traverse access (label_of obj) Context.Rel.empty
(GlobRef.Set_env.empty,data,ax2ty) body in
GlobRef.Map_env.add obj (Some contents) data, ax2ty in
(GlobRef.Set_env.add obj curr, data, ax2ty)
(** Collects the references occurring in the declaration of mutual inductive definitions. All the constructors and names of a mutual inductive definition share exactly the same dependencies. Also, there is no explicit
dependency between mutually defined inductives and constructors. *) and traverse_inductive access (curr, data, ax2ty) mind obj = let firstind_ref = (GlobRef.IndRef (mind, 0)) in let label = label_of obj in let data, ax2ty = (* Invariant : I_0 \in data iff I_i \in data iff c_ij \in data where I_0, I_1, ... are in the same mutual definition and c_ij
are all their constructors. *) if (* recursive call: *) GlobRef.Set_env.mem firstind_ref curr || (* already in: *) GlobRef.Map_env.mem firstind_ref data then data, ax2ty else (* Take into account potential recursivity of ind in itself *) let curr = GlobRef.Set_env.add firstind_ref GlobRef.Set_env.empty in let accu = (curr, data, ax2ty) in let mib = lookup_mind mind in (* Collects references of parameters *) let param_ctx = mib.mind_params_ctxt in let nparam = List.length param_ctx in let accu = traverse_context access label Context.Rel.empty accu param_ctx in (* For each inductive, collects references in their arity and in the type
of constructors*) let (contents, data, ax2ty) = Array.fold_left (fun accu oib -> let arity_wo_param = List.rev (List.skipn nparam (List.rev oib.mind_arity_ctxt)) in let accu =
traverse_context
access label param_ctx accu arity_wo_param in
Array.fold_left (fun accu cst_typ -> let param_ctx, cst_typ_wo_param = Term.decompose_prod_n_decls nparam cst_typ in
traverse access label param_ctx accu cst_typ_wo_param)
accu oib.mind_user_lc)
accu mib.mind_packets in (* Maps all these dependencies to inductives and constructors*) let data = let contents = GlobRef.Set_env.remove firstind_ref contents in
Array.fold_left_i (fun n data oib -> let ind = (mind, n) in let data = GlobRef.Map_env.add (GlobRef.IndRef ind) (Some contents) data in
Array.fold_left_i (fun k data _ ->
GlobRef.Map_env.add (GlobRef.ConstructRef (ind, k+1)) (Some contents) data
) data oib.mind_consnames) data mib.mind_packets in
(data, ax2ty) in
(GlobRef.Set_env.add obj curr, data, ax2ty)
(** Collects references in a rel_context. *) and traverse_context access current ctx accu ctxt =
snd (Context.Rel.fold_outside (fun decl (ctx, accu) -> match decl with
| Context.Rel.Declaration.LocalDef (_,c,t) -> let accu = traverse access current ctx (traverse access current ctx accu t) c in let ctx = Context.Rel.add decl ctx in
ctx, accu
| Context.Rel.Declaration.LocalAssum (_,t) -> let accu = traverse access current ctx accu t in let ctx = Context.Rel.add decl ctx in
ctx, accu) ctxt ~init:(ctx, accu))
let traverse access current t = let () = modcache := MPmap.empty in
traverse access current Context.Rel.empty (GlobRef.Set_env.empty, GlobRef.Map_env.empty, GlobRef.Map_env.empty) t
(** Hopefully bullet-proof function to recover the type of a constant. It just ignores all the universe stuff. There are many issues that can arise when
considering terms out of any valid environment, so use with caution. *) let type_of_constant cb = cb.Declarations.const_type
let assumptions ?(add_opaque=false) ?(add_transparent=false) access st gr t = letopen Printer in (* Only keep the transitive dependencies *) let (_, graph, ax2ty) = traverse access (label_of gr) t in letopen GlobRef in let fold obj contents accu = match obj with
| VarRef id -> let decl = Global.lookup_named id in if Context.Named.Declaration.is_local_assum decl then let t = Context.Named.Declaration.get_type decl in
ContextObjectMap.add (Variable id) t accu else accu
| ConstRef kn -> let cb = lookup_constant kn in let accu = if cb.const_typing_flags.check_guarded then accu else let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (Guarded obj, l)) Constr.mkProp accu in let accu = if cb.const_typing_flags.check_universes then accu else let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (TypeInType obj, l)) Constr.mkProp accu in ifnot (Option.has_some contents) then let t = type_of_constant cb in let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (Constant kn,l)) t accu elseif add_opaque && (Declareops.is_opaque cb || not (Structures.PrimitiveProjections.is_transparent_constant st kn)) then let t = type_of_constant cb in
ContextObjectMap.add (Opaque kn) t accu elseif add_transparent then let t = type_of_constant cb in
ContextObjectMap.add (Transparent kn) t accu else
accu
| IndRef (m,_) | ConstructRef ((m,_),_) -> let mind = lookup_mind m in let accu = if mind.mind_typing_flags.check_positive then accu else let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (Positive m, l)) Constr.mkProp accu in let accu = if mind.mind_typing_flags.check_guarded then accu else let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (Guarded obj, l)) Constr.mkProp accu in let accu = if mind.mind_typing_flags.check_universes then accu else let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (TypeInType obj, l)) Constr.mkProp accu in let accu = ifnot (uses_uip mind) then accu else let l = try GlobRef.Map_env.find obj ax2ty with Not_found -> [] in
ContextObjectMap.add (Axiom (UIP m, l)) Constr.mkProp accu in
accu in GlobRef.Map_env.fold fold graph ContextObjectMap.empty
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.