aboutsummaryrefslogtreecommitdiff
path: root/kernel/safe_typing.ml
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/safe_typing.ml')
-rw-r--r--kernel/safe_typing.ml1312
1 files changed, 1312 insertions, 0 deletions
diff --git a/kernel/safe_typing.ml b/kernel/safe_typing.ml
new file mode 100644
index 0000000000..673f025c75
--- /dev/null
+++ b/kernel/safe_typing.ml
@@ -0,0 +1,1312 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \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) *)
+(************************************************************************)
+
+(* Created by Jean-Christophe Filliâtre as part of the rebuilding of
+ Coq around a purely functional abstract type-checker, Dec 1999 *)
+
+(* This file provides the entry points to the kernel type-checker. It
+ defines the abstract type of well-formed environments and
+ implements the rules that build well-formed environments.
+
+ An environment is made of constants and inductive types (E), of
+ section declarations (Delta), of local bound-by-index declarations
+ (Gamma) and of universe constraints (C). Below E[Delta,Gamma] |-_C
+ means that the tuple E, Delta, Gamma, C is a well-formed
+ environment. Main rules are:
+
+ empty_environment:
+
+ ------
+ [,] |-
+
+ push_named_assum(a,T):
+
+ E[Delta,Gamma] |-_G
+ ------------------------
+ E[Delta,Gamma,a:T] |-_G'
+
+ push_named_def(a,t,T):
+
+ E[Delta,Gamma] |-_G
+ ---------------------------
+ E[Delta,Gamma,a:=t:T] |-_G'
+
+ add_constant(ConstantEntry(DefinitionEntry(c,t,T))):
+
+ E[Delta,Gamma] |-_G
+ ---------------------------
+ E,c:=t:T[Delta,Gamma] |-_G'
+
+ add_constant(ConstantEntry(ParameterEntry(c,T))):
+
+ E[Delta,Gamma] |-_G
+ ------------------------
+ E,c:T[Delta,Gamma] |-_G'
+
+ add_mind(Ind(Ind[Gamma_p](Gamma_I:=Gamma_C))):
+
+ E[Delta,Gamma] |-_G
+ ------------------------
+ E,Ind[Gamma_p](Gamma_I:=Gamma_C)[Delta,Gamma] |-_G'
+
+ etc.
+*)
+
+open Util
+open Names
+open Declarations
+open Constr
+open Context.Named.Declaration
+
+module NamedDecl = Context.Named.Declaration
+
+(** {6 Safe environments }
+
+ Fields of [safe_environment] :
+
+ - [env] : the underlying environment (cf Environ)
+ - [modpath] : the current module name
+ - [modvariant] :
+ * NONE before coqtop initialization
+ * LIBRARY at toplevel of a compilation or a regular coqtop session
+ * STRUCT (params,oldsenv) : inside a local module, with
+ module parameters [params] and earlier environment [oldsenv]
+ * SIG (params,oldsenv) : same for a local module type
+ - [modresolver] : delta_resolver concerning the module content
+ - [paramresolver] : delta_resolver concerning the module parameters
+ - [revstruct] : current module content, most recent declarations first
+ - [modlabels] and [objlabels] : names defined in the current module,
+ either for modules/modtypes or for constants/inductives.
+ These fields could be deduced from [revstruct], but they allow faster
+ name freshness checks.
+ - [univ] and [future_cst] : current and future universe constraints
+ - [engagement] : are we Set-impredicative? does the universe hierarchy collapse?
+ - [required] : names and digests of Require'd libraries since big-bang.
+ This field will only grow
+ - [loads] : list of libraries Require'd inside the current module.
+ They will be propagated to the upper module level when
+ the current module ends.
+ - [local_retroknowledge]
+
+*)
+
+type vodigest =
+ | Dvo_or_vi of Digest.t (* The digest of the seg_lib part *)
+ | Dvivo of Digest.t * Digest.t (* The digest of the seg_lib + seg_univ part *)
+
+let digest_match ~actual ~required =
+ match actual, required with
+ | Dvo_or_vi d1, Dvo_or_vi d2
+ | Dvivo (d1,_), Dvo_or_vi d2 -> String.equal d1 d2
+ | Dvivo (d1,e1), Dvivo (d2,e2) -> String.equal d1 d2 && String.equal e1 e2
+ | Dvo_or_vi _, Dvivo _ -> false
+
+type library_info = DirPath.t * vodigest
+
+(** Functor and funsig parameters, most recent first *)
+type module_parameters = (MBId.t * module_type_body) list
+
+module DPMap = Map.Make(DirPath)
+
+type safe_environment =
+ { env : Environ.env;
+ modpath : ModPath.t;
+ modvariant : modvariant;
+ modresolver : Mod_subst.delta_resolver;
+ paramresolver : Mod_subst.delta_resolver;
+ revstruct : structure_body;
+ modlabels : Label.Set.t;
+ objlabels : Label.Set.t;
+ univ : Univ.ContextSet.t;
+ future_cst : Univ.ContextSet.t Future.computation list;
+ engagement : engagement option;
+ required : vodigest DPMap.t;
+ loads : (ModPath.t * module_body) list;
+ local_retroknowledge : Retroknowledge.action list;
+ native_symbols : Nativecode.symbols DPMap.t }
+
+and modvariant =
+ | NONE
+ | LIBRARY
+ | SIG of module_parameters * safe_environment (** saved env *)
+ | STRUCT of module_parameters * safe_environment (** saved env *)
+
+let rec library_dp_of_senv senv =
+ match senv.modvariant with
+ | NONE | LIBRARY -> ModPath.dp senv.modpath
+ | SIG(_,senv) -> library_dp_of_senv senv
+ | STRUCT(_,senv) -> library_dp_of_senv senv
+
+let empty_environment =
+ { env = Environ.empty_env;
+ modpath = ModPath.initial;
+ modvariant = NONE;
+ modresolver = Mod_subst.empty_delta_resolver;
+ paramresolver = Mod_subst.empty_delta_resolver;
+ revstruct = [];
+ modlabels = Label.Set.empty;
+ objlabels = Label.Set.empty;
+ future_cst = [];
+ univ = Univ.ContextSet.empty;
+ engagement = None;
+ required = DPMap.empty;
+ loads = [];
+ local_retroknowledge = [];
+ native_symbols = DPMap.empty }
+
+let is_initial senv =
+ match senv.revstruct, senv.modvariant with
+ | [], NONE -> ModPath.equal senv.modpath ModPath.initial
+ | _ -> false
+
+let delta_of_senv senv = senv.modresolver,senv.paramresolver
+
+let constant_of_delta_kn_senv senv kn =
+ Mod_subst.constant_of_deltas_kn senv.paramresolver senv.modresolver kn
+
+let mind_of_delta_kn_senv senv kn =
+ Mod_subst.mind_of_deltas_kn senv.paramresolver senv.modresolver kn
+
+(** The safe_environment state monad *)
+
+type safe_transformer0 = safe_environment -> safe_environment
+type 'a safe_transformer = safe_environment -> 'a * safe_environment
+
+
+(** {6 Engagement } *)
+
+let set_engagement_opt env = function
+ | Some c -> Environ.set_engagement c env
+ | None -> env
+
+let set_engagement c senv =
+ { senv with
+ env = Environ.set_engagement c senv.env;
+ engagement = Some c }
+
+let set_typing_flags c senv =
+ let env = Environ.set_typing_flags c senv.env in
+ if env == senv.env then senv
+ else { senv with env }
+
+let set_indices_matter indices_matter senv =
+ set_typing_flags { (Environ.typing_flags senv.env) with indices_matter } senv
+
+let set_share_reduction b senv =
+ let flags = Environ.typing_flags senv.env in
+ set_typing_flags { flags with share_reduction = b } senv
+
+let set_VM b senv =
+ let flags = Environ.typing_flags senv.env in
+ set_typing_flags { flags with enable_VM = b } senv
+
+let set_native_compiler b senv =
+ let flags = Environ.typing_flags senv.env in
+ set_typing_flags { flags with enable_native_compiler = b } senv
+
+let make_sprop_cumulative senv = { senv with env = Environ.make_sprop_cumulative senv.env }
+
+let set_allow_sprop b senv = { senv with env = Environ.set_allow_sprop b senv.env }
+
+(** Check that the engagement [c] expected by a library matches
+ the current (initial) one *)
+let check_engagement env expected_impredicative_set =
+ let impredicative_set = Environ.engagement env in
+ begin
+ match impredicative_set, expected_impredicative_set with
+ | PredicativeSet, ImpredicativeSet ->
+ CErrors.user_err Pp.(str "Needs option -impredicative-set.")
+ | _ -> ()
+ end
+
+(** {6 Stm machinery } *)
+
+let get_opaque_body env cbo =
+ match cbo.const_body with
+ | Undef _ -> assert false
+ | Primitive _ -> assert false
+ | Def _ -> `Nothing
+ | OpaqueDef opaque ->
+ `Opaque
+ (Opaqueproof.force_proof (Environ.opaque_tables env) opaque,
+ Opaqueproof.force_constraints (Environ.opaque_tables env) opaque)
+
+type side_effect = {
+ from_env : Declarations.structure_body CEphemeron.key;
+ eff : Entries.side_eff list;
+}
+
+module SideEffects :
+sig
+ type t
+ val repr : t -> side_effect list
+ val empty : t
+ val add : side_effect -> t -> t
+ val concat : t -> t -> t
+end =
+struct
+
+module SeffOrd = struct
+open Entries
+type t = side_effect
+let compare e1 e2 =
+ let cmp e1 e2 = Constant.CanOrd.compare e1.seff_constant e2.seff_constant in
+ List.compare cmp e1.eff e2.eff
+end
+
+module SeffSet = Set.Make(SeffOrd)
+
+type t = { seff : side_effect list; elts : SeffSet.t }
+(** Invariant: [seff] is a permutation of the elements of [elts] *)
+
+let repr eff = eff.seff
+let empty = { seff = []; elts = SeffSet.empty }
+let add x es =
+ if SeffSet.mem x es.elts then es
+ else { seff = x :: es.seff; elts = SeffSet.add x es.elts }
+let concat xes yes =
+ List.fold_right add xes.seff yes
+
+end
+
+type private_constants = SideEffects.t
+
+let side_effects_of_private_constants l =
+ let ans = List.rev (SideEffects.repr l) in
+ List.map_append (fun { eff; _ } -> eff) ans
+
+let empty_private_constants = SideEffects.empty
+let add_private mb eff effs =
+ let from_env = CEphemeron.create mb in
+ SideEffects.add { eff; from_env } effs
+let concat_private = SideEffects.concat
+
+let make_eff env cst r =
+ let open Entries in
+ let cbo = Environ.lookup_constant cst env.env in
+ {
+ seff_constant = cst;
+ seff_body = cbo;
+ seff_env = get_opaque_body env.env cbo;
+ seff_role = r;
+ }
+
+let private_con_of_con env c =
+ let open Entries in
+ let eff = [make_eff env c Subproof] in
+ add_private env.revstruct eff empty_private_constants
+
+let private_con_of_scheme ~kind env cl =
+ let open Entries in
+ let eff = List.map (fun (i, c) -> make_eff env c (Schema (i, kind))) cl in
+ add_private env.revstruct eff empty_private_constants
+
+let universes_of_private eff =
+ let open Entries in
+ let fold acc eff =
+ let acc = match eff.seff_env with
+ | `Nothing -> acc
+ | `Opaque (_, ctx) -> ctx :: acc
+ in
+ match eff.seff_body.const_universes with
+ | Monomorphic ctx -> ctx :: acc
+ | Polymorphic _ -> acc
+ in
+ List.fold_left fold [] (side_effects_of_private_constants eff)
+
+let env_of_safe_env senv = senv.env
+let env_of_senv = env_of_safe_env
+
+type constraints_addition =
+ | Now of bool * Univ.ContextSet.t
+ | Later of Univ.ContextSet.t Future.computation
+
+let add_constraints cst senv =
+ match cst with
+ | Later fc ->
+ {senv with future_cst = fc :: senv.future_cst}
+ | Now (poly,cst) ->
+ { senv with
+ env = Environ.push_context_set ~strict:(not poly) cst senv.env;
+ univ = Univ.ContextSet.union cst senv.univ }
+
+let add_constraints_list cst senv =
+ List.fold_left (fun acc c -> add_constraints c acc) senv cst
+
+let push_context_set poly ctx = add_constraints (Now (poly,ctx))
+
+let is_curmod_library senv =
+ match senv.modvariant with LIBRARY -> true | _ -> false
+
+let join_safe_environment ?(except=Future.UUIDSet.empty) e =
+ Modops.join_structure except (Environ.opaque_tables e.env) e.revstruct;
+ List.fold_left
+ (fun e fc ->
+ if Future.UUIDSet.mem (Future.uuid fc) except then e
+ else add_constraints (Now (false, Future.join fc)) e)
+ {e with future_cst = []} e.future_cst
+
+let is_joined_environment e = List.is_empty e.future_cst
+
+(** {6 Various checks } *)
+
+let exists_modlabel l senv = Label.Set.mem l senv.modlabels
+let exists_objlabel l senv = Label.Set.mem l senv.objlabels
+
+let check_modlabel l senv =
+ if exists_modlabel l senv then Modops.error_existing_label l
+
+let check_objlabel l senv =
+ if exists_objlabel l senv then Modops.error_existing_label l
+
+let check_objlabels ls senv =
+ Label.Set.iter (fun l -> check_objlabel l senv) ls
+
+(** Are we closing the right module / modtype ?
+ No user error here, since the opening/ending coherence
+ is now verified in [vernac_end_segment] *)
+
+let check_current_label lab = function
+ | MPdot (_,l) -> assert (Label.equal lab l)
+ | _ -> assert false
+
+let check_struct = function
+ | STRUCT (params,oldsenv) -> params, oldsenv
+ | NONE | LIBRARY | SIG _ -> assert false
+
+let check_sig = function
+ | SIG (params,oldsenv) -> params, oldsenv
+ | NONE | LIBRARY | STRUCT _ -> assert false
+
+let check_current_library dir senv = match senv.modvariant with
+ | LIBRARY -> assert (ModPath.equal senv.modpath (MPfile dir))
+ | NONE | STRUCT _ | SIG _ -> assert false (* cf Lib.end_compilation *)
+
+(** When operating on modules, we're normally outside sections *)
+
+let check_empty_context senv =
+ assert (Environ.empty_context senv.env)
+
+(** When adding a parameter to the current module/modtype,
+ it must have been freshly started *)
+
+let check_empty_struct senv =
+ assert (List.is_empty senv.revstruct
+ && List.is_empty senv.loads)
+
+(** When starting a library, the current environment should be initial
+ i.e. only composed of Require's *)
+
+let check_initial senv = assert (is_initial senv)
+
+(** When loading a library, its dependencies should be already there,
+ with the correct digests. *)
+
+let check_required current_libs needed =
+ let check (id,required) =
+ try
+ let actual = DPMap.find id current_libs in
+ if not(digest_match ~actual ~required) then
+ CErrors.user_err Pp.(pr_sequence str
+ ["Inconsistent assumptions over module"; DirPath.to_string id; "."])
+ with Not_found ->
+ CErrors.user_err Pp.(pr_sequence str ["Reference to unknown module"; DirPath.to_string id; "."])
+ in
+ Array.iter check needed
+
+
+(** {6 Insertion of section variables} *)
+
+(** They are now typed before being added to the environment.
+ Same as push_named, but check that the variable is not already
+ there. Should *not* be done in Environ because tactics add temporary
+ hypothesis many many times, and the check performed here would
+ cost too much. *)
+
+let safe_push_named d env =
+ let id = NamedDecl.get_id d in
+ let _ =
+ try
+ let _ = Environ.lookup_named id env in
+ CErrors.user_err Pp.(pr_sequence str ["Identifier"; Id.to_string id; "already defined."])
+ with Not_found -> () in
+ Environ.push_named d env
+
+
+let push_named_def (id,de) senv =
+ let c, r, typ = Term_typing.translate_local_def senv.env id de in
+ let x = Context.make_annot id r in
+ let env'' = safe_push_named (LocalDef (x, c, typ)) senv.env in
+ { senv with env = env'' }
+
+let push_named_assum ((id,t,poly),ctx) senv =
+ let senv' = push_context_set poly ctx senv in
+ let t, r = Term_typing.translate_local_assum senv'.env t in
+ let x = Context.make_annot id r in
+ let env'' = safe_push_named (LocalAssum (x,t)) senv'.env in
+ {senv' with env=env''}
+
+
+(** {6 Insertion of new declarations to current environment } *)
+
+let labels_of_mib mib =
+ let add,get =
+ let labels = ref Label.Set.empty in
+ (fun id -> labels := Label.Set.add (Label.of_id id) !labels),
+ (fun () -> !labels)
+ in
+ let visit_mip mip =
+ add mip.mind_typename;
+ Array.iter add mip.mind_consnames
+ in
+ Array.iter visit_mip mib.mind_packets;
+ get ()
+
+let globalize_constant_universes env cb =
+ match cb.const_universes with
+ | Monomorphic cstrs ->
+ Now (false, cstrs) ::
+ (match cb.const_body with
+ | (Undef _ | Def _ | Primitive _) -> []
+ | OpaqueDef lc ->
+ match Opaqueproof.get_constraints (Environ.opaque_tables env) lc with
+ | None -> []
+ | Some fc ->
+ match Future.peek_val fc with
+ | None -> [Later fc]
+ | Some c -> [Now (false, c)])
+ | Polymorphic _ ->
+ [Now (true, Univ.ContextSet.empty)]
+
+let globalize_mind_universes mb =
+ match mb.mind_universes with
+ | Monomorphic ctx ->
+ [Now (false, ctx)]
+ | Polymorphic _ -> [Now (true, Univ.ContextSet.empty)]
+
+let constraints_of_sfb env sfb =
+ match sfb with
+ | SFBconst cb -> globalize_constant_universes env cb
+ | SFBmind mib -> globalize_mind_universes mib
+ | SFBmodtype mtb -> [Now (false, mtb.mod_constraints)]
+ | SFBmodule mb -> [Now (false, mb.mod_constraints)]
+
+let add_retroknowledge pttc senv =
+ { senv with
+ env = Primred.add_retroknowledge senv.env pttc;
+ local_retroknowledge = pttc::senv.local_retroknowledge }
+
+(** A generic function for adding a new field in a same environment.
+ It also performs the corresponding [add_constraints]. *)
+
+type generic_name =
+ | C of Constant.t
+ | I of MutInd.t
+ | M (** name already known, cf the mod_mp field *)
+ | MT (** name already known, cf the mod_mp field *)
+
+let add_field ?(is_include=false) ((l,sfb) as field) gn senv =
+ let mlabs,olabs = match sfb with
+ | SFBmind mib ->
+ let l = labels_of_mib mib in
+ check_objlabels l senv; (Label.Set.empty,l)
+ | SFBconst _ ->
+ check_objlabel l senv; (Label.Set.empty, Label.Set.singleton l)
+ | SFBmodule _ | SFBmodtype _ ->
+ check_modlabel l senv; (Label.Set.singleton l, Label.Set.empty)
+ in
+ let senv =
+ if is_include then
+ (* Universes and constraints were added when the included module
+ was defined eg in [Include F X.] (one of the trickier
+ versions of Include) the constraints on the fields are
+ exactly those of the fields of F which was defined
+ separately. *)
+ senv
+ else
+ let cst = constraints_of_sfb senv.env sfb in
+ add_constraints_list cst senv
+ in
+ let env' = match sfb, gn with
+ | SFBconst cb, C con -> Environ.add_constant con cb senv.env
+ | SFBmind mib, I mind -> Environ.add_mind mind mib senv.env
+ | SFBmodtype mtb, MT -> Environ.add_modtype mtb senv.env
+ | SFBmodule mb, M -> Modops.add_module mb senv.env
+ | _ -> assert false
+ in
+ { senv with
+ env = env';
+ revstruct = field :: senv.revstruct;
+ modlabels = Label.Set.union mlabs senv.modlabels;
+ objlabels = Label.Set.union olabs senv.objlabels }
+
+(** Applying a certain function to the resolver of a safe environment *)
+
+let update_resolver f senv = { senv with modresolver = f senv.modresolver }
+
+(** Insertion of constants and parameters in environment *)
+type 'a effect_entry =
+| EffectEntry : private_constants effect_entry
+| PureEntry : unit effect_entry
+
+type global_declaration =
+ | ConstantEntry : 'a effect_entry * 'a Entries.constant_entry -> global_declaration
+ | GlobalRecipe of Cooking.recipe
+
+type exported_private_constant =
+ Constant.t * Entries.side_effect_role
+
+let add_constant_aux ~in_section senv (kn, cb) =
+ let l = Constant.label kn in
+ let cb, otab = match cb.const_body with
+ | OpaqueDef lc when not in_section ->
+ (* In coqc, opaque constants outside sections will be stored
+ indirectly in a specific table *)
+ let od, otab =
+ Opaqueproof.turn_indirect
+ (library_dp_of_senv senv) lc (Environ.opaque_tables senv.env) in
+ { cb with const_body = OpaqueDef od }, otab
+ | _ -> cb, (Environ.opaque_tables senv.env)
+ in
+ let senv = { senv with env = Environ.set_opaque_tables senv.env otab } in
+ let senv' = add_field (l,SFBconst cb) (C kn) senv in
+ let senv'' = match cb.const_body with
+ | Undef (Some lev) ->
+ update_resolver
+ (Mod_subst.add_inline_delta_resolver (Constant.user kn) (lev,None)) senv'
+ | _ -> senv'
+ in
+ senv''
+
+let mk_pure_proof c = (c, Univ.ContextSet.empty), SideEffects.empty
+
+let inline_side_effects env body side_eff =
+ let open Entries in
+ let open Constr in
+ (** First step: remove the constants that are still in the environment *)
+ let filter { eff = se; from_env = mb } =
+ let map e = (e.seff_constant, e.seff_body, e.seff_env) in
+ let cbl = List.map map se in
+ let not_exists (c,_,_) =
+ try ignore(Environ.lookup_constant c env); false
+ with Not_found -> true in
+ let cbl = List.filter not_exists cbl in
+ (cbl, mb)
+ in
+ (* CAVEAT: we assure that most recent effects come first *)
+ let side_eff = List.map filter (SideEffects.repr side_eff) in
+ let sigs = List.rev_map (fun (cbl, mb) -> mb, List.length cbl) side_eff in
+ let side_eff = List.fold_left (fun accu (cbl, _) -> cbl @ accu) [] side_eff in
+ let side_eff = List.rev side_eff in
+ (** Most recent side-effects first in side_eff *)
+ if List.is_empty side_eff then (body, Univ.ContextSet.empty, sigs)
+ else
+ (** Second step: compute the lifts and substitutions to apply *)
+ let cname c r = Context.make_annot (Name (Label.to_id (Constant.label c))) r in
+ let fold (subst, var, ctx, args) (c, cb, b) =
+ let (b, opaque) = match cb.const_body, b with
+ | Def b, _ -> (Mod_subst.force_constr b, false)
+ | OpaqueDef _, `Opaque (b,_) -> (b, true)
+ | _ -> assert false
+ in
+ match cb.const_universes with
+ | Monomorphic univs ->
+ (** Abstract over the term at the top of the proof *)
+ let ty = cb.const_type in
+ let subst = Cmap_env.add c (Inr var) subst in
+ let ctx = Univ.ContextSet.union ctx univs in
+ (subst, var + 1, ctx, (cname c cb.const_relevance, b, ty, opaque) :: args)
+ | Polymorphic _ ->
+ (** Inline the term to emulate universe polymorphism *)
+ let subst = Cmap_env.add c (Inl b) subst in
+ (subst, var, ctx, args)
+ in
+ let (subst, len, ctx, args) = List.fold_left fold (Cmap_env.empty, 1, Univ.ContextSet.empty, []) side_eff in
+ (** Third step: inline the definitions *)
+ let rec subst_const i k t = match Constr.kind t with
+ | Const (c, u) ->
+ let data = try Some (Cmap_env.find c subst) with Not_found -> None in
+ begin match data with
+ | None -> t
+ | Some (Inl b) ->
+ (** [b] is closed but may refer to other constants *)
+ subst_const i k (Vars.subst_instance_constr u b)
+ | Some (Inr n) ->
+ mkRel (k + n - i)
+ end
+ | Rel n ->
+ (** Lift free rel variables *)
+ if n <= k then t
+ else mkRel (n + len - i - 1)
+ | _ -> Constr.map_with_binders ((+) 1) (fun k t -> subst_const i k t) k t
+ in
+ let map_args i (na, b, ty, opaque) =
+ (** Both the type and the body may mention other constants *)
+ let ty = subst_const (len - i - 1) 0 ty in
+ let b = subst_const (len - i - 1) 0 b in
+ (na, b, ty, opaque)
+ in
+ let args = List.mapi map_args args in
+ let body = subst_const 0 0 body in
+ let fold_arg (na, b, ty, opaque) accu =
+ if opaque then mkApp (mkLambda (na, ty, accu), [|b|])
+ else mkLetIn (na, b, ty, accu)
+ in
+ let body = List.fold_right fold_arg args body in
+ (body, ctx, sigs)
+
+let inline_private_constants_in_definition_entry env ce =
+ let open Entries in
+ { ce with
+ const_entry_body = Future.chain
+ ce.const_entry_body (fun ((body, ctx), side_eff) ->
+ let body, ctx',_ = inline_side_effects env body side_eff in
+ let ctx' = Univ.ContextSet.union ctx ctx' in
+ (body, ctx'), ());
+ }
+
+let inline_private_constants_in_constr env body side_eff =
+ pi1 (inline_side_effects env body side_eff)
+
+let rec is_nth_suffix n l suf =
+ if Int.equal n 0 then l == suf
+ else match l with
+ | [] -> false
+ | _ :: l -> is_nth_suffix (pred n) l suf
+
+(* Given the list of signatures of side effects, checks if they match.
+ * I.e. if they are ordered descendants of the current revstruct.
+ Returns the number of effects that can be trusted. *)
+let check_signatures curmb sl =
+ let is_direct_ancestor accu (mb, how_many) =
+ match accu with
+ | None -> None
+ | Some (n, curmb) ->
+ try
+ let mb = CEphemeron.get mb in
+ if is_nth_suffix how_many mb curmb
+ then Some (n + how_many, mb)
+ else None
+ with CEphemeron.InvalidKey -> None in
+ let sl = List.fold_left is_direct_ancestor (Some (0, curmb)) sl in
+ match sl with
+ | None -> 0
+ | Some (n, _) -> n
+
+
+let constant_entry_of_side_effect cb u =
+ let open Entries in
+ let univs =
+ match cb.const_universes with
+ | Monomorphic uctx ->
+ Monomorphic_entry uctx
+ | Polymorphic auctx ->
+ Polymorphic_entry (Univ.AUContext.names auctx, Univ.AUContext.repr auctx)
+ in
+ let pt =
+ match cb.const_body, u with
+ | OpaqueDef _, `Opaque (b, c) -> b, c
+ | Def b, `Nothing -> Mod_subst.force_constr b, Univ.ContextSet.empty
+ | _ -> assert false in
+ DefinitionEntry {
+ const_entry_body = Future.from_val (pt, ());
+ const_entry_secctx = None;
+ const_entry_feedback = None;
+ const_entry_type = Some cb.const_type;
+ const_entry_universes = univs;
+ const_entry_opaque = Declareops.is_opaque cb;
+ const_entry_inline_code = cb.const_inline_code }
+
+let turn_direct orig =
+ let open Entries in
+ let cb = orig.seff_body in
+ if Declareops.is_opaque cb then
+ let p = match orig.seff_env with
+ | `Opaque (b, c) -> (b, c)
+ | _ -> assert false
+ in
+ let const_body = OpaqueDef (Opaqueproof.create (Future.from_val p)) in
+ let cb = { cb with const_body } in
+ { orig with seff_body = cb }
+ else orig
+
+let export_eff eff =
+ let open Entries in
+ (eff.seff_constant, eff.seff_body, eff.seff_role)
+
+let export_side_effects mb env c =
+ let open Entries in
+ let body = c.const_entry_body in
+ let _, eff = Future.force body in
+ let ce = { c with
+ Entries.const_entry_body = Future.chain body
+ (fun (b_ctx, _) -> b_ctx, ()) } in
+ let not_exists e =
+ try ignore(Environ.lookup_constant e.seff_constant env); false
+ with Not_found -> true in
+ let aux (acc,sl) { eff = se; from_env = mb } =
+ let cbl = List.filter not_exists se in
+ if List.is_empty cbl then acc, sl
+ else cbl :: acc, (mb,List.length cbl) :: sl in
+ let seff, signatures = List.fold_left aux ([],[]) (SideEffects.repr eff) in
+ let trusted = check_signatures mb signatures in
+ let push_seff env eff =
+ let { seff_constant = kn; seff_body = cb ; _ } = eff in
+ let env = Environ.add_constant kn cb env in
+ match cb.const_universes with
+ | Polymorphic _ -> env
+ | Monomorphic ctx ->
+ let ctx = match eff.seff_env with
+ | `Nothing -> ctx
+ | `Opaque(_, ctx') -> Univ.ContextSet.union ctx' ctx
+ in
+ Environ.push_context_set ~strict:true ctx env
+ in
+ let rec translate_seff sl seff acc env =
+ match seff with
+ | [] -> List.rev acc, ce
+ | cbs :: rest ->
+ if Int.equal sl 0 then
+ let env, cbs =
+ List.fold_left (fun (env,cbs) eff ->
+ let { seff_constant = kn; seff_body = ocb; seff_env = u ; _ } = eff in
+ let ce = constant_entry_of_side_effect ocb u in
+ let cb = Term_typing.translate_constant Term_typing.Pure env kn ce in
+ let eff = { eff with
+ seff_body = cb;
+ seff_env = `Nothing;
+ } in
+ (push_seff env eff, export_eff eff :: cbs))
+ (env,[]) cbs in
+ translate_seff 0 rest (cbs @ acc) env
+ else
+ let cbs_len = List.length cbs in
+ let cbs = List.map turn_direct cbs in
+ let env = List.fold_left push_seff env cbs in
+ let ecbs = List.map export_eff cbs in
+ translate_seff (sl - cbs_len) rest (ecbs @ acc) env
+ in
+ translate_seff trusted seff [] env
+
+let export_private_constants ~in_section ce senv =
+ let exported, ce = export_side_effects senv.revstruct senv.env ce in
+ let bodies = List.map (fun (kn, cb, _) -> (kn, cb)) exported in
+ let exported = List.map (fun (kn, _, r) -> (kn, r)) exported in
+ let senv = List.fold_left (add_constant_aux ~in_section) senv bodies in
+ (ce, exported), senv
+
+let add_constant ~in_section l decl senv =
+ let kn = Constant.make2 senv.modpath l in
+ let senv =
+ let cb =
+ match decl with
+ | ConstantEntry (EffectEntry, ce) ->
+ let handle env body eff =
+ let body, uctx, signatures = inline_side_effects env body eff in
+ let trusted = check_signatures senv.revstruct signatures in
+ body, uctx, trusted
+ in
+ Term_typing.translate_constant (Term_typing.SideEffects handle) senv.env kn ce
+ | ConstantEntry (PureEntry, ce) ->
+ Term_typing.translate_constant Term_typing.Pure senv.env kn ce
+ | GlobalRecipe r ->
+ let cb = Term_typing.translate_recipe ~hcons:(not in_section) senv.env kn r in
+ if in_section then cb else Declareops.hcons_const_body cb in
+ add_constant_aux ~in_section senv (kn, cb) in
+ let senv =
+ match decl with
+ | ConstantEntry (_,(Entries.PrimitiveEntry { Entries.prim_entry_content = CPrimitives.OT_type t; _ })) ->
+ if in_section then CErrors.anomaly (Pp.str "Primitive type not allowed in sections");
+ add_retroknowledge (Retroknowledge.Register_type(t,kn)) senv
+ | _ -> senv
+ in
+ kn, senv
+
+(** Insertion of inductive types *)
+
+let check_mind mie lab =
+ let open Entries in
+ match mie.mind_entry_inds with
+ | [] -> assert false (* empty inductive entry *)
+ | oie::_ ->
+ (* The label and the first inductive type name should match *)
+ assert (Id.equal (Label.to_id lab) oie.mind_entry_typename)
+
+let add_mind l mie senv =
+ let () = check_mind mie l in
+ let kn = MutInd.make2 senv.modpath l in
+ let mib = Indtypes.check_inductive senv.env kn mie in
+ let mib =
+ match mib.mind_hyps with [] -> Declareops.hcons_mind mib | _ -> mib
+ in
+ kn, add_field (l,SFBmind mib) (I kn) senv
+
+(** Insertion of module types *)
+
+let add_modtype l params_mte inl senv =
+ let mp = MPdot(senv.modpath, l) in
+ let mtb = Mod_typing.translate_modtype senv.env mp inl params_mte in
+ let mtb = Declareops.hcons_module_type mtb in
+ let senv' = add_field (l,SFBmodtype mtb) MT senv in
+ mp, senv'
+
+(** full_add_module adds module with universes and constraints *)
+
+let full_add_module mb senv =
+ let senv = add_constraints (Now (false, mb.mod_constraints)) senv in
+ let dp = ModPath.dp mb.mod_mp in
+ let linkinfo = Nativecode.link_info_of_dirpath dp in
+ { senv with env = Modops.add_linked_module mb linkinfo senv.env }
+
+let full_add_module_type mp mt senv =
+ let senv = add_constraints (Now (false, mt.mod_constraints)) senv in
+ { senv with env = Modops.add_module_type mp mt senv.env }
+
+(** Insertion of modules *)
+
+let add_module l me inl senv =
+ let mp = MPdot(senv.modpath, l) in
+ let mb = Mod_typing.translate_module senv.env mp inl me in
+ let mb = Declareops.hcons_module_body mb in
+ let senv' = add_field (l,SFBmodule mb) M senv in
+ let senv'' =
+ if Modops.is_functor mb.mod_type then senv'
+ else update_resolver (Mod_subst.add_delta_resolver mb.mod_delta) senv'
+ in
+ (mp,mb.mod_delta),senv''
+
+
+(** {6 Starting / ending interactive modules and module types } *)
+
+let start_module l senv =
+ let () = check_modlabel l senv in
+ let () = check_empty_context senv in
+ let mp = MPdot(senv.modpath, l) in
+ mp,
+ { empty_environment with
+ env = senv.env;
+ modpath = mp;
+ modvariant = STRUCT ([],senv);
+ required = senv.required }
+
+let start_modtype l senv =
+ let () = check_modlabel l senv in
+ let () = check_empty_context senv in
+ let mp = MPdot(senv.modpath, l) in
+ mp,
+ { empty_environment with
+ env = senv.env;
+ modpath = mp;
+ modvariant = SIG ([], senv);
+ required = senv.required }
+
+(** Adding parameters to the current module or module type.
+ This module should have been freshly started. *)
+
+let add_module_parameter mbid mte inl senv =
+ let () = check_empty_struct senv in
+ let mp = MPbound mbid in
+ let mtb = Mod_typing.translate_modtype senv.env mp inl ([],mte) in
+ let senv = full_add_module_type mp mtb senv in
+ let new_variant = match senv.modvariant with
+ | STRUCT (params,oldenv) -> STRUCT ((mbid,mtb) :: params, oldenv)
+ | SIG (params,oldenv) -> SIG ((mbid,mtb) :: params, oldenv)
+ | _ -> assert false
+ in
+ let new_paramresolver =
+ if Modops.is_functor mtb.mod_type then senv.paramresolver
+ else Mod_subst.add_delta_resolver mtb.mod_delta senv.paramresolver
+ in
+ mtb.mod_delta,
+ { senv with
+ modvariant = new_variant;
+ paramresolver = new_paramresolver }
+
+let functorize params init =
+ List.fold_left (fun e (mbid,mt) -> MoreFunctor(mbid,mt,e)) init params
+
+let propagate_loads senv =
+ List.fold_left
+ (fun env (_,mb) -> full_add_module mb env)
+ senv
+ (List.rev senv.loads)
+
+(** Build the module body of the current module, taking in account
+ a possible return type (_:T) *)
+
+let functorize_module params mb =
+ let f x = functorize params x in
+ { mb with
+ mod_expr = Modops.implem_smartmap f f mb.mod_expr;
+ mod_type = f mb.mod_type;
+ mod_type_alg = Option.map f mb.mod_type_alg }
+
+let build_module_body params restype senv =
+ let struc = NoFunctor (List.rev senv.revstruct) in
+ let restype' = Option.map (fun (ty,inl) -> (([],ty),inl)) restype in
+ let mb =
+ Mod_typing.finalize_module senv.env senv.modpath
+ (struc,None,senv.modresolver,senv.univ) restype'
+ in
+ let mb' = functorize_module params mb in
+ { mb' with mod_retroknowledge = ModBodyRK senv.local_retroknowledge }
+
+(** Returning back to the old pre-interactive-module environment,
+ with one extra component and some updated fields
+ (constraints, required, etc) *)
+
+let allow_delayed_constants = ref false
+
+let propagate_senv newdef newenv newresolver senv oldsenv =
+ let now_cst, later_cst = List.partition Future.is_val senv.future_cst in
+ (* This asserts that after Paral-ITP, standard vo compilation is behaving
+ * exctly as before: the same universe constraints are added to modules *)
+ if not !allow_delayed_constants && later_cst <> [] then
+ CErrors.anomaly ~label:"safe_typing"
+ Pp.(str "True Future.t were created for opaque constants even if -async-proofs is off");
+ { oldsenv with
+ env = newenv;
+ modresolver = newresolver;
+ revstruct = newdef::oldsenv.revstruct;
+ modlabels = Label.Set.add (fst newdef) oldsenv.modlabels;
+ univ =
+ List.fold_left (fun acc cst ->
+ Univ.ContextSet.union acc (Future.force cst))
+ (Univ.ContextSet.union senv.univ oldsenv.univ)
+ now_cst;
+ future_cst = later_cst @ oldsenv.future_cst;
+ (* engagement is propagated to the upper level *)
+ engagement = senv.engagement;
+ required = senv.required;
+ loads = senv.loads@oldsenv.loads;
+ local_retroknowledge =
+ senv.local_retroknowledge@oldsenv.local_retroknowledge;
+ native_symbols = senv.native_symbols}
+
+let end_module l restype senv =
+ let mp = senv.modpath in
+ let params, oldsenv = check_struct senv.modvariant in
+ let () = check_current_label l mp in
+ let () = check_empty_context senv in
+ let mbids = List.rev_map fst params in
+ let mb = build_module_body params restype senv in
+ let newenv = Environ.set_opaque_tables oldsenv.env (Environ.opaque_tables senv.env) in
+ let newenv = set_engagement_opt newenv senv.engagement in
+ let senv'=
+ propagate_loads { senv with
+ env = newenv;
+ univ = Univ.ContextSet.union senv.univ mb.mod_constraints} in
+ let newenv = Environ.push_context_set ~strict:true mb.mod_constraints senv'.env in
+ let newenv = Modops.add_module mb newenv in
+ let newresolver =
+ if Modops.is_functor mb.mod_type then oldsenv.modresolver
+ else Mod_subst.add_delta_resolver mb.mod_delta oldsenv.modresolver
+ in
+ (mp,mbids,mb.mod_delta),
+ propagate_senv (l,SFBmodule mb) newenv newresolver senv' oldsenv
+
+let build_mtb mp sign cst delta =
+ { mod_mp = mp;
+ mod_expr = ();
+ mod_type = sign;
+ mod_type_alg = None;
+ mod_constraints = cst;
+ mod_delta = delta;
+ mod_retroknowledge = ModTypeRK }
+
+let end_modtype l senv =
+ let mp = senv.modpath in
+ let params, oldsenv = check_sig senv.modvariant in
+ let () = check_current_label l mp in
+ let () = check_empty_context senv in
+ let mbids = List.rev_map fst params in
+ let newenv = Environ.set_opaque_tables oldsenv.env (Environ.opaque_tables senv.env) in
+ let newenv = Environ.push_context_set ~strict:true senv.univ newenv in
+ let newenv = set_engagement_opt newenv senv.engagement in
+ let senv' = propagate_loads {senv with env=newenv} in
+ let auto_tb = functorize params (NoFunctor (List.rev senv.revstruct)) in
+ let mtb = build_mtb mp auto_tb senv'.univ senv.modresolver in
+ let newenv = Environ.add_modtype mtb senv'.env in
+ let newresolver = oldsenv.modresolver in
+ (mp,mbids),
+ propagate_senv (l,SFBmodtype mtb) newenv newresolver senv' oldsenv
+
+(** {6 Inclusion of module or module type } *)
+
+let add_include me is_module inl senv =
+ let open Mod_typing in
+ let mp_sup = senv.modpath in
+ let sign,(),resolver,cst =
+ translate_mse_incl is_module senv.env mp_sup inl me
+ in
+ let senv = add_constraints (Now (false, cst)) senv in
+ (* Include Self support *)
+ let rec compute_sign sign mb resolver senv =
+ match sign with
+ | MoreFunctor(mbid,mtb,str) ->
+ let cst_sub = Subtyping.check_subtypes senv.env mb mtb in
+ let senv =
+ add_constraints
+ (Now (false, Univ.ContextSet.add_constraints cst_sub Univ.ContextSet.empty))
+ senv in
+ let mpsup_delta =
+ Modops.inline_delta_resolver senv.env inl mp_sup mbid mtb mb.mod_delta
+ in
+ let subst = Mod_subst.map_mbid mbid mp_sup mpsup_delta in
+ let resolver = Mod_subst.subst_codom_delta_resolver subst resolver in
+ compute_sign (Modops.subst_signature subst str) mb resolver senv
+ | NoFunctor str -> resolver,str,senv
+ in
+ let resolver,str,senv =
+ let struc = NoFunctor (List.rev senv.revstruct) in
+ let mtb = build_mtb mp_sup struc Univ.ContextSet.empty senv.modresolver in
+ compute_sign sign mtb resolver senv
+ in
+ let senv = update_resolver (Mod_subst.add_delta_resolver resolver) senv
+ in
+ let add senv ((l,elem) as field) =
+ let new_name = match elem with
+ | SFBconst _ ->
+ C (Mod_subst.constant_of_delta_kn resolver (KerName.make mp_sup l))
+ | SFBmind _ ->
+ I (Mod_subst.mind_of_delta_kn resolver (KerName.make mp_sup l))
+ | SFBmodule _ -> M
+ | SFBmodtype _ -> MT
+ in
+ add_field ~is_include:true field new_name senv
+ in
+ resolver, List.fold_left add senv str
+
+(** {6 Libraries, i.e. compiled modules } *)
+
+type compiled_library = {
+ comp_name : DirPath.t;
+ comp_mod : module_body;
+ comp_deps : library_info array;
+ comp_enga : engagement;
+ comp_natsymbs : Nativecode.symbols
+}
+
+let module_of_library lib = lib.comp_mod
+
+type native_library = Nativecode.global list
+
+let get_library_native_symbols senv dir =
+ try DPMap.find dir senv.native_symbols
+ with Not_found -> CErrors.user_err ~hdr:"get_library_native_symbols"
+ Pp.((str "Linker error in the native compiler. Are you using Require inside a nested Module declaration?") ++ fnl () ++
+ (str "This use case is not supported, but disabling the native compiler may help."))
+
+(** FIXME: MS: remove?*)
+let current_modpath senv = senv.modpath
+let current_dirpath senv = Names.ModPath.dp (current_modpath senv)
+
+let start_library dir senv =
+ check_initial senv;
+ assert (not (DirPath.is_empty dir));
+ let mp = MPfile dir in
+ mp,
+ { empty_environment with
+ env = senv.env;
+ modpath = mp;
+ modvariant = LIBRARY;
+ required = senv.required }
+
+let export ?except ~output_native_objects senv dir =
+ let senv =
+ try join_safe_environment ?except senv
+ with e ->
+ let e = CErrors.push e in
+ CErrors.user_err ~hdr:"export" (CErrors.iprint e)
+ in
+ assert(senv.future_cst = []);
+ let () = check_current_library dir senv in
+ let mp = senv.modpath in
+ let str = NoFunctor (List.rev senv.revstruct) in
+ let mb =
+ { mod_mp = mp;
+ mod_expr = FullStruct;
+ mod_type = str;
+ mod_type_alg = None;
+ mod_constraints = senv.univ;
+ mod_delta = senv.modresolver;
+ mod_retroknowledge = ModBodyRK senv.local_retroknowledge
+ }
+ in
+ let ast, symbols =
+ if output_native_objects then
+ Nativelibrary.dump_library mp dir senv.env str
+ else [], Nativecode.empty_symbols
+ in
+ let lib = {
+ comp_name = dir;
+ comp_mod = mb;
+ comp_deps = Array.of_list (DPMap.bindings senv.required);
+ comp_enga = Environ.engagement senv.env;
+ comp_natsymbs = symbols }
+ in
+ mp, lib, ast
+
+(* cst are the constraints that were computed by the vi2vo step and hence are
+ * not part of the mb.mod_constraints field (but morally should be) *)
+let import lib cst vodigest senv =
+ check_required senv.required lib.comp_deps;
+ check_engagement senv.env lib.comp_enga;
+ if DirPath.equal (ModPath.dp senv.modpath) lib.comp_name then
+ CErrors.user_err ~hdr:"Safe_typing.import"
+ (Pp.strbrk "Cannot load a library with the same name as the current one.");
+ let mp = MPfile lib.comp_name in
+ let mb = lib.comp_mod in
+ let env = Environ.push_context_set ~strict:true
+ (Univ.ContextSet.union mb.mod_constraints cst)
+ senv.env
+ in
+ mp,
+ { senv with
+ env =
+ (let linkinfo =
+ Nativecode.link_info_of_dirpath lib.comp_name
+ in
+ Modops.add_linked_module mb linkinfo env);
+ modresolver = Mod_subst.add_delta_resolver mb.mod_delta senv.modresolver;
+ required = DPMap.add lib.comp_name vodigest senv.required;
+ loads = (mp,mb)::senv.loads;
+ native_symbols = DPMap.add lib.comp_name lib.comp_natsymbs senv.native_symbols }
+
+(** {6 Safe typing } *)
+
+type judgment = Environ.unsafe_judgment
+
+let j_val j = j.Environ.uj_val
+let j_type j = j.Environ.uj_type
+
+let typing senv = Typeops.infer (env_of_senv senv)
+
+(** {6 Retroknowledge / native compiler } *)
+
+let register_inline kn senv =
+ let open Environ in
+ if not (evaluable_constant kn senv.env) then
+ CErrors.user_err Pp.(str "Register inline: an evaluable constant is expected");
+ let env = senv.env in
+ let cb = lookup_constant kn env in
+ let cb = {cb with const_inline_code = true} in
+ let env = add_constant kn cb env in { senv with env}
+
+let check_register_ind ind r env =
+ let (mb,ob as spec) = Inductive.lookup_mind_specif env ind in
+ let check_if b msg =
+ if not b then
+ CErrors.user_err ~hdr:"check_register_ind" msg in
+ check_if (Int.equal (Array.length mb.mind_packets) 1) Pp.(str "A non mutual inductive is expected");
+ let is_monomorphic = function Monomorphic _ -> true | Polymorphic _ -> false in
+ check_if (is_monomorphic mb.mind_universes) Pp.(str "A universe monomorphic inductive type is expected");
+ check_if (not @@ Inductive.is_private spec) Pp.(str "A non-private inductive type is expected");
+ let check_nparams n =
+ check_if (Int.equal mb.mind_nparams n) Pp.(str "An inductive type with " ++ int n ++ str " parameters is expected")
+ in
+ let check_nconstr n =
+ check_if (Int.equal (Array.length ob.mind_consnames) n)
+ Pp.(str "an inductive type with " ++ int n ++ str " constructors is expected")
+ in
+ let check_name pos s =
+ check_if (Id.equal ob.mind_consnames.(pos) (Id.of_string s))
+ Pp.(str"the " ++ int (pos + 1) ++ str
+ "th constructor does not have the expected name: " ++ str s) in
+ let check_type pos t =
+ check_if (Constr.equal t ob.mind_user_lc.(pos))
+ Pp.(str"the " ++ int (pos + 1) ++ str
+ "th constructor does not have the expected type") in
+ let check_type_cte pos = check_type pos (Constr.mkRel 1) in
+ match r with
+ | CPrimitives.PIT_bool ->
+ check_nparams 0;
+ check_nconstr 2;
+ check_name 0 "true";
+ check_type_cte 0;
+ check_name 1 "false";
+ check_type_cte 1
+ | CPrimitives.PIT_carry ->
+ check_nparams 1;
+ check_nconstr 2;
+ let test_type pos =
+ let c = ob.mind_user_lc.(pos) in
+ let s = Pp.(str"the " ++ int (pos + 1) ++ str
+ "th constructor does not have the expected type") in
+ check_if (Constr.isProd c) s;
+ let (_,d,cd) = Constr.destProd c in
+ check_if (Constr.is_Type d) s;
+ check_if
+ (Constr.equal
+ (mkProd (Context.anonR,mkRel 1, mkApp (mkRel 3,[|mkRel 2|])))
+ cd)
+ s in
+ check_name 0 "C0";
+ test_type 0;
+ check_name 1 "C1";
+ test_type 1;
+ | CPrimitives.PIT_pair ->
+ check_nparams 2;
+ check_nconstr 1;
+ check_name 0 "pair";
+ let c = ob.mind_user_lc.(0) in
+ let s = Pp.str "the constructor does not have the expected type" in
+ begin match Term.decompose_prod c with
+ | ([_,b;_,a;_,_B;_,_A], codom) ->
+ check_if (is_Type _A) s;
+ check_if (is_Type _B) s;
+ check_if (Constr.equal a (mkRel 2)) s;
+ check_if (Constr.equal b (mkRel 2)) s;
+ check_if (Constr.equal codom (mkApp (mkRel 5,[|mkRel 4; mkRel 3|]))) s
+ | _ -> check_if false s
+ end
+ | CPrimitives.PIT_cmp ->
+ check_nparams 0;
+ check_nconstr 3;
+ check_name 0 "Eq";
+ check_type_cte 0;
+ check_name 1 "Lt";
+ check_type_cte 1;
+ check_name 2 "Gt";
+ check_type_cte 2
+
+let register_inductive ind prim senv =
+ check_register_ind ind prim senv.env;
+ let action = Retroknowledge.Register_ind(prim,ind) in
+ add_retroknowledge action senv
+
+let add_constraints c =
+ add_constraints
+ (Now (false, Univ.ContextSet.add_constraints c Univ.ContextSet.empty))
+
+
+(* NB: The next old comment probably refers to [propagate_loads] above.
+ When a Require is done inside a module, we'll redo this require
+ at the upper level after the module is ended, and so on.
+ This is probably not a big deal anyway, since these Require's
+ inside modules should be pretty rare. Maybe someday we could
+ brutally forbid this tricky "feature"... *)
+
+(* we have an inefficiency: Since loaded files are added to the
+environment every time a module is closed, their components are
+calculated many times. This could be avoided in several ways:
+
+1 - for each file create a dummy environment containing only this
+file's components, merge this environment with the global
+environment, and store for the future (instead of just its type)
+
+2 - create "persistent modules" environment table in Environ add put
+loaded by side-effect once and for all (like it is done in OCaml).
+Would this be correct with respect to undo's and stuff ?
+*)
+
+let set_strategy k l e = { e with env =
+ (Environ.set_oracle e.env
+ (Conv_oracle.set_strategy (Environ.oracle e.env) k l)) }