summaryrefslogtreecommitdiff
path: root/toplevel/classes.ml
diff options
context:
space:
mode:
Diffstat (limited to 'toplevel/classes.ml')
-rw-r--r--toplevel/classes.ml418
1 files changed, 235 insertions, 183 deletions
diff --git a/toplevel/classes.ml b/toplevel/classes.ml
index 3843ea83..f44ac367 100644
--- a/toplevel/classes.ml
+++ b/toplevel/classes.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 *)
@@ -8,80 +8,77 @@
(*i*)
open Names
-open Decl_kinds
open Term
-open Sign
-open Entries
-open Evd
+open Vars
open Environ
open Nametab
-open Mod_subst
+open Errors
open Util
open Typeclasses_errors
open Typeclasses
open Libnames
+open Globnames
open Constrintern
-open Glob_term
-open Topconstr
+open Constrexpr
(*i*)
open Decl_kinds
open Entries
+let refine_instance = ref true
+
+let _ = Goptions.declare_bool_option {
+ Goptions.optsync = true;
+ Goptions.optdepr = false;
+ Goptions.optname = "definition of instances by refining";
+ Goptions.optkey = ["Refine";"Instance";"Mode"];
+ Goptions.optread = (fun () -> !refine_instance);
+ Goptions.optwrite = (fun b -> refine_instance := b)
+}
+
let typeclasses_db = "typeclass_instances"
let set_typeclass_transparency c local b =
- Auto.add_hints local [typeclasses_db]
- (Auto.HintsTransparencyEntry ([c], b))
+ Hints.add_hints local [typeclasses_db]
+ (Hints.HintsTransparencyEntry ([c], b))
let _ =
- Typeclasses.register_add_instance_hint
- (fun inst local pri ->
- let path =
- try Auto.PathHints [global_of_constr inst]
- with e when Errors.noncritical e -> Auto.PathAny
+ Hook.set Typeclasses.add_instance_hint_hook
+ (fun inst path local pri poly ->
+ let inst' = match inst with IsConstr c -> Hints.IsConstr (c, Univ.ContextSet.empty)
+ | IsGlobal gr -> Hints.IsGlobRef gr
in
Flags.silently (fun () ->
- Auto.add_hints local [typeclasses_db]
- (Auto.HintsResolveEntry
- [pri, false, path, inst])) ());
- Typeclasses.register_set_typeclass_transparency set_typeclass_transparency;
- Typeclasses.register_classes_transparent_state
- (fun () -> Auto.Hint_db.transparent_state (Auto.searchtable_map typeclasses_db))
-
-let declare_class g =
- match global g with
- | ConstRef x -> Typeclasses.add_constant_class x
- | IndRef x -> Typeclasses.add_inductive_class x
- | _ -> user_err_loc (loc_of_reference g, "declare_class",
- Pp.str"Unsupported class type, only constants and inductives are allowed")
-
+ Hints.add_hints local [typeclasses_db]
+ (Hints.HintsResolveEntry
+ [pri, poly, false, Hints.PathHints path, inst'])) ());
+ Hook.set Typeclasses.set_typeclass_transparency_hook set_typeclass_transparency;
+ Hook.set Typeclasses.classes_transparent_state_hook
+ (fun () -> Hints.Hint_db.transparent_state (Hints.searchtable_map typeclasses_db))
+
(** TODO: add subinstances *)
-let existing_instance glob g =
+let existing_instance glob g pri =
let c = global g in
- let instance = Typing.type_of (Global.env ()) Evd.empty (constr_of_global c) in
+ let instance = Global.type_of_global_unsafe c in
let _, r = decompose_prod_assum instance in
match class_of_constr r with
- | Some (_, (tc, _)) -> add_instance (new_instance tc None glob c)
+ | Some (_, ((tc,u), _)) -> add_instance (new_instance tc pri glob
+ (*FIXME*) (Flags.use_polymorphic_flag ()) c)
| None -> user_err_loc (loc_of_reference g, "declare_instance",
Pp.str "Constant does not build instances of a declared type class.")
let mismatched_params env n m = mismatched_ctx_inst env Parameters n m
let mismatched_props env n m = mismatched_ctx_inst env Properties n m
-type binder_list = (identifier located * bool * constr_expr) list
-
(* Declare everything in the parameters as implicit, and the class instance as well *)
-open Topconstr
-
let type_ctx_instance evars env ctx inst subst =
let rec aux (subst, instctx) l = function
(na, b, t) :: ctx ->
let t' = substl subst t in
let c', l =
match b with
- | None -> interp_casted_constr_evars evars env (List.hd l) t', List.tl l
+ | None -> interp_casted_constr_evars env evars (List.hd l) t', List.tl l
| Some b -> substl subst b, l
in
let d = na, Some c', t' in
@@ -89,11 +86,9 @@ let type_ctx_instance evars env ctx inst subst =
| [] -> subst
in aux (subst, []) inst (List.rev ctx)
-let refine_ref = ref (fun _ -> assert(false))
-
let id_of_class cl =
match cl.cl_impl with
- | ConstRef kn -> let _,_,l = repr_con kn in id_of_label l
+ | ConstRef kn -> let _,_,l = repr_con kn in Label.to_id l
| IndRef (kn,i) ->
let mip = (Environ.lookup_mind kn (Global.env ())).Declarations.mind_packets in
mip.(0).Declarations.mind_typename
@@ -101,55 +96,53 @@ let id_of_class cl =
open Pp
-let ($$) g f = fun x -> g (f x)
-
let instance_hook k pri global imps ?hook cst =
Impargs.maybe_declare_manual_implicits false cst ~enriching:false imps;
Typeclasses.declare_instance pri (not global) cst;
(match hook with Some h -> h cst | None -> ())
-let declare_instance_constant k pri global imps ?hook id term termtype =
- let cdecl =
- let kind = IsDefinition Instance in
- let entry =
- { const_entry_body = term;
- const_entry_secctx = None;
- const_entry_type = Some termtype;
- const_entry_opaque = false }
- in DefinitionEntry entry, kind
+let declare_instance_constant k pri global imps ?hook id poly uctx term termtype =
+ let kind = IsDefinition Instance in
+ let entry =
+ Declare.definition_entry ~types:termtype ~poly ~univs:uctx term
in
+ let cdecl = (DefinitionEntry entry, kind) in
let kn = Declare.declare_constant id cdecl in
Declare.definition_message id;
instance_hook k pri global imps ?hook (ConstRef kn);
id
-let new_instance ?(abstract=false) ?(global=false) ctx (instid, bk, cl) props
+let new_instance ?(abstract=false) ?(global=false) poly ctx (instid, bk, cl) props
?(generalize=true)
- ?(tac:Proof_type.tactic option) ?(hook:(global_reference -> unit) option) pri =
+ ?(tac:unit Proofview.tactic option) ?hook pri =
let env = Global.env() in
- let evars = ref Evd.empty in
+ let evars = ref (Evd.from_env env) in
let tclass, ids =
match bk with
| Implicit ->
- Implicit_quantifiers.implicit_application Idset.empty ~allow_partial:false
+ Implicit_quantifiers.implicit_application Id.Set.empty ~allow_partial:false
(fun avoid (clname, (id, _, t)) ->
match clname with
| Some (cl, b) ->
- let t = CHole (Util.dummy_loc, None) in
+ let t = CHole (Loc.ghost, None, Misctypes.IntroAnonymous, None) in
t, avoid
| None -> failwith ("new instance: under-applied typeclass"))
cl
- | Explicit -> cl, Idset.empty
+ | Explicit -> cl, Id.Set.empty
+ in
+ let tclass =
+ if generalize then CGeneralization (Loc.ghost, Implicit, Some AbsPi, tclass)
+ else tclass
in
- let tclass = if generalize then CGeneralization (dummy_loc, Implicit, Some AbsPi, tclass) else tclass in
- let k, cty, ctx', ctx, len, imps, subst =
- let impls, ((env', ctx), imps) = interp_context_evars evars env ctx in
- let c', imps' = interp_type_evars_impls ~impls ~evdref:evars ~fail_evar:false env' tclass in
+ let k, u, cty, ctx', ctx, len, imps, subst =
+ let impls, ((env', ctx), imps) = interp_context_evars env evars ctx in
+ let c', imps' = interp_type_evars_impls ~impls env' evars tclass in
let len = List.length ctx in
let imps = imps @ Impargs.lift_implicits len imps' in
let ctx', c = decompose_prod_assum c' in
let ctx'' = ctx' @ ctx in
- let cl, args = Typeclasses.dest_class_app (push_rel_context ctx'' env) c in
+ let k, args = Typeclasses.dest_class_app (push_rel_context ctx'' env) c in
+ let cl, u = Typeclasses.typeclass_univ_instance k in
let _, args =
List.fold_right (fun (na, b, t) (args, args') ->
match b with
@@ -157,7 +150,7 @@ let new_instance ?(abstract=false) ?(global=false) ctx (instid, bk, cl) props
| Some b -> (args, substl args' b :: args'))
(snd cl.cl_context) (args, [])
in
- cl, c', ctx', ctx, len, imps, args
+ cl, u, c', ctx', ctx, len, imps, args
in
let id =
match snd instid with
@@ -172,158 +165,217 @@ let new_instance ?(abstract=false) ?(global=false) ctx (instid, bk, cl) props
in
let env' = push_rel_context ctx env in
evars := Evarutil.nf_evar_map !evars;
- evars := resolve_typeclasses env !evars;
- let sigma = !evars in
- let subst = List.map (Evarutil.nf_evar sigma) subst in
+ evars := resolve_typeclasses ~filter:Typeclasses.no_goals ~fail:true env !evars;
+ let subst = List.map (Evarutil.nf_evar !evars) subst in
if abstract then
begin
- if not (Lib.is_modtype ()) then
- error "Declare Instance while not in Module Type.";
- let _, ty_constr = instance_constructor k (List.rev subst) in
+ let subst = List.fold_left2
+ (fun subst' s (_, b, _) -> if Option.is_empty b then s :: subst' else subst')
+ [] subst (snd k.cl_context)
+ in
+ let (_, ty_constr) = instance_constructor (k,u) subst in
+ let nf, subst = Evarutil.e_nf_evars_and_universes evars in
let termtype =
let t = it_mkProd_or_LetIn ty_constr (ctx' @ ctx) in
- Evarutil.nf_evar !evars t
+ nf t
in
Evarutil.check_evars env Evd.empty !evars termtype;
+ let ctx = Evd.universe_context !evars in
let cst = Declare.declare_constant ~internal:Declare.KernelSilent id
(Entries.ParameterEntry
- (None,termtype,None), Decl_kinds.IsAssumption Decl_kinds.Logical)
+ (None,poly,(termtype,ctx),None), Decl_kinds.IsAssumption Decl_kinds.Logical)
in instance_hook k None global imps ?hook (ConstRef cst); id
end
- else
- begin
- let props =
- match props with
- | Some (CRecord (loc, _, fs)) ->
- if List.length fs > List.length k.cl_props then
- mismatched_props env' (List.map snd fs) k.cl_props;
- Some (Inl fs)
- | Some t -> Some (Inr t)
- | None -> None
- in
- let subst =
- match props with
- | None -> if k.cl_props = [] then Some (Inl subst) else None
- | Some (Inr term) ->
- let c = interp_casted_constr_evars evars env' term cty in
- Some (Inr (c, subst))
- | Some (Inl props) ->
- let get_id =
- function
- | Ident id' -> id'
- | _ -> errorlabstrm "new_instance" (Pp.str "Only local structures are handled")
- in
- let props, rest =
- List.fold_left
- (fun (props, rest) (id,b,_) ->
- if b = None then
- try
- let (loc_mid, c) = List.find (fun (id', _) -> Name (snd (get_id id')) = id) rest in
- let rest' = List.filter (fun (id', _) -> Name (snd (get_id id')) <> id) rest in
- let (loc, mid) = get_id loc_mid in
- List.iter (fun (n, _, x) ->
- if n = Name mid then
- Option.iter (fun x -> Dumpglob.add_glob loc (ConstRef x)) x)
- k.cl_projs;
- c :: props, rest'
- with Not_found ->
- (CHole (Util.dummy_loc, None) :: props), rest
- else props, rest)
- ([], props) k.cl_props
- in
- if rest <> [] then
- unbound_method env' k.cl_impl (get_id (fst (List.hd rest)))
- else
- Some (Inl (type_ctx_instance evars (push_rel_context ctx' env') k.cl_props props subst))
- in
+ else (
+ let props =
+ match props with
+ | Some (true, CRecord (loc, _, fs)) ->
+ if List.length fs > List.length k.cl_props then
+ mismatched_props env' (List.map snd fs) k.cl_props;
+ Some (Inl fs)
+ | Some (_, t) -> Some (Inr t)
+ | None ->
+ if Flags.is_program_mode () then Some (Inl [])
+ else None
+ in
+ let subst =
+ match props with
+ | None -> if List.is_empty k.cl_props then Some (Inl subst) else None
+ | Some (Inr term) ->
+ let c = interp_casted_constr_evars env' evars term cty in
+ Some (Inr (c, subst))
+ | Some (Inl props) ->
+ let get_id =
+ function
+ | Ident id' -> id'
+ | _ -> errorlabstrm "new_instance" (Pp.str "Only local structures are handled")
+ in
+ let props, rest =
+ List.fold_left
+ (fun (props, rest) (id,b,_) ->
+ if Option.is_empty b then
+ try
+ let is_id (id', _) = match id, get_id id' with
+ | Name id, (_, id') -> Id.equal id id'
+ | Anonymous, _ -> false
+ in
+ let (loc_mid, c) =
+ List.find is_id rest
+ in
+ let rest' =
+ List.filter (fun v -> not (is_id v)) rest
+ in
+ let (loc, mid) = get_id loc_mid in
+ List.iter (fun (n, _, x) ->
+ if Name.equal n (Name mid) then
+ Option.iter (fun x -> Dumpglob.add_glob loc (ConstRef x)) x)
+ k.cl_projs;
+ c :: props, rest'
+ with Not_found ->
+ (CHole (Loc.ghost, Some Evar_kinds.GoalEvar, Misctypes.IntroAnonymous, None) :: props), rest
+ else props, rest)
+ ([], props) k.cl_props
+ in
+ match rest with
+ | (n, _) :: _ ->
+ unbound_method env' k.cl_impl (get_id n)
+ | _ ->
+ Some (Inl (type_ctx_instance evars (push_rel_context ctx' env')
+ k.cl_props props subst))
+ in
+ let term, termtype =
+ match subst with
+ | None -> let termtype = it_mkProd_or_LetIn cty ctx in
+ None, termtype
+ | Some (Inl subst) ->
+ let subst = List.fold_left2
+ (fun subst' s (_, b, _) -> if Option.is_empty b then s :: subst' else subst')
+ [] subst (k.cl_props @ snd k.cl_context)
+ in
+ let (app, ty_constr) = instance_constructor (k,u) subst in
+ let termtype = it_mkProd_or_LetIn ty_constr (ctx' @ ctx) in
+ let term = Termops.it_mkLambda_or_LetIn (Option.get app) (ctx' @ ctx) in
+ Some term, termtype
+ | Some (Inr (def, subst)) ->
+ let termtype = it_mkProd_or_LetIn cty ctx in
+ let term = Termops.it_mkLambda_or_LetIn def ctx in
+ Some term, termtype
+ in
+ let _ =
evars := Evarutil.nf_evar_map !evars;
- let term, termtype =
- match subst with
- | None -> let termtype = it_mkProd_or_LetIn cty ctx in
- None, termtype
- | Some (Inl subst) ->
- let subst = List.fold_left2
- (fun subst' s (_, b, _) -> if b = None then s :: subst' else subst')
- [] subst (k.cl_props @ snd k.cl_context)
+ evars := Typeclasses.resolve_typeclasses ~filter:Typeclasses.no_goals_or_obligations ~fail:true
+ env !evars;
+ (* Try resolving fields that are typeclasses automatically. *)
+ evars := Typeclasses.resolve_typeclasses ~filter:Typeclasses.all_evars ~fail:false
+ env !evars
+ in
+ let _ = evars := Evarutil.nf_evar_map_undefined !evars in
+ let evm, nf = Evarutil.nf_evar_map_universes !evars in
+ let termtype = nf termtype in
+ let _ = (* Check that the type is free of evars now. *)
+ Evarutil.check_evars env Evd.empty evm termtype
+ in
+ let term = Option.map nf term in
+ if not (Evd.has_undefined evm) && not (Option.is_empty term) then
+ let ctx = Evd.universe_context evm in
+ declare_instance_constant k pri global imps ?hook id
+ poly ctx (Option.get term) termtype
+ else if !refine_instance || Option.is_empty term then begin
+ let kind = Decl_kinds.Global, poly, Decl_kinds.DefinitionBody Decl_kinds.Instance in
+ if Flags.is_program_mode () then
+ let hook vis gr =
+ let cst = match gr with ConstRef kn -> kn | _ -> assert false in
+ Impargs.declare_manual_implicits false gr ~enriching:false [imps];
+ Typeclasses.declare_instance pri (not global) (ConstRef cst)
in
- let app, ty_constr = instance_constructor k subst in
- let termtype = it_mkProd_or_LetIn ty_constr (ctx' @ ctx) in
- let term = Termops.it_mkLambda_or_LetIn (Option.get app) (ctx' @ ctx) in
- Some term, termtype
- | Some (Inr (def, subst)) ->
- let termtype = it_mkProd_or_LetIn cty ctx in
- let term = Termops.it_mkLambda_or_LetIn def ctx in
- Some term, termtype
- in
- let _ =
- evars := Evarutil.nf_evar_map !evars;
- evars := Typeclasses.resolve_typeclasses ~filter:Typeclasses.no_goals ~fail:true
- env !evars;
- (* Try resolving fields that are typeclasses automatically. *)
- evars := Typeclasses.resolve_typeclasses ~filter:Typeclasses.all_evars ~fail:false
- env !evars
- in
- let termtype = Evarutil.nf_evar !evars termtype in
- let term = Option.map (Evarutil.nf_evar !evars) term in
- let evm = undefined_evars !evars in
- Evarutil.check_evars env Evd.empty !evars termtype;
- if Evd.is_empty evm && term <> None then
- declare_instance_constant k pri global imps ?hook id (Option.get term) termtype
- else begin
- let kind = Decl_kinds.Global, Decl_kinds.DefinitionBody Decl_kinds.Instance in
- Flags.silently (fun () ->
- Lemmas.start_proof id kind termtype (fun _ -> instance_hook k pri global imps ?hook);
- if term <> None then
- Pfedit.by (!refine_ref (evm, Option.get term))
+ let obls, constr, typ =
+ match term with
+ | Some t ->
+ let obls, _, constr, typ =
+ Obligations.eterm_obligations env id evm 0 t termtype
+ in obls, Some constr, typ
+ | None -> [||], None, termtype
+ in
+ let hook = Lemmas.mk_hook hook in
+ let ctx = Evd.evar_universe_context evm in
+ ignore (Obligations.add_definition id ?term:constr
+ typ ctx ~kind:(Global,poly,Instance) ~hook obls);
+ id
+ else
+ (Flags.silently
+ (fun () ->
+ (* spiwack: it is hard to reorder the actions to do
+ the pretyping after the proof has opened. As a
+ consequence, we use the low-level primitives to code
+ the refinement manually.*)
+ let gls = List.rev (Evd.future_goals evm) in
+ let evm = Evd.reset_future_goals evm in
+ Lemmas.start_proof id kind evm termtype
+ (Lemmas.mk_hook
+ (fun _ -> instance_hook k pri global imps ?hook));
+ (* spiwack: I don't know what to do with the status here. *)
+ if not (Option.is_empty term) then
+ let init_refine =
+ Tacticals.New.tclTHENLIST [
+ Proofview.Refine.refine (fun evm -> evm, Option.get term);
+ Proofview.Unsafe.tclNEWGOALS gls;
+ Tactics.New.reduce_after_refine;
+ ]
+ in
+ ignore (Pfedit.by init_refine)
else if Flags.is_auto_intros () then
- Pfedit.by (Refiner.tclDO len Tactics.intro);
- (match tac with Some tac -> Pfedit.by tac | None -> ())) ();
- Flags.if_verbose (msg $$ Printer.pr_open_subgoals) ();
- id
- end
- end
+ ignore (Pfedit.by (Tacticals.New.tclDO len Tactics.intro));
+ (match tac with Some tac -> ignore (Pfedit.by tac) | None -> ())) ();
+ id)
+ end
+ else Errors.error "Unsolved obligations remaining.")
let named_of_rel_context l =
let acc, ctx =
List.fold_right
(fun (na, b, t) (subst, ctx) ->
- let id = match na with Anonymous -> raise (Invalid_argument "named_of_rel_context") | Name id -> id in
+ let id = match na with Anonymous -> invalid_arg "named_of_rel_context" | Name id -> id in
let d = (id, Option.map (substl subst) b, substl subst t) in
(mkVar id :: subst, d :: ctx))
l ([], [])
in ctx
-let string_of_global r =
- string_of_qualid (Nametab.shortest_qualid_of_global Idset.empty r)
-
-let context l =
+let context poly l =
let env = Global.env() in
let evars = ref Evd.empty in
- let _, ((env', fullctx), impls) = interp_context_evars evars env l in
- let fullctx = Evarutil.nf_rel_context_evar !evars fullctx in
+ let _, ((env', fullctx), impls) = interp_context_evars env evars l in
+ let subst = Evarutil.evd_comb0 Evarutil.nf_evars_and_universes evars in
+ let fullctx = Context.map_rel_context subst fullctx in
let ce t = Evarutil.check_evars env Evd.empty !evars t in
- List.iter (fun (n, b, t) -> Option.iter ce b; ce t) fullctx;
+ let () = List.iter (fun (n, b, t) -> Option.iter ce b; ce t) fullctx in
let ctx =
try named_of_rel_context fullctx
with e when Errors.noncritical e ->
error "Anonymous variables not allowed in contexts."
in
- let fn (id, _, t) =
+ let uctx = Evd.universe_context_set !evars in
+ let fn status (id, b, t) =
if Lib.is_modtype () && not (Lib.sections_are_opened ()) then
- let cst = Declare.declare_constant ~internal:Declare.KernelSilent id
- (ParameterEntry (None,t,None), IsAssumption Logical)
- in
+ let uctx = Univ.ContextSet.to_context uctx in
+ let decl = (ParameterEntry (None,poly,(t,uctx),None), IsAssumption Logical) in
+ let cst = Declare.declare_constant ~internal:Declare.KernelSilent id decl in
match class_of_constr t with
- | Some (rels, (tc, args) as _cl) ->
- add_instance (Typeclasses.new_instance tc None false (ConstRef cst))
+ | Some (rels, ((tc,_), args) as _cl) ->
+ add_instance (Typeclasses.new_instance tc None false (*FIXME*)
+ poly (ConstRef cst));
+ status
(* declare_subclasses (ConstRef cst) cl *)
- | None -> ()
- else (
- let impl = List.exists
- (fun (x,_) ->
- match x with ExplByPos (_, Some id') -> id = id' | _ -> false) impls
+ | None -> status
+ else
+ let test (x, _) = match x with
+ | ExplByPos (_, Some id') -> Id.equal id id'
+ | _ -> false
+ in
+ let impl = List.exists test impls in
+ let decl = (Discharge, poly, Definitional) in
+ let nstatus =
+ pi3 (Command.declare_assumption false decl (t, uctx) [] impl
+ Vernacexpr.NoInline (Loc.ghost, id))
in
- Command.declare_assumption false (Local (* global *), Definitional) t
- [] impl (* implicit *) None (* inline *) (dummy_loc, id))
- in List.iter fn (List.rev ctx)
-
+ status && nstatus
+ in List.fold_left fn true (List.rev ctx)