aboutsummaryrefslogtreecommitdiff
path: root/toplevel/command.ml
diff options
context:
space:
mode:
Diffstat (limited to 'toplevel/command.ml')
-rw-r--r--toplevel/command.ml968
1 files changed, 141 insertions, 827 deletions
diff --git a/toplevel/command.ml b/toplevel/command.ml
index 34afbbcd50..67660cab34 100644
--- a/toplevel/command.ml
+++ b/toplevel/command.ml
@@ -13,54 +13,25 @@ open Util
open Flags
open Term
open Termops
-open Declarations
open Entries
-open Inductive
open Environ
-open Reduction
open Redexpr
open Declare
-open Nametab
open Names
open Libnames
open Nameops
open Topconstr
-open Library
-open Libobject
open Constrintern
-open Proof_type
-open Tacmach
-open Safe_typing
open Nametab
open Impargs
-open Typeops
open Reductionops
open Indtypes
-open Vernacexpr
open Decl_kinds
open Pretyping
open Evarutil
open Evarconv
open Notation
-open Goptions
-open Mod_subst
-open Evd
-open Decls
-open Smartlocate
-
-let rec abstract_constr_expr c = function
- | [] -> c
- | LocalRawDef (x,b)::bl -> mkLetInC(x,b,abstract_constr_expr c bl)
- | LocalRawAssum (idl,k,t)::bl ->
- List.fold_right (fun x b -> mkLambdaC([x],k,t,b)) idl
- (abstract_constr_expr c bl)
-
-let rec generalize_constr_expr c = function
- | [] -> c
- | LocalRawDef (x,b)::bl -> mkLetInC(x,b,generalize_constr_expr c bl)
- | LocalRawAssum (idl,k,t)::bl ->
- List.fold_right (fun x b -> mkProdC([x],k,t,b)) idl
- (generalize_constr_expr c bl)
+open Indschemes
let rec under_binders env f n c =
if n = 0 then f env Evd.empty c else
@@ -88,23 +59,30 @@ let rec complete_conclusion a cs = function
(* 1| Constant definitions *)
-let definition_message id =
- if_verbose message ((string_of_id id) ^ " is defined")
+let red_constant_entry bl ce = function
+ | None -> ce
+ | Some red ->
+ let body = ce.const_entry_body in
+ { ce with const_entry_body =
+ under_binders (Global.env()) (fst (reduction_of_red_expr red))
+ (local_binders_length bl)
+ body }
-let constant_entry_of_com (bl,com,comtypopt,opacity,boxed) =
+let interp_definition boxed bl red_option c ctypopt =
let env = Global.env() in
- match comtypopt with
+ let imps,ce =
+ match ctypopt with
None ->
- let b = abstract_constr_expr com bl in
+ let b = abstract_constr_expr c bl in
let b, imps = interp_constr_evars_impls env b in
imps,
{ const_entry_body = b;
const_entry_type = None;
- const_entry_opaque = opacity;
+ const_entry_opaque = false;
const_entry_boxed = boxed }
- | Some comtyp ->
- let ty = generalize_constr_expr comtyp bl in
- let b = abstract_constr_expr com bl in
+ | Some ctyp ->
+ let ty = prod_constr_expr ctyp bl in
+ let b = abstract_constr_expr c bl in
let evdref = ref Evd.empty in
let ty, impls = interp_type_evars_impls ~evdref ~fail_evar:false env ty in
let b, imps = interp_casted_constr_evars_impls ~evdref ~fail_evar:false env b ty in
@@ -114,20 +92,13 @@ let constant_entry_of_com (bl,com,comtypopt,opacity,boxed) =
imps,
{ const_entry_body = body;
const_entry_type = Some typ;
- const_entry_opaque = opacity;
+ const_entry_opaque = false;
const_entry_boxed = boxed }
+ in
+ red_constant_entry bl ce red_option, imps
-let red_constant_entry bl ce = function
- | None -> ce
- | Some red ->
- let body = ce.const_entry_body in
- { ce with const_entry_body =
- under_binders (Global.env()) (fst (reduction_of_red_expr red))
- (local_binders_length bl)
- body }
-
-let declare_global_definition ident ce local imps =
- let kn = declare_constant ident (DefinitionEntry ce,IsDefinition Definition) in
+let declare_global_definition ident ce local k imps =
+ let kn = declare_constant ident (DefinitionEntry ce,IsDefinition k) in
let gr = ConstRef kn in
maybe_declare_manual_implicits false gr imps;
if local = Local && Flags.is_verbose() then
@@ -140,15 +111,13 @@ let declare_definition_hook = ref ignore
let set_declare_definition_hook = (:=) declare_definition_hook
let get_declare_definition_hook () = !declare_definition_hook
-let declare_definition ident (local,boxed,dok) bl red_option c typopt hook =
- let imps, ce = constant_entry_of_com (bl,c,typopt,false,boxed) in
- let ce' = red_constant_entry bl ce red_option in
- !declare_definition_hook ce';
+let declare_definition ident (local,k) ce imps hook =
+ !declare_definition_hook ce;
let r = match local with
| Local when Lib.sections_are_opened () ->
let c =
- SectionLocalDef(ce'.const_entry_body,ce'.const_entry_type,false) in
- let _ = declare_variable ident (Lib.cwd(),c,IsDefinition Definition) in
+ SectionLocalDef(ce.const_entry_body,ce.const_entry_type,false) in
+ let _ = declare_variable ident (Lib.cwd(),c,IsDefinition k) in
definition_message ident;
if Pfedit.refining () then
Flags.if_verbose msg_warning
@@ -156,20 +125,12 @@ let declare_definition ident (local,boxed,dok) bl red_option c typopt hook =
str" is not visible from current goals");
VarRef ident
| (Global|Local) ->
- declare_global_definition ident ce' local imps in
+ declare_global_definition ident ce local k imps in
hook local r
-let syntax_definition ident (vars,c) local onlyparse =
- let ((vars,_),pat) = interp_aconstr [] (vars,[]) c in
- let onlyparse = onlyparse or Metasyntax.is_not_printable pat in
- Syntax_def.declare_syntactic_definition local ident onlyparse (vars,pat)
-
(* 2| Variable/Hypothesis/Parameter/Axiom declarations *)
-let assumption_message id =
- if_verbose message ((string_of_id id) ^ " is assumed")
-
-let declare_one_assumption is_coe (local,kind) c imps impl nl (_,ident) =
+let declare_assumption is_coe (local,kind) c imps impl nl (_,ident) =
let r = match local with
| Local when Lib.sections_are_opened () ->
let _ =
@@ -193,286 +154,22 @@ let declare_one_assumption is_coe (local,kind) c imps impl nl (_,ident) =
gr in
if is_coe then Class.try_add_new_coercion r local
-let declare_assumption_hook = ref ignore
-let set_declare_assumption_hook = (:=) declare_assumption_hook
-
-let declare_assumption idl is_coe k bl c impl nl =
- if not (Pfedit.refining ()) then
- let c = generalize_constr_expr c bl in
- let env = Global.env () in
- let c', imps = interp_type_evars_impls env c in
- !declare_assumption_hook c';
- List.iter (declare_one_assumption is_coe k c' imps impl nl) idl
- else
- errorlabstrm "Command.Assumption"
- (str "Cannot declare an assumption while in proof editing mode.")
-
-(* 3a| Elimination schemes for mutual inductive definitions *)
-
-open Indrec
-open Inductiveops
+let declare_assumptions_hook = ref ignore
+let set_declare_assumptions_hook = (:=) declare_assumptions_hook
+let interp_assumption bl c =
+ let c = prod_constr_expr c bl in
+ let env = Global.env () in
+ interp_type_evars_impls env c
-let non_type_eliminations =
- [ (InProp,elimination_suffix InProp);
- (InSet,elimination_suffix InSet) ]
+let declare_assumptions idl is_coe k c imps impl_is_on nl =
+ !declare_assumptions_hook c;
+ List.iter (declare_assumption is_coe k c imps impl_is_on nl) idl
-let declare_one_elimination ind =
- let (mib,mip) = Global.lookup_inductive ind in
- let mindstr = string_of_id mip.mind_typename in
- let declare s c t =
- let id = id_of_string s in
- let kn = Declare.declare_internal_constant id
- (DefinitionEntry
- { const_entry_body = c;
- const_entry_type = t;
- const_entry_opaque = false;
- const_entry_boxed = Flags.boxed_definitions() },
- Decl_kinds.IsDefinition Definition) in
- definition_message id;
- kn
- in
- let env = Global.env () in
- let sigma = Evd.empty in
- let elim_scheme = Indrec.build_indrec env sigma ind in
- let npars =
- (* if a constructor of [ind] contains a recursive call, the scheme
- is generalized only wrt recursively uniform parameters *)
- if (Inductiveops.mis_is_recursive_subset [snd ind] mip.mind_recargs)
- then
- mib.mind_nparams_rec
- else
- mib.mind_nparams in
- let make_elim s = Indrec.instantiate_indrec_scheme s npars elim_scheme in
- let kelim = elim_sorts (mib,mip) in
- (* in case the inductive has a type elimination, generates only one
- induction scheme, the other ones share the same code with the
- apropriate type *)
- if List.mem InType kelim then
- let elim = make_elim (new_sort_in_family InType) in
- let cte = declare (mindstr^(Indrec.elimination_suffix InType)) elim None in
- let c = mkConst cte in
- let t = type_of_constant (Global.env()) cte in
- List.iter (fun (sort,suff) ->
- let (t',c') =
- Indrec.instantiate_type_indrec_scheme (new_sort_in_family sort)
- npars c t in
- let _ = declare (mindstr^suff) c' (Some t') in ())
- non_type_eliminations
- else (* Impredicative or logical inductive definition *)
- List.iter
- (fun (sort,suff) ->
- if List.mem sort kelim then
- let elim = make_elim (new_sort_in_family sort) in
- let _ = declare (mindstr^suff) elim None in ())
- non_type_eliminations
-
-(* bool eq declaration flag && eq dec declaration flag *)
-let eq_flag = ref false
-let _ =
- declare_bool_option
- { optsync = true;
- optname = "automatic declaration of boolean equality";
- optkey = ["Equality";"Scheme"];
- optread = (fun () -> !eq_flag) ;
- optwrite = (fun b -> eq_flag := b) }
-
-(* boolean equality *)
-let (inScheme,_) =
- declare_object {(default_object "EQSCHEME") with
- cache_function = Ind_tables.cache_scheme;
- load_function = (fun _ -> Ind_tables.cache_scheme);
- subst_function = Auto_ind_decl.subst_in_constr }
-
-let declare_eq_scheme sp =
- let mib = Global.lookup_mind sp in
- let nb_ind = Array.length mib.mind_packets in
- let eq_array = Auto_ind_decl.make_eq_scheme sp in
- try
- for i=0 to (nb_ind-1) do
- let cpack = Array.get mib.mind_packets i in
- let nam = id_of_string ((string_of_id cpack.mind_typename)^"_beq")
- in
- let cst_entry = {const_entry_body = eq_array.(i);
- const_entry_type = None;
- const_entry_opaque = false;
- const_entry_boxed = Flags.boxed_definitions() }
- in
- let cst_decl = (DefinitionEntry cst_entry),(IsDefinition Definition)
- in
- let cst = Declare.declare_constant nam cst_decl in
- Lib.add_anonymous_leaf (inScheme ((sp,i),mkConst cst));
- definition_message nam
- done
- with Not_found ->
- error "Your type contains Parameters without a boolean equality."
-
-(* decidability of eq *)
-
-
-let (inBoolLeib,_) =
- declare_object {(default_object "BOOLLIEB") with
- cache_function = Ind_tables.cache_bl;
- load_function = (fun _ -> Ind_tables.cache_bl);
- subst_function = Auto_ind_decl.subst_in_constr }
-
-let (inLeibBool,_) =
- declare_object {(default_object "LIEBBOOL") with
- cache_function = Ind_tables.cache_lb;
- load_function = (fun _ -> Ind_tables.cache_lb);
- subst_function = Auto_ind_decl.subst_in_constr }
-
-let (inDec,_) =
- declare_object {(default_object "EQDEC") with
- cache_function = Ind_tables.cache_dec;
- load_function = (fun _ -> Ind_tables.cache_dec);
- subst_function = Auto_ind_decl.subst_in_constr }
-
-let start_hook = ref ignore
-let set_start_hook = (:=) start_hook
-
-let start_proof id kind c ?init_tac ?(compute_guard=false) hook =
- let sign = Global.named_context () in
- let sign = clear_proofs sign in
- !start_hook c;
- Pfedit.start_proof id kind sign c ?init_tac ~compute_guard hook
-
-let adjust_guardness_conditions const =
- (* Try all combinations... not optimal *)
- match kind_of_term const.const_entry_body with
- | Fix ((nv,0),(_,_,fixdefs as fixdecls)) ->
- let possible_indexes =
- List.map (fun c ->
- interval 0 (List.length ((lam_assum c))))
- (Array.to_list fixdefs) in
- let indexes = search_guard dummy_loc (Global.env()) possible_indexes fixdecls in
- { const with const_entry_body = mkFix ((indexes,0),fixdecls) }
- | c -> const
-
-let save id const do_guard (locality,kind) hook =
- let const = if do_guard then adjust_guardness_conditions const else const in
- let {const_entry_body = pft;
- const_entry_type = tpo;
- const_entry_opaque = opacity } = const in
- let k = logical_kind_of_goal_kind kind in
- let l,r = match locality with
- | Local when Lib.sections_are_opened () ->
- let c = SectionLocalDef (pft, tpo, opacity) in
- let _ = declare_variable id (Lib.cwd(), c, k) in
- (Local, VarRef id)
- | Local | Global ->
- let kn = declare_constant id (DefinitionEntry const, k) in
- Autoinstance.search_declaration (ConstRef kn);
- (Global, ConstRef kn) in
- Pfedit.delete_current_proof ();
- definition_message id;
- hook l r
-
-let save_hook = ref ignore
-let set_save_hook f = save_hook := f
-
-let save_named opacity =
- let id,(const,do_guard,persistence,hook) = Pfedit.cook_proof !save_hook in
- let const = { const with const_entry_opaque = opacity } in
- save id const do_guard persistence hook
-
-let make_eq_decidability ind =
- (* fetching data *)
- let mib = Global.lookup_mind (fst ind) in
- let nparams = mib.mind_nparams in
- let nparrec = mib.mind_nparams_rec in
- let lnonparrec,lnamesparrec =
- context_chop (nparams-nparrec) mib.mind_params_ctxt in
- let proof_name = (string_of_id(
- Array.get mib.mind_packets (snd ind)).mind_typename)^"_eq_dec" in
- let bl_name =(string_of_id(
- Array.get mib.mind_packets (snd ind)).mind_typename)^"_dec_bl" in
- let lb_name =(string_of_id(
- Array.get mib.mind_packets (snd ind)).mind_typename)^"_dec_lb" in
- (* main calls*)
- if Ind_tables.check_bl_proof ind
- then (message (bl_name^" is already declared."))
- else (
- start_proof (id_of_string bl_name)
- (Global,Proof Theorem)
- (Auto_ind_decl.compute_bl_goal ind lnamesparrec nparrec)
- (fun _ _ -> ());
- Auto_ind_decl.compute_bl_tact ind lnamesparrec nparrec;
- save_named true;
- Lib.add_anonymous_leaf
- (inBoolLeib (ind,mkConst (Lib.make_con (id_of_string bl_name))))
-(* definition_message (id_of_string bl_name) *)
- );
- if Ind_tables.check_lb_proof ind
- then (message (lb_name^" is already declared."))
- else (
- start_proof (id_of_string lb_name)
- (Global,Proof Theorem)
- (Auto_ind_decl.compute_lb_goal ind lnamesparrec nparrec)
- ( fun _ _ -> ());
- Auto_ind_decl.compute_lb_tact ind lnamesparrec nparrec;
- save_named true;
- Lib.add_anonymous_leaf
- (inLeibBool (ind,mkConst (Lib.make_con (id_of_string lb_name))))
-(* definition_message (id_of_string lb_name) *)
- );
- if Ind_tables.check_dec_proof ind
- then (message (proof_name^" is already declared."))
- else (
- start_proof (id_of_string proof_name)
- (Global,Proof Theorem)
- (Auto_ind_decl.compute_dec_goal ind lnamesparrec nparrec)
- ( fun _ _ -> ());
- Auto_ind_decl.compute_dec_tact ind lnamesparrec nparrec;
- save_named true;
- Lib.add_anonymous_leaf
- (inDec (ind,mkConst (Lib.make_con (id_of_string proof_name))))
-(* definition_message (id_of_string proof_name) *)
- )
-
-(* end of automated definition on ind*)
-
-let declare_eliminations sp =
- let mib = Global.lookup_mind sp in
- if mib.mind_finite then begin
- if (!eq_flag) then (declare_eq_scheme sp);
- for i = 0 to Array.length mib.mind_packets - 1 do
- declare_one_elimination (sp,i);
- try
- if (!eq_flag) then (make_eq_decidability (sp,i))
- with _ ->
- Pfedit.delete_current_proof();
- message "Error while computing decidability scheme. Please report."
- done;
- end
+(* 3a| Elimination schemes for mutual inductive definitions *)
(* 3b| Mutual inductive definitions *)
-let compute_interning_datas env ty l nal typl impll =
- let mk_interning_data na typ impls =
- let idl, impl =
- let impl =
- compute_implicits_with_manual env typ (is_implicit_args ()) impls
- in
- let sub_impl,_ = list_chop (List.length l) impl in
- let sub_impl' = List.filter is_status_implicit sub_impl in
- (List.map name_of_implicit sub_impl', impl)
- in
- (na, (ty, idl, impl, compute_arguments_scope typ)) in
- (l, list_map3 mk_interning_data nal typl impll)
-
-
- (* temporary open scopes during interpretation of mutual families
- so that locally defined notations are available
- *)
-let open_temp_scopes = function
- | None -> ()
- | Some sc -> if not (Notation.scope_is_open sc)
- then Notation.open_close_scope (false,true,sc)
-
-let declare_interning_data (_,impls) (df,c,scope) =
- silently (Metasyntax.add_notation_interpretation df impls c) scope
-
let push_named_types env idl tl =
List.fold_left2 (fun env id t -> Environ.push_named (id,None,t) env)
env idl tl
@@ -481,12 +178,15 @@ let push_types env idl tl =
List.fold_left2 (fun env id t -> Environ.push_rel (Name id,None,t) env)
env idl tl
-type inductive_expr = {
+type structured_one_inductive_expr = {
ind_name : identifier;
ind_arity : constr_expr;
ind_lc : (identifier * constr_expr) list
}
+type structured_inductive_expr =
+ local_binder list * structured_one_inductive_expr list
+
let minductive_message = function
| [] -> error "No inductive definition."
| [x] -> (pr_id x ++ str " is defined")
@@ -522,7 +222,7 @@ let interp_cstrs evdref env impls mldata arity ind =
let ctyps'', cimpls = List.split (List.map (interp_type_evars_impls ~evdref env ~impls) ctyps') in
(cnames, ctyps'', cimpls)
-let interp_mutual paramsl indl notations finite =
+let interp_mutual_inductive (paramsl,indl) notations finite =
check_all_names_different indl;
let env0 = Global.env() in
let evdref = ref Evd.empty in
@@ -544,16 +244,13 @@ let interp_mutual paramsl indl notations finite =
(* Compute interpretation metadatas *)
let indimpls = List.map (fun (_, impls) -> userimpls @ lift_implicits (List.length userimpls) impls) arities in
let arities = List.map fst arities in
- let impls = compute_interning_datas env0 Inductive params indnames fullarities indimpls in
+ let impls = compute_full_internalization_env env0 Inductive params indnames fullarities indimpls in
let mldatas = List.map2 (mk_mltype_data evdref env_params params) arities indnames in
let constructors =
States.with_state_protection (fun () ->
(* Temporary declaration of notations and scopes *)
- List.iter (fun ((_,_,sc) as x ) ->
- declare_interning_data impls x;
- open_temp_scopes sc
- ) notations;
+ List.iter (Metasyntax.set_notation_for_interpretation impls) notations;
(* Interpret the constructor types *)
list_map3 (interp_cstrs evdref env_ar_params impls) mldatas arities indl)
() in
@@ -622,30 +319,25 @@ let extract_params indl =
"Parameters should be syntactically the same for each inductive type.";
params
-let prepare_inductive ntnl indl =
- let indl =
- List.map (fun ((_,indname),_,ar,lc) -> {
- ind_name = indname;
- ind_arity = Option.cata (fun x -> x) (CSort (dummy_loc, Rawterm.RType None)) ar;
- ind_lc = List.map (fun (_,((_,id),t)) -> (id,t)) lc
- }) indl in
- List.fold_right Option.List.cons ntnl [], indl
-
-
-let elim_flag = ref true
-let _ =
- declare_bool_option
- { optsync = true;
- optname = "automatic declaration of eliminations";
- optkey = ["Elimination";"Schemes"];
- optread = (fun () -> !elim_flag) ;
- optwrite = (fun b -> elim_flag := b) }
-
-let declare_mutual_with_eliminations isrecord mie impls =
+let extract_inductive indl =
+ List.map (fun ((_,indname),_,ar,lc) -> {
+ ind_name = indname;
+ ind_arity = Option.cata (fun x -> x) (CSort (dummy_loc, Rawterm.RType None)) ar;
+ ind_lc = List.map (fun (_,((_,id),t)) -> (id,t)) lc
+ }) indl
+
+let extract_mutual_inductive_declaration_components indl =
+ let indl,ntnl = List.split indl in
+ let params = extract_params indl in
+ let coes = extract_coercions indl in
+ let indl = extract_inductive indl in
+ (params,indl), coes, List.fold_right Option.List.cons ntnl []
+
+let declare_mutual_inductive_with_eliminations isrecord mie impls =
let names = List.map (fun e -> e.mind_entry_typename) mie.mind_entry_inds in
let (_,kn) = declare_mind isrecord mie in
- let mind =Global.mind_of_delta (mind_of_kn kn) in
- list_iter_i (fun i (indimpls, constrimpls) ->
+ let mind = Global.mind_of_delta (mind_of_kn kn) in
+ list_iter_i (fun i (indimpls, constrimpls) ->
let ind = (mind,i) in
Autoinstance.search_declaration (IndRef ind);
maybe_declare_manual_implicits false (IndRef ind) indimpls;
@@ -655,54 +347,32 @@ let declare_mutual_with_eliminations isrecord mie impls =
maybe_declare_manual_implicits false (ConstructRef (ind, succ j)) impls)
constrimpls)
impls;
- if_verbose ppnl (minductive_message names);
- if !elim_flag then declare_eliminations mind;
- mind
+ if_verbose ppnl (minductive_message names);
+ declare_default_schemes mind;
+ mind
-let build_mutual l finite =
- let indl,ntnl = List.split l in
- let paramsl = extract_params indl in
- let coes = extract_coercions indl in
- let notations,indl = prepare_inductive ntnl indl in
- let mie,impls = interp_mutual paramsl indl notations finite in
- (* Declare the mutual inductive block with its eliminations *)
- ignore (declare_mutual_with_eliminations false mie impls);
+open Vernacexpr
+
+type one_inductive_impls =
+ Impargs.manual_explicitation list (* for inds *)*
+ Impargs.manual_explicitation list list (* for constrs *)
+
+type one_inductive_expr =
+ lident * local_binder list * constr_expr option * constructor_expr list
+
+let do_mutual_inductive indl finite =
+ let indl,coes,ntns = extract_mutual_inductive_declaration_components indl in
+ (* Interpret the types *)
+ let mie,impls = interp_mutual_inductive indl ntns finite in
+ (* Declare the mutual inductive block with its associated schemes *)
+ ignore (declare_mutual_inductive_with_eliminations false mie impls);
(* Declare the possible notations of inductive types *)
- List.iter (declare_interning_data ([],[])) notations;
+ List.iter Metasyntax.add_notation_interpretation ntns;
(* Declare the coercions *)
List.iter (fun qid -> Class.try_add_new_coercion (locate qid) Global) coes
(* 3c| Fixpoints and co-fixpoints *)
-let pr_rank = function
- | 0 -> str "1st"
- | 1 -> str "2nd"
- | 2 -> str "3rd"
- | n -> str ((string_of_int (n+1))^"th")
-
-let recursive_message indexes = function
- | [] -> anomaly "no recursive definition"
- | [id] -> pr_id id ++ str " is recursively defined" ++
- (match indexes with
- | Some [|i|] -> str " (decreasing on "++pr_rank i++str " argument)"
- | _ -> mt ())
- | l -> hov 0 (prlist_with_sep pr_coma pr_id l ++
- spc () ++ str "are recursively defined" ++
- match indexes with
- | Some a -> spc () ++ str "(decreasing respectively on " ++
- prlist_with_sep pr_coma pr_rank (Array.to_list a) ++
- str " arguments)"
- | None -> mt ())
-
-let corecursive_message _ = function
- | [] -> error "No corecursive definition."
- | [id] -> pr_id id ++ str " is corecursively defined"
- | l -> hov 0 (prlist_with_sep pr_coma pr_id l ++
- spc () ++ str "are corecursively defined")
-
-let recursive_message isfix =
- if isfix=Fixpoint then recursive_message else corecursive_message
-
(* An (unoptimized) function that maps preorders to partial orders...
Input: a list of associations (x,[y1;...;yn]), all yi distincts
@@ -747,7 +417,7 @@ let rec partial_order = function
in link y
in browse (partial_order rest) [] xge
-let non_full_mutual_message x xge y yge kind rest =
+let non_full_mutual_message x xge y yge isfix rest =
let reason =
if List.mem x yge then
string_of_id y^" depends on "^string_of_id x^" but not conversely"
@@ -756,13 +426,12 @@ let non_full_mutual_message x xge y yge kind rest =
else
string_of_id y^" and "^string_of_id x^" are not mutually dependent" in
let e = if rest <> [] then "e.g.: "^reason else reason in
- let k = if kind=Fixpoint then "fixpoint" else "cofixpoint" in
+ let k = if isfix then "fixpoint" else "cofixpoint" in
let w =
- if kind=Fixpoint then "Well-foundedness check may fail unexpectedly.\n"
- else "" in
+ if isfix then "Well-foundedness check may fail unexpectedly.\n" else "" in
"Not a fully mutually defined "^k^"\n("^e^").\n"^w
-let check_mutuality env kind fixl =
+let check_mutuality env isfix fixl =
let names = List.map fst fixl in
let preorder =
List.map (fun (id,def) ->
@@ -771,14 +440,10 @@ let check_mutuality env kind fixl =
let po = partial_order preorder in
match List.filter (function (_,Inr _) -> true | _ -> false) po with
| (x,Inr xge)::(y,Inr yge)::rest ->
- if_verbose warning (non_full_mutual_message x xge y yge kind rest)
+ if_verbose warning (non_full_mutual_message x xge y yge isfix rest)
| _ -> ()
-type fixpoint_kind =
- | IsFixpoint of (identifier located option * recursion_order_expr) list
- | IsCoFixpoint
-
-type fixpoint_expr = {
+type structured_fixpoint_expr = {
fix_name : identifier;
fix_binders : local_binder list;
fix_body : constr_expr;
@@ -826,7 +491,7 @@ let rec unfold f b =
| Some (x, b') -> x :: unfold f b'
| None -> []
-let compute_possible_guardness_evidences (n,_) (_, fixctx) fixtype =
+let compute_possible_guardness_evidences n fixctx fixtype =
match n with
| Some (loc, n) -> [rel_index n fixctx]
| None ->
@@ -839,10 +504,11 @@ let compute_possible_guardness_evidences (n,_) (_, fixctx) fixtype =
unfold (function x when x = len -> None
| n -> Some (n, succ n)) 0
-let interp_recursive fixkind l boxed =
+type recursive_preentry =
+ identifier list * constr list * types list
+
+let interp_recursive isfix fixl notations =
let env = Global.env() in
- let fixl, ntnl = List.split l in
- let kind = if fixkind <> IsCoFixpoint then Fixpoint else CoFixpoint in
let fixnames = List.map (fun fix -> fix.fix_name) fixl in
(* Interp arities allowing for unresolved types *)
@@ -855,16 +521,12 @@ let interp_recursive fixkind l boxed =
let env_rec = push_named_types env fixnames fixtypes in
(* Get interpretation metadatas *)
- let impls = compute_interning_datas env Recursive [] fixnames fixtypes fiximps in
- let notations = List.fold_right Option.List.cons ntnl [] in
+ let impls = compute_full_internalization_env env Recursive [] fixnames fixtypes fiximps in
(* Interp bodies with rollback because temp use of notations/implicit *)
let fixdefs =
States.with_state_protection (fun () ->
- List.iter (fun ((_,_,sc) as x) ->
- declare_interning_data impls x;
- open_temp_scopes sc
- ) notations;
+ List.iter (Metasyntax.set_notation_for_interpretation impls) notations;
list_map3 (interp_fix_body evdref env_rec impls) fixctxs fixl fixccls)
() in
@@ -875,410 +537,62 @@ let interp_recursive fixkind l boxed =
let evd = Typeclasses.resolve_typeclasses ~onlyargs:false ~fail:true env evd in
List.iter (check_evars env_rec Evd.empty evd) fixdefs;
List.iter (check_evars env Evd.empty evd) fixtypes;
- check_mutuality env kind (List.combine fixnames fixdefs);
+ check_mutuality env isfix (List.combine fixnames fixdefs);
(* Build the fix declaration block *)
let fixdecls = prepare_recursive_declaration fixnames fixtypes fixdefs in
+ (snd (List.split fixctxs),fixnames,fixdecls,fixtypes),fiximps
+
+let interp_fixpoint fixl wfl notations =
+ let (fixctxs,fixnames,fixdecls,fixtypes),fiximps =
+ interp_recursive true fixl notations in
let indexes, fixdecls =
- match fixkind with
- | IsFixpoint wfl ->
- let possible_indexes =
- list_map3 compute_possible_guardness_evidences wfl fixctxs fixtypes in
- let indexes = search_guard dummy_loc env possible_indexes fixdecls in
- Some indexes, list_map_i (fun i _ -> mkFix ((indexes,i),fixdecls)) 0 l
- | IsCoFixpoint ->
- None, list_map_i (fun i _ -> mkCoFix (i,fixdecls)) 0 l
+ let possible_indexes =
+ list_map3 compute_possible_guardness_evidences wfl fixctxs fixtypes in
+ let indexes =
+ search_guard dummy_loc (Global.env()) possible_indexes fixdecls in
+ Some indexes,
+ list_map_i (fun i _ -> mkFix ((indexes,i),fixdecls)) 0 fixnames
in
+ ((fixnames,fixdecls,fixtypes),fiximps,indexes)
+
+let interp_cofixpoint fixl notations =
+ let (fixctxs,fixnames,fixdecls,fixtypes),fiximps =
+ interp_recursive false fixl notations in
+ let fixdecls = list_map_i (fun i _ -> mkCoFix (i,fixdecls)) 0 fixnames in
+ ((fixnames,fixdecls,fixtypes),fiximps)
+let declare_fixpoint boxed ((fixnames,fixdecls,fixtypes),fiximps,indexes) ntns =
+ ignore (list_map4 (declare_fix boxed Fixpoint) fixnames fixdecls fixtypes fiximps);
(* Declare the recursive definitions *)
- ignore (list_map4 (declare_fix boxed kind) fixnames fixdecls fixtypes fiximps);
- if_verbose ppnl (recursive_message kind indexes fixnames);
+ fixpoint_message indexes fixnames;
+ (* Declare notations *)
+ List.iter Metasyntax.add_notation_interpretation ntns
+let declare_cofixpoint boxed ((fixnames,fixdecls,fixtypes),fiximps) ntns =
+ ignore (list_map4 (declare_fix boxed CoFixpoint) fixnames fixdecls fixtypes fiximps);
+ (* Declare the recursive definitions *)
+ cofixpoint_message fixnames;
(* Declare notations *)
- List.iter (declare_interning_data ([],[])) notations
-
-let build_recursive l b =
- let g = List.map (fun ((_,wf,_,_,_),_) -> wf) l in
- let fixl = List.map (fun (((_,id),_,bl,typ,def),ntn) ->
- ({fix_name = id; fix_binders = bl; fix_body = def; fix_type = typ},ntn))
- l in
- interp_recursive (IsFixpoint g) fixl b
-
-let build_corecursive l b =
- let fixl = List.map (fun (((_,id),bl,typ,def),ntn) ->
- ({fix_name = id; fix_binders = bl; fix_body = def; fix_type = typ},ntn))
- l in
- interp_recursive IsCoFixpoint fixl b
-
-(* 3d| Schemes *)
-let rec split_scheme l =
- let env = Global.env() in
- match l with
- | [] -> [],[]
- | (Some id,t)::q -> let l1,l2 = split_scheme q in
- ( match t with
- | InductionScheme (x,y,z) -> ((id,x,y,z)::l1),l2
- | EqualityScheme x -> l1,(x::l2)
- )
-(*
- if no name has been provided, we build one from the types of the ind
-requested
-*)
- | (None,t)::q ->
- let l1,l2 = split_scheme q in
- ( match t with
- | InductionScheme (x,y,z) ->
- let ind = smart_global_inductive y in
- let sort_of_ind = Retyping.get_sort_family_of env Evd.empty (mkInd ind)
-in
- let z' = family_of_sort (interp_sort z) in
- let suffix = (
- match sort_of_ind with
- | InProp ->
- if x then (match z' with
- | InProp -> "_ind_nodep"
- | InSet -> "_rec_nodep"
- | InType -> "_rect_nodep")
- else ( match z' with
- | InProp -> "_ind"
- | InSet -> "_rec"
- | InType -> "_rect" )
- | _ ->
- if x then (match z' with
- | InProp -> "_ind"
- | InSet -> "_rec"
- | InType -> "_rect" )
- else (match z' with
- | InProp -> "_ind_nodep"
- | InSet -> "_rec_nodep"
- | InType -> "_rect_nodep")
- ) in
- let newid = add_suffix (basename_of_global (IndRef ind)) suffix in
- let newref = (dummy_loc,newid) in
- ((newref,x,y,z)::l1),l2
- | EqualityScheme x -> l1,(x::l2)
- )
-
-
-let build_induction_scheme lnamedepindsort =
- let lrecnames = List.map (fun ((_,f),_,_,_) -> f) lnamedepindsort
- and sigma = Evd.empty
- and env0 = Global.env() in
- let lrecspec =
- List.map
- (fun (_,dep,indid,sort) ->
- let ind = smart_global_inductive indid in
- let (mib,mip) = Global.lookup_inductive ind in
- (ind,mib,mip,dep,interp_elimination_sort sort))
- lnamedepindsort
- in
- let listdecl = Indrec.build_mutual_indrec env0 sigma lrecspec in
- let rec declare decl fi lrecref =
- let decltype = Retyping.get_type_of env0 Evd.empty decl in
- let decltype = refresh_universes decltype in
- let ce = { const_entry_body = decl;
- const_entry_type = Some decltype;
- const_entry_opaque = false;
- const_entry_boxed = Flags.boxed_definitions() } in
- let kn = declare_constant fi (DefinitionEntry ce, IsDefinition Scheme) in
- ConstRef kn :: lrecref
- in
- let _ = List.fold_right2 declare listdecl lrecnames [] in
- if_verbose ppnl (recursive_message Fixpoint None lrecnames)
-
-let build_scheme l =
- let ischeme,escheme = split_scheme l in
-(* we want 1 kind of scheme at a time so we check if the user
-tried to declare different schemes at once *)
- if (ischeme <> []) && (escheme <> [])
- then
- error "Do not declare equality and induction scheme at the same time."
- else (
- if ischeme <> [] then build_induction_scheme ischeme;
- List.iter ( fun indname ->
- let ind = smart_global_inductive indname
- in declare_eq_scheme (fst ind);
- try
- make_eq_decidability ind
- with _ ->
- Pfedit.delete_current_proof();
- message "Error while computing decidability scheme. Please report."
- ) escheme
- )
-
-let list_split_rev_at index l =
- let rec aux i acc = function
- hd :: tl when i = index -> acc, tl
- | hd :: tl -> aux (succ i) (hd :: acc) tl
- | [] -> failwith "list_split_when: Invalid argument"
- in aux 0 [] l
-
-let fold_left' f = function
- [] -> raise (Invalid_argument "fold_right'")
- | hd :: tl -> List.fold_left f hd tl
-
-let build_combined_scheme name schemes =
- let env = Global.env () in
-(* let nschemes = List.length schemes in *)
- let find_inductive ty =
- let (ctx, arity) = decompose_prod ty in
- let (_, last) = List.hd ctx in
- match kind_of_term last with
- | App (ind, args) ->
- let ind = destInd ind in
- let (_,spec) = Inductive.lookup_mind_specif env ind in
- ctx, ind, spec.mind_nrealargs
- | _ -> ctx, destInd last, 0
- in
- let defs =
- List.map (fun x ->
- let refe = Ident x in
- let qualid = qualid_of_reference refe in
- let cst = try Nametab.locate_constant (snd qualid)
- with Not_found -> error ((string_of_qualid (snd qualid))^" is not declared.")
- in
- let ty = Typeops.type_of_constant env cst in
- qualid, cst, ty)
- schemes
- in
- let (qid, c, t) = List.hd defs in
- let ctx, ind, nargs = find_inductive t in
- (* Number of clauses, including the predicates quantification *)
- let prods = nb_prod t - (nargs + 1) in
- let coqand = Coqlib.build_coq_and () and coqconj = Coqlib.build_coq_conj () in
- let relargs = rel_vect 0 prods in
- let concls = List.rev_map
- (fun (_, cst, t) ->
- mkApp(mkConst cst, relargs),
- snd (decompose_prod_n prods t)) defs in
- let concl_bod, concl_typ =
- fold_left'
- (fun (accb, acct) (cst, x) ->
- mkApp (coqconj, [| x; acct; cst; accb |]),
- mkApp (coqand, [| x; acct |])) concls
- in
- let ctx, _ =
- list_split_rev_at prods
- (List.rev_map (fun (x, y) -> x, None, y) ctx) in
- let typ = it_mkProd_wo_LetIn concl_typ ctx in
- let body = it_mkLambda_or_LetIn concl_bod ctx in
- let ce = { const_entry_body = body;
- const_entry_type = Some typ;
- const_entry_opaque = false;
- const_entry_boxed = Flags.boxed_definitions() } in
- let _ = declare_constant (snd name) (DefinitionEntry ce, IsDefinition Scheme) in
- if_verbose ppnl (recursive_message Fixpoint None [snd name])
-(* 4| Goal declaration *)
-
-(* 4.1| Support for mutually proved theorems *)
-
-let retrieve_first_recthm = function
- | VarRef id ->
- (pi2 (Global.lookup_named id),variable_opacity id)
- | ConstRef cst ->
- let {const_body=body;const_opaque=opaq} = Global.lookup_constant cst in
- (Option.map Declarations.force body,opaq)
- | _ -> assert false
-
-let default_thm_id = id_of_string "Unnamed_thm"
-
-let compute_proof_name = function
- | Some (loc,id) ->
- (* We check existence here: it's a bit late at Qed time *)
- if Nametab.exists_cci (Lib.make_path id) or is_section_variable id then
- user_err_loc (loc,"",pr_id id ++ str " already exists.");
- id
- | None ->
- let rec next avoid id =
- let id = next_global_ident_away false id avoid in
- if Nametab.exists_cci (Lib.make_path id) then next (id::avoid) id
- else id
- in
- next (Pfedit.get_all_proof_names ()) default_thm_id
-
-let save_remaining_recthms (local,kind) body opaq i (id,(t_i,(_,imps))) =
- match body with
- | None ->
- (match local with
- | Local ->
- let impl=false in (* copy values from Vernacentries *)
- let k = IsAssumption Conjectural in
- let c = SectionLocalAssum (t_i,impl) in
- let _ = declare_variable id (Lib.cwd(),c,k) in
- (Local,VarRef id,imps)
- | Global ->
- let k = IsAssumption Conjectural in
- let kn = declare_constant id (ParameterEntry (t_i,false), k) in
- (Global,ConstRef kn,imps))
- | Some body ->
- let k = logical_kind_of_goal_kind kind in
- let body_i = match kind_of_term body with
- | Fix ((nv,0),decls) -> mkFix ((nv,i),decls)
- | CoFix (0,decls) -> mkCoFix (i,decls)
- | _ -> anomaly "Not a proof by induction" in
- match local with
- | Local ->
- let c = SectionLocalDef (body_i, Some t_i, opaq) in
- let _ = declare_variable id (Lib.cwd(), c, k) in
- (Local,VarRef id,imps)
- | Global ->
- let const =
- { const_entry_body = body_i;
- const_entry_type = Some t_i;
- const_entry_opaque = opaq;
- const_entry_boxed = false (* copy of what cook_proof does *)} in
- let kn = declare_constant id (DefinitionEntry const, k) in
- (Global,ConstRef kn,imps)
-
-let look_for_mutual_statements thms =
- if List.tl thms <> [] then
- (* More than one statement: we look for a common inductive hyp or a *)
- (* common coinductive conclusion *)
- let n = List.length thms in
- let inds = List.map (fun (id,(t,_) as x) ->
- let (hyps,ccl) = decompose_prod_assum t in
- let whnf_hyp_hds = map_rel_context_in_env
- (fun env c -> fst (whd_betadeltaiota_stack env Evd.empty c))
- (Global.env()) hyps in
- let ind_hyps =
- List.flatten (list_map_i (fun i (_,b,t) ->
- match kind_of_term t with
- | Ind (kn,_ as ind) when
- let mind = Global.lookup_mind kn in
- mind.mind_finite & b = None ->
- [ind,x,i]
- | _ ->
- []) 1 (List.rev whnf_hyp_hds)) in
- let ind_ccl =
- let cclenv = push_rel_context hyps (Global.env()) in
- let whnf_ccl,_ = whd_betadeltaiota_stack cclenv Evd.empty ccl in
- match kind_of_term whnf_ccl with
- | Ind (kn,_ as ind) when
- let mind = Global.lookup_mind kn in
- mind.mind_ntypes = n & not mind.mind_finite ->
- [ind,x,0]
- | _ ->
- [] in
- ind_hyps,ind_ccl) thms in
- let inds_hyps,ind_ccls = List.split inds in
- let of_same_mutind ((kn,_),_,_) = function ((kn',_),_,_) -> kn = kn' in
- (* Check if all conclusions are coinductive in the same type *)
- (* (degenerated cartesian product since there is at most one coind ccl) *)
- let same_indccl =
- list_cartesians_filter (fun hyp oks ->
- if List.for_all (of_same_mutind hyp) oks
- then Some (hyp::oks) else None) [] ind_ccls in
- let ordered_same_indccl =
- List.filter (list_for_all_i (fun i ((kn,j),_,_) -> i=j) 0) same_indccl in
- (* Check if some hypotheses are inductive in the same type *)
- let common_same_indhyp =
- list_cartesians_filter (fun hyp oks ->
- if List.for_all (of_same_mutind hyp) oks
- then Some (hyp::oks) else None) [] inds_hyps in
- let ordered_inds,finite =
- match ordered_same_indccl, common_same_indhyp with
- | indccl::rest, _ ->
- assert (rest=[]);
- (* One occ. of common coind ccls and no common inductive hyps *)
- if common_same_indhyp <> [] then
- if_verbose warning "Assuming mutual coinductive statements.";
- flush_all ();
- indccl, true
- | [], _::_ ->
- if same_indccl <> [] &&
- list_distinct (List.map pi1 (List.hd same_indccl)) then
- if_verbose warn (strbrk "Coinductive statements do not follow the order of definition, assume the proof to be by induction."); flush_all ();
- (* assume the largest indices as possible *)
- list_last common_same_indhyp, false
- | _, [] ->
- error
- ("Cannot find common (mutual) inductive premises or coinductive" ^
- " conclusions in the statements.")
- in
- let nl,thms = List.split (List.map (fun (_,x,i) -> (i,x)) ordered_inds) in
- let rec_tac =
- if finite then
- match List.map (fun (id,(t,_)) -> (id,t)) thms with
- | (id,_)::l -> Hiddentac.h_mutual_cofix true id l
- | _ -> assert false
- else
- (* nl is dummy: it will be recomputed at Qed-time *)
- match List.map2 (fun (id,(t,_)) n -> (id,n,t)) thms nl with
- | (id,n,_)::l -> Hiddentac.h_mutual_fix true id n l
- | _ -> assert false in
- Some rec_tac,thms
- else
- None, thms
-
-(* 4.2| General support for goals *)
-
-let start_proof_com kind thms hook =
- let evdref = ref (create_evar_defs Evd.empty) in
- let env = Global.env () in
- let thms = List.map (fun (sopt,(bl,t)) ->
- let (env, ctx), imps = interp_context_evars evdref env bl in
- let t', imps' = interp_type_evars_impls ~evdref env t in
- let len = List.length ctx in
- (compute_proof_name sopt,
- (nf_isevar !evdref (it_mkProd_or_LetIn t' ctx), (len, imps @ lift_implicits len imps'))))
- thms in
- let rec_tac,thms = look_for_mutual_statements thms in
- match thms with
- | [] -> anomaly "No proof to start"
- | (id,(t,(len,imps)) as thm)::other_thms ->
- let hook strength ref =
- let other_thms_data =
- if other_thms = [] then [] else
- (* there are several theorems defined mutually *)
- let body,opaq = retrieve_first_recthm ref in
- list_map_i (save_remaining_recthms kind body opaq) 1 other_thms in
- let thms_data = (strength,ref,imps)::other_thms_data in
- List.iter (fun (strength,ref,imps) ->
- maybe_declare_manual_implicits false ref imps;
- hook strength ref) thms_data in
- let init_tac =
- let intro_tac (_, (_, (len, _))) = Refiner.tclDO len Tactics.intro in
- if Flags.is_auto_intros () then
- match rec_tac with
- | None -> Some (intro_tac thm)
- | Some tac -> Some (Tacticals.tclTHENS tac (List.map intro_tac thms))
- else rec_tac
- in start_proof id kind t ?init_tac hook ~compute_guard:(rec_tac<>None)
-
-let check_anonymity id save_ident =
- if atompart_of_id id <> "Unnamed_thm" then
- error "This command can only be used for unnamed theorem."
-(*
- message("Overriding name "^(string_of_id id)^" and using "^save_ident)
-*)
+ List.iter Metasyntax.add_notation_interpretation ntns
-let save_anonymous opacity save_ident =
- let id,(const,do_guard,persistence,hook) = Pfedit.cook_proof !save_hook in
- let const = { const with const_entry_opaque = opacity } in
- check_anonymity id save_ident;
- save save_ident const do_guard persistence hook
-
-let save_anonymous_with_strength kind opacity save_ident =
- let id,(const,do_guard,_,hook) = Pfedit.cook_proof !save_hook in
- let const = { const with const_entry_opaque = opacity } in
- check_anonymity id save_ident;
- (* we consider that non opaque behaves as local for discharge *)
- save save_ident const do_guard (Global, Proof kind) hook
-
-let admit () =
- let (id,k,typ,hook) = Pfedit.current_proof_statement () in
-(* Contraire aux besoins d'interactivité...
- if k <> IsGlobal (Proof Conjecture) then
- error "Only statements declared as conjecture can be admitted";
-*)
- let kn =
- declare_constant id (ParameterEntry (typ,false), IsAssumption Conjectural) in
- Pfedit.delete_current_proof ();
- assumption_message id;
- hook Global (ConstRef kn)
+let extract_fixpoint_components l =
+ let fixl, ntnl = List.split l in
+ let wfl = List.map (fun (_,wf,_,_,_) -> fst wf) fixl in
+ let fixl = List.map (fun ((_,id),_,bl,typ,def) ->
+ {fix_name = id; fix_binders = bl; fix_body = def; fix_type = typ}) fixl in
+ fixl, List.fold_right Option.List.cons ntnl [], wfl
+
+let extract_cofixpoint_components l =
+ let fixl, ntnl = List.split l in
+ List.map (fun ((_,id),bl,typ,def) ->
+ {fix_name = id; fix_binders = bl; fix_body = def; fix_type = typ}) fixl,
+ List.fold_right Option.List.cons ntnl []
-let get_current_context () =
- try Pfedit.get_current_goal_context ()
- with e when Logic.catchable_exception e ->
- (Evd.empty, Global.env())
+let do_fixpoint l b =
+ let fixl,ntns,wfl = extract_fixpoint_components l in
+ declare_fixpoint b (interp_fixpoint fixl wfl ntns) ntns
+let do_cofixpoint l b =
+ let fixl,ntns = extract_cofixpoint_components l in
+ declare_cofixpoint b (interp_cofixpoint fixl ntns) ntns