diff options
Diffstat (limited to 'library/declare.ml')
-rw-r--r-- | library/declare.ml | 356 |
1 files changed, 267 insertions, 89 deletions
diff --git a/library/declare.ml b/library/declare.ml index d6413d3d..7f42a747 100644 --- a/library/declare.ml +++ b/library/declare.ml @@ -1,6 +1,6 @@ (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) -(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *) +(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) @@ -9,12 +9,13 @@ (** This module is about the low-level declaration of logical objects *) open Pp +open Errors open Util open Names open Libnames +open Globnames open Nameops open Term -open Sign open Declarations open Entries open Libobject @@ -31,55 +32,44 @@ type internal_flag = | KernelSilent (* kernel action, no message is displayed *) | UserVerbose (* user action, a message is displayed *) -(** XML output hooks *) - -let xml_declare_variable = ref (fun (sp:object_name) -> ()) -let xml_declare_constant = ref (fun (sp:internal_flag * constant)-> ()) -let xml_declare_inductive = ref (fun (sp:internal_flag * object_name) -> ()) - -let if_xml f x = if !Flags.xml_export then f x else () - -let set_xml_declare_variable f = xml_declare_variable := if_xml f -let set_xml_declare_constant f = xml_declare_constant := if_xml f -let set_xml_declare_inductive f = xml_declare_inductive := if_xml f - -let cache_hook = ref ignore -let add_cache_hook f = cache_hook := f - (** Declaration of section variables and local definitions *) type section_variable_entry = - | SectionLocalDef of constr * types option * bool (* opacity *) - | SectionLocalAssum of types * bool (* Implicit status *) + | SectionLocalDef of definition_entry + | SectionLocalAssum of types Univ.in_universe_context_set * polymorphic * bool (** Implicit status *) -type variable_declaration = dir_path * section_variable_entry * logical_kind +type variable_declaration = DirPath.t * section_variable_entry * logical_kind let cache_variable ((sp,_),o) = match o with - | Inl cst -> Global.add_constraints cst + | Inl ctx -> Global.push_context_set ctx | Inr (id,(p,d,mk)) -> (* Constr raisonne sur les noms courts *) if variable_exists id then alreadydeclared (pr_id id ++ str " already exists"); - let impl,opaq,cst = match d with (* Fails if not well-typed *) - | SectionLocalAssum (ty, impl) -> - let cst = Global.push_named_assum (id,ty) in - let impl = if impl then Lib.Implicit else Lib.Explicit in - impl, true, cst - | SectionLocalDef (c,t,opaq) -> - let cst = Global.push_named_def (id,c,t) in - Lib.Explicit, opaq, cst in + + let impl,opaq,poly,ctx = match d with (* Fails if not well-typed *) + | SectionLocalAssum ((ty,ctx),poly,impl) -> + let () = Global.push_named_assum ((id,ty),ctx) in + let impl = if impl then Implicit else Explicit in + impl, true, poly, ctx + | SectionLocalDef (de) -> + let () = Global.push_named_def (id,de) in + Explicit, de.const_entry_opaque, de.const_entry_polymorphic, + (Univ.ContextSet.of_context de.const_entry_universes) in Nametab.push (Nametab.Until 1) (restrict_path 0 sp) (VarRef id); - add_section_variable id impl; + add_section_variable id impl poly ctx; Dischargedhypsmap.set_discharged_hyps sp []; - add_variable_data id (p,opaq,cst,mk) + add_variable_data id (p,opaq,ctx,poly,mk) let discharge_variable (_,o) = match o with - | Inr (id,_) -> Some (Inl (variable_constraints id)) + | Inr (id,_) -> + if variable_polymorphic id then None + else Some (Inl (variable_context id)) | Inl _ -> Some o type variable_obj = - (Univ.constraints, identifier * variable_declaration) union + (Univ.ContextSet.t, Id.t * variable_declaration) union let inVariable : variable_obj -> obj = declare_object { (default_object "VARIABLE") with @@ -93,70 +83,90 @@ let declare_variable id obj = declare_var_implicits id; Notation.declare_ref_arguments_scope (VarRef id); Heads.declare_head (EvalVarRef id); - !xml_declare_variable oname; oname (** Declaration of constants and parameters *) +type constant_obj = { + cst_decl : global_declaration; + cst_hyps : Dischargedhypsmap.discharged_hyps; + cst_kind : logical_kind; + cst_locl : bool; +} + type constant_declaration = constant_entry * logical_kind (* At load-time, the segment starting from the module name to the discharge *) (* section (if Remark or Fact) is needed to access a construction *) -let load_constant i ((sp,kn),(_,_,kind)) = +let load_constant i ((sp,kn), obj) = if Nametab.exists_cci sp then alreadydeclared (pr_id (basename sp) ++ str " already exists"); let con = Global.constant_of_delta_kn kn in Nametab.push (Nametab.Until i) sp (ConstRef con); - add_constant_kind con kind + add_constant_kind con obj.cst_kind (* Opening means making the name without its module qualification available *) -let open_constant i ((sp,kn),_) = - let con = Global.constant_of_delta_kn kn in - Nametab.push (Nametab.Exactly i) sp (ConstRef con) +let open_constant i ((sp,kn), obj) = + (** Never open a local definition *) + if obj.cst_locl then () + else + let con = Global.constant_of_delta_kn kn in + Nametab.push (Nametab.Exactly i) sp (ConstRef con); + match (Global.lookup_constant con).const_body with + | (Def _ | Undef _) -> () + | OpaqueDef lc -> + match Opaqueproof.get_constraints (Global.opaque_tables ())lc with + | Some f when Future.is_val f -> Global.push_context_set (Future.force f) + | _ -> () let exists_name id = - variable_exists id or Global.exists_objlabel (label_of_id id) + variable_exists id || Global.exists_objlabel (Label.of_id id) let check_exists sp = let id = basename sp in if exists_name id then alreadydeclared (pr_id id ++ str " already exists") -let cache_constant ((sp,kn),(cdt,dhyps,kind)) = +let cache_constant ((sp,kn), obj) = let id = basename sp in let _,dir,_ = repr_kn kn in - check_exists sp; - let kn' = Global.add_constant dir id cdt in - assert (kn' = constant_of_kn kn); + let () = check_exists sp in + let kn' = Global.add_constant dir id obj.cst_decl in + assert (eq_constant kn' (constant_of_kn kn)); Nametab.push (Nametab.Until 1) sp (ConstRef (constant_of_kn kn)); - add_section_constant kn' (Global.lookup_constant kn').const_hyps; - Dischargedhypsmap.set_discharged_hyps sp dhyps; - add_constant_kind (constant_of_kn kn) kind; - !cache_hook sp + let cst = Global.lookup_constant kn' in + add_section_constant (cst.const_proj <> None) kn' cst.const_hyps; + Dischargedhypsmap.set_discharged_hyps sp obj.cst_hyps; + add_constant_kind (constant_of_kn kn) obj.cst_kind let discharged_hyps kn sechyps = let (_,dir,_) = repr_kn kn in let args = Array.to_list (instance_from_variable_context sechyps) in - List.rev (List.map (Libnames.make_path dir) args) + List.rev_map (Libnames.make_path dir) args -let discharge_constant ((sp,kn),(cdt,dhyps,kind)) = +let discharge_constant ((sp, kn), obj) = let con = constant_of_kn kn in - let cb = Global.lookup_constant con in - let repl = replacement_context () in - let sechyps = section_segment_of_constant con in - let recipe = { d_from=cb; d_modlist=repl; d_abstract=named_of_variable_context sechyps } in - Some (GlobalRecipe recipe,(discharged_hyps kn sechyps)@dhyps,kind) + let from = Global.lookup_constant con in + let modlist = replacement_context () in + let hyps,subst,uctx = section_segment_of_constant con in + let new_hyps = (discharged_hyps kn hyps) @ obj.cst_hyps in + let abstract = (named_of_variable_context hyps, subst, uctx) in + let new_decl = GlobalRecipe{ from; info = { Opaqueproof.modlist; abstract}} in + Some { obj with cst_hyps = new_hyps; cst_decl = new_decl; } (* Hack to reduce the size of .vo: we keep only what load/open needs *) -let dummy_constant_entry = ConstantEntry (ParameterEntry (None,mkProp,None)) - -let dummy_constant (ce,_,mk) = dummy_constant_entry,[],mk +let dummy_constant_entry = + ConstantEntry (ParameterEntry (None,false,(mkProp,Univ.UContext.empty),None)) + +let dummy_constant cst = { + cst_decl = dummy_constant_entry; + cst_hyps = []; + cst_kind = cst.cst_kind; + cst_locl = cst.cst_locl; +} let classify_constant cst = Substitute (dummy_constant cst) -type constant_obj = - global_declaration * Dischargedhypsmap.discharged_hyps * logical_kind - let inConstant : constant_obj -> obj = declare_object { (default_object "CONSTANT") with cache_function = cache_constant; @@ -166,23 +176,125 @@ let inConstant : constant_obj -> obj = subst_function = ident_subst_function; discharge_function = discharge_constant } -let declare_constant_common id dhyps (cd,kind) = - let (sp,kn) = add_leaf id (inConstant (cd,dhyps,kind)) in +let declare_constant_common id cst = + let (sp,kn) = add_leaf id (inConstant cst) in let c = Global.constant_of_delta_kn kn in declare_constant_implicits c; Heads.declare_head (EvalConstRef c); Notation.declare_ref_arguments_scope (ConstRef c); c -let declare_constant ?(internal = UserVerbose) id (cd,kind) = - let kn = declare_constant_common id [] (ConstantEntry cd,kind) in - !xml_declare_constant (internal,kn); +let definition_entry ?(opaque=false) ?(inline=false) ?types + ?(poly=false) ?(univs=Univ.UContext.empty) ?(eff=Declareops.no_seff) body = + { const_entry_body = Future.from_val ((body,Univ.ContextSet.empty), eff); + const_entry_secctx = None; + const_entry_type = types; + const_entry_polymorphic = poly; + const_entry_universes = univs; + const_entry_opaque = opaque; + const_entry_feedback = None; + const_entry_inline_code = inline} + +let declare_scheme = ref (fun _ _ -> assert false) +let set_declare_scheme f = declare_scheme := f +let declare_sideff env fix_exn se = + let cbl, scheme = match se with + | SEsubproof (c, cb, pt) -> [c, cb, pt], None + | SEscheme (cbl, k) -> + List.map (fun (_,c,cb,pt) -> c,cb,pt) cbl, Some (cbl,k) in + let id_of c = Names.Label.to_id (Names.Constant.label c) in + let pt_opaque_of cb pt = + match cb, pt with + | { const_body = Def sc }, _ -> (Mod_subst.force_constr sc, Univ.ContextSet.empty), false + | { const_body = OpaqueDef _ }, `Opaque(pt,univ) -> (pt, univ), true + | _ -> assert false + in + let ty_of cb = + match cb.Declarations.const_type with + | Declarations.RegularArity t -> Some t + | Declarations.TemplateArity _ -> None in + let cst_of cb pt = + let pt, opaque = pt_opaque_of cb pt in + let univs, subst = + if cb.const_polymorphic then + let univs = Univ.instantiate_univ_context cb.const_universes in + univs, Vars.subst_instance_constr (Univ.UContext.instance univs) + else cb.const_universes, fun x -> x + in + let pt = (subst (fst pt), snd pt) in + let ty = Option.map subst (ty_of cb) in + { cst_decl = ConstantEntry (DefinitionEntry { + const_entry_body = Future.from_here ~fix_exn (pt, Declareops.no_seff); + const_entry_secctx = Some cb.Declarations.const_hyps; + const_entry_type = ty; + const_entry_opaque = opaque; + const_entry_inline_code = false; + const_entry_feedback = None; + const_entry_polymorphic = cb.const_polymorphic; + const_entry_universes = univs; + }); + cst_hyps = [] ; + cst_kind = Decl_kinds.IsDefinition Decl_kinds.Definition; + cst_locl = true; + } in + let exists c = + try ignore(Environ.lookup_constant c env); true + with Not_found -> false in + let knl = + CList.map_filter (fun (c,cb,pt) -> + if exists c then None + else Some (c,declare_constant_common (id_of c) (cst_of cb pt))) cbl in + match scheme with + | None -> () + | Some (inds_consts,kind) -> + !declare_scheme kind (Array.of_list + (List.map (fun (c,kn) -> + CList.find_map (fun (x,c',_,_) -> + if Constant.equal c c' then Some (x,kn) else None) inds_consts) + knl)) + +let declare_constant ?(internal = UserVerbose) ?(local = false) id (cd, kind) = + let cd = (* We deal with side effects of non-opaque constants *) + match cd with + | Entries.DefinitionEntry ({ + const_entry_opaque = false; const_entry_body = bo } as de) + | Entries.DefinitionEntry ({ + const_entry_polymorphic = true; const_entry_body = bo } as de) + -> + let _, seff = Future.force bo in + if Declareops.side_effects_is_empty seff then cd + else begin + let seff = Declareops.uniquize_side_effects seff in + Declareops.iter_side_effects + (declare_sideff (Global.env ()) (Future.fix_exn_of bo)) seff; + Entries.DefinitionEntry { de with + const_entry_body = Future.chain ~pure:true bo (fun (pt, _) -> + pt, Declareops.no_seff) } + end + | _ -> cd + in + let cst = { + cst_decl = ConstantEntry cd; + cst_hyps = [] ; + cst_kind = kind; + cst_locl = local; + } in + let kn = declare_constant_common id cst in kn +let declare_definition ?(internal=UserVerbose) + ?(opaque=false) ?(kind=Decl_kinds.Definition) ?(local = false) + ?(poly=false) id ?types (body,ctx) = + let cb = + definition_entry ?types ~poly ~univs:(Univ.ContextSet.to_context ctx) ~opaque body + in + declare_constant ~internal ~local id + (Entries.DefinitionEntry cb, Decl_kinds.IsDefinition kind) + (** Declaration of inductive blocks *) let declare_inductive_argument_scopes kn mie = - list_iter_i (fun i {mind_entry_consnames=lc} -> + List.iteri (fun i {mind_entry_consnames=lc} -> Notation.declare_ref_arguments_scope (IndRef (kn,i)); for j=1 to List.length lc do Notation.declare_ref_arguments_scope (ConstructRef ((kn,i),j)); @@ -223,24 +335,24 @@ let cache_inductive ((sp,kn),(dhyps,mie)) = let id = basename sp in let _,dir,_ = repr_kn kn in let kn' = Global.add_mind dir id mie in - assert (kn'= mind_of_kn kn); - add_section_kn kn' (Global.lookup_mind kn').mind_hyps; + assert (eq_mind kn' (mind_of_kn kn)); + let mind = Global.lookup_mind kn' in + add_section_kn kn' mind.mind_hyps; Dischargedhypsmap.set_discharged_hyps sp dhyps; - List.iter (fun (sp, ref) -> Nametab.push (Nametab.Until 1) sp ref) names; - List.iter (fun (sp,_) -> !cache_hook sp) (inductive_names sp kn mie) - + List.iter (fun (sp, ref) -> Nametab.push (Nametab.Until 1) sp ref) names let discharge_inductive ((sp,kn),(dhyps,mie)) = let mind = Global.mind_of_delta_kn kn in let mie = Global.lookup_mind mind in let repl = replacement_context () in - let sechyps = section_segment_of_mutual_inductive mind in + let sechyps,usubst,uctx = section_segment_of_mutual_inductive mind in Some (discharged_hyps kn sechyps, - Discharge.process_inductive (named_of_variable_context sechyps) repl mie) + Discharge.process_inductive (named_of_variable_context sechyps,uctx) repl mie) let dummy_one_inductive_entry mie = { mind_entry_typename = mie.mind_entry_typename; mind_entry_arity = mkProp; + mind_entry_template = false; mind_entry_consnames = mie.mind_entry_consnames; mind_entry_lc = [] } @@ -248,9 +360,12 @@ let dummy_one_inductive_entry mie = { (* Hack to reduce the size of .vo: we keep only what load/open needs *) let dummy_inductive_entry (_,m) = ([],{ mind_entry_params = []; - mind_entry_record = false; - mind_entry_finite = true; - mind_entry_inds = List.map dummy_one_inductive_entry m.mind_entry_inds }) + mind_entry_record = None; + mind_entry_finite = Decl_kinds.BiFinite; + mind_entry_inds = List.map dummy_one_inductive_entry m.mind_entry_inds; + mind_entry_polymorphic = false; + mind_entry_universes = Univ.UContext.empty; + mind_entry_private = None }) type inductive_obj = Dischargedhypsmap.discharged_hyps * mutual_inductive_entry @@ -263,25 +378,38 @@ let inInductive : inductive_obj -> obj = subst_function = ident_subst_function; discharge_function = discharge_inductive } +let declare_projections mind = + let spec,_ = Inductive.lookup_mind_specif (Global.env ()) (mind,0) in + match spec.mind_record with + | Some (Some (_, kns, pjs)) -> + Array.iteri (fun i kn -> + let id = Label.to_id (Constant.label kn) in + let entry = {proj_entry_ind = mind; proj_entry_arg = i} in + let kn' = declare_constant id (ProjectionEntry entry, + IsDefinition StructureComponent) + in + assert(eq_constant kn kn')) kns; true + | Some None | None -> false + (* for initial declaration *) -let declare_mind isrecord mie = +let declare_mind mie = let id = match mie.mind_entry_inds with | ind::_ -> ind.mind_entry_typename - | [] -> anomaly "cannot declare an empty list of inductives" in + | [] -> anomaly (Pp.str "cannot declare an empty list of inductives") in let (sp,kn as oname) = add_leaf id (inInductive ([],mie)) in let mind = Global.mind_of_delta_kn kn in + let isprim = declare_projections mind in declare_mib_implicits mind; declare_inductive_argument_scopes mind mie; - !xml_declare_inductive (isrecord,oname); - oname + oname, isprim (* Declaration messages *) -let pr_rank i = str (ordinal (i+1)) +let pr_rank i = pr_nth (i+1) let fixpoint_message indexes l = - Flags.if_verbose msgnl (match l with - | [] -> anomaly "no recursive definition" + Flags.if_verbose msg_info (match l with + | [] -> anomaly (Pp.str "no recursive definition") | [id] -> pr_id id ++ str " is recursively defined" ++ (match indexes with | Some [|i|] -> str " (decreasing on "++pr_rank i++str " argument)" @@ -290,13 +418,13 @@ let fixpoint_message indexes l = spc () ++ str "are recursively defined" ++ match indexes with | Some a -> spc () ++ str "(decreasing respectively on " ++ - prlist_with_sep pr_comma pr_rank (Array.to_list a) ++ + prvect_with_sep pr_comma pr_rank a ++ str " arguments)" | None -> mt ())) let cofixpoint_message l = - Flags.if_verbose msgnl (match l with - | [] -> anomaly "No corecursive definition." + Flags.if_verbose msg_info (match l with + | [] -> anomaly (Pp.str "No corecursive definition.") | [id] -> pr_id id ++ str " is corecursively defined" | l -> hov 0 (prlist_with_sep pr_comma pr_id l ++ spc () ++ str "are corecursively defined")) @@ -305,7 +433,57 @@ let recursive_message isfix i l = (if isfix then fixpoint_message i else cofixpoint_message) l let definition_message id = - Flags.if_verbose msgnl (pr_id id ++ str " is defined") + Flags.if_verbose msg_info (pr_id id ++ str " is defined") let assumption_message id = - Flags.if_verbose msgnl (pr_id id ++ str " is assumed") + Flags.if_verbose msg_info (pr_id id ++ str " is assumed") + +(** Global universe names, in a different summary *) + +type universe_names = + (Univ.universe_level Idmap.t * Id.t Univ.LMap.t) + +let input_universes : universe_names -> Libobject.obj = + let open Libobject in + declare_object + { (default_object "Global universe name state") with + cache_function = (fun (na, pi) -> Universes.set_global_universe_names pi); + load_function = (fun _ (_, pi) -> Universes.set_global_universe_names pi); + discharge_function = (fun (_, a) -> Some a); + classify_function = (fun a -> Keep a) } + +let do_universe l = + let glob = Universes.global_universe_names () in + let glob' = + List.fold_left (fun (idl,lid) (l, id) -> + let lev = Universes.new_univ_level (Global.current_dirpath ()) in + (Idmap.add id lev idl, Univ.LMap.add lev id lid)) + glob l + in + Lib.add_anonymous_leaf (input_universes glob') + + +let input_constraints : Univ.constraints -> Libobject.obj = + let open Libobject in + declare_object + { (default_object "Global universe constraints") with + cache_function = (fun (na, c) -> Global.add_constraints c); + load_function = (fun _ (_, c) -> Global.add_constraints c); + discharge_function = (fun (_, a) -> Some a); + classify_function = (fun a -> Keep a) } + +let do_constraint l = + let u_of_id = + let names, _ = Universes.global_universe_names () in + fun (loc, id) -> + try Idmap.find id names + with Not_found -> + user_err_loc (loc, "Constraint", str "Undeclared universe " ++ pr_id id) + in + let constraints = List.fold_left (fun acc (l, d, r) -> + let lu = u_of_id l and ru = u_of_id r in + Univ.Constraint.add (lu, d, ru) acc) + Univ.Constraint.empty l + in + Lib.add_anonymous_leaf (input_constraints constraints) + |