summaryrefslogtreecommitdiff
path: root/kernel/term_typing.ml
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/term_typing.ml')
-rw-r--r--kernel/term_typing.ml357
1 files changed, 248 insertions, 109 deletions
diff --git a/kernel/term_typing.ml b/kernel/term_typing.ml
index 8932ce5e..a3441aa3 100644
--- a/kernel/term_typing.ml
+++ b/kernel/term_typing.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 *)
@@ -12,147 +12,286 @@
(* This module provides the main entry points for type-checking basic
declarations *)
+open Errors
open Util
open Names
open Univ
open Term
-open Reduction
-open Sign
+open Context
open Declarations
-open Inductive
open Environ
open Entries
-open Type_errors
-open Indtypes
open Typeops
+open Fast_typeops
-let constrain_type env j cst1 = function
- | None ->
- make_polymorphic_if_constant_for_ind env j, cst1
- | Some t ->
- let (tj,cst2) = infer_type env t in
- let (_,cst3) = judge_of_cast env j DEFAULTcast tj in
+let constrain_type env j poly subst = function
+ | `None ->
+ if not poly then (* Old-style polymorphism *)
+ make_polymorphic_if_constant_for_ind env j
+ else RegularArity (Vars.subst_univs_level_constr subst j.uj_type)
+ | `Some t ->
+ let tj = infer_type env t in
+ let _ = judge_of_cast env j DEFAULTcast tj in
assert (eq_constr t tj.utj_val);
- let cstrs = union_constraints (union_constraints cst1 cst2) cst3 in
- NonPolymorphicType t, cstrs
-
-let local_constrain_type env j cst1 = function
- | None ->
- j.uj_type, cst1
- | Some t ->
- let (tj,cst2) = infer_type env t in
- let (_,cst3) = judge_of_cast env j DEFAULTcast tj in
- assert (eq_constr t tj.utj_val);
- t, union_constraints (union_constraints cst1 cst2) cst3
-
-let translate_local_def env (b,topt) =
- let (j,cst) = infer env b in
- let (typ,cst) = local_constrain_type env j cst topt in
- (j.uj_val,typ,cst)
+ RegularArity (Vars.subst_univs_level_constr subst t)
+ | `SomeWJ (t, tj) ->
+ let tj = infer_type env t in
+ let _ = judge_of_cast env j DEFAULTcast tj in
+ assert (eq_constr t tj.utj_val);
+ RegularArity (Vars.subst_univs_level_constr subst t)
-let translate_local_assum env t =
- let (j,cst) = infer env t in
- let t = Typeops.assumption_of_judgment env j in
- (t,cst)
-
-(*
-
-(* 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 (id,_,_ as d) env =
- let _ =
- try
- let _ = lookup_named id env in
- error ("Identifier "^string_of_id id^" already defined.")
- with Not_found -> () in
- push_named d env
-
-let push_named_def = push_rel_or_named_def safe_push_named
-let push_rel_def = push_rel_or_named_def push_rel
-
-let push_rel_or_named_assum push (id,t) env =
- let (j,cst) = safe_infer env t in
- let t = Typeops.assumption_of_judgment env j in
- let env' = add_constraints cst env in
- let env'' = push (id,None,t) env' in
- (cst,env'')
+let map_option_typ = function None -> `None | Some x -> `Some x
+
+(* Insertion of constants and parameters in environment. *)
-let push_named_assum = push_rel_or_named_assum push_named
-let push_rel_assum d env = snd (push_rel_or_named_assum push_rel d env)
+let mk_pure_proof c = (c, Univ.ContextSet.empty), Declareops.no_seff
-let push_rels_with_univ vars env =
- List.fold_left (fun env nvar -> push_rel_assum nvar env) env vars
-*)
+let handle_side_effects env body side_eff =
+ let handle_sideff t se =
+ let cbl = match se with
+ | SEsubproof (c,cb,b) -> [c,cb,b]
+ | SEscheme (cl,_) -> List.map (fun (_,c,cb,b) -> c,cb,b) cl 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
+ let cname c =
+ let name = string_of_con c in
+ for i = 0 to String.length name - 1 do
+ if name.[i] == '.' || name.[i] == '#' then name.[i] <- '_' done;
+ Name (id_of_string name) in
+ let rec sub c i x = match kind_of_term x with
+ | Const (c', _) when eq_constant c c' -> mkRel i
+ | _ -> map_constr_with_binders ((+) 1) (fun i x -> sub c i x) i x in
+ let rec sub_body c u b i x = match kind_of_term x with
+ | Const (c',u') when eq_constant c c' ->
+ Vars.subst_instance_constr u' b
+ | _ -> map_constr_with_binders ((+) 1) (fun i x -> sub_body c u b i x) i x in
+ let fix_body (c,cb,b) t =
+ match cb.const_body, b with
+ | Def b, _ ->
+ let b = Mod_subst.force_constr b in
+ let poly = cb.const_polymorphic in
+ if not poly then
+ let b_ty = Typeops.type_of_constant_type env cb.const_type in
+ let t = sub c 1 (Vars.lift 1 t) in
+ mkLetIn (cname c, b, b_ty, t)
+ else
+ let univs = cb.const_universes in
+ sub_body c (Univ.UContext.instance univs) b 1 (Vars.lift 1 t)
+ | OpaqueDef _, `Opaque (b,_) ->
+ let poly = cb.const_polymorphic in
+ if not poly then
+ let b_ty = Typeops.type_of_constant_type env cb.const_type in
+ let t = sub c 1 (Vars.lift 1 t) in
+ mkApp (mkLambda (cname c, b_ty, t), [|b|])
+ else
+ let univs = cb.const_universes in
+ sub_body c (Univ.UContext.instance univs) b 1 (Vars.lift 1 t)
+ | _ -> assert false
+ in
+ List.fold_right fix_body cbl t
+ in
+ (* CAVEAT: we assure a proper order *)
+ Declareops.fold_side_effects handle_sideff body
+ (Declareops.uniquize_side_effects side_eff)
+let hcons_j j =
+ { uj_val = hcons_constr j.uj_val; uj_type = hcons_constr j.uj_type}
-(* Insertion of constants and parameters in environment. *)
+let feedback_completion_typecheck =
+ Option.iter (fun state_id -> Pp.feedback ~state_id Feedback.Complete)
+
+let subst_instance_j s j =
+ { uj_val = Vars.subst_univs_level_constr s j.uj_val;
+ uj_type = Vars.subst_univs_level_constr s j.uj_type }
-let infer_declaration env dcl =
+let infer_declaration env kn dcl =
match dcl with
+ | ParameterEntry (ctx,poly,(t,uctx),nl) ->
+ let env = push_context uctx env in
+ let j = infer env t in
+ let abstract = poly && not (Option.is_empty kn) in
+ let usubst, univs = Univ.abstract_universes abstract uctx in
+ let c = Typeops.assumption_of_judgment env j in
+ let t = hcons_constr (Vars.subst_univs_level_constr usubst c) in
+ Undef nl, RegularArity t, None, poly, univs, false, ctx
+
+ | DefinitionEntry ({ const_entry_type = Some typ;
+ const_entry_opaque = true;
+ const_entry_polymorphic = false} as c) ->
+ let env = push_context c.const_entry_universes env in
+ let { const_entry_body = body; const_entry_feedback = feedback_id } = c in
+ let tyj = infer_type env typ in
+ let proofterm =
+ Future.chain ~greedy:true ~pure:true body (fun ((body, ctx),side_eff) ->
+ let body = handle_side_effects env body side_eff in
+ let env' = push_context_set ctx env in
+ let j = infer env' body in
+ let j = hcons_j j in
+ let subst = Univ.LMap.empty in
+ let _typ = constrain_type env' j c.const_entry_polymorphic subst
+ (`SomeWJ (typ,tyj)) in
+ feedback_completion_typecheck feedback_id;
+ j.uj_val, ctx) in
+ let def = OpaqueDef (Opaqueproof.create proofterm) in
+ def, RegularArity typ, None, c.const_entry_polymorphic,
+ c.const_entry_universes,
+ c.const_entry_inline_code, c.const_entry_secctx
+
| DefinitionEntry c ->
- let (j,cst) = infer env c.const_entry_body in
- let j =
- {uj_val = hcons_constr j.uj_val;
- uj_type = hcons_constr j.uj_type} in
- let (typ,cst) = constrain_type env j cst c.const_entry_type in
- let def =
- if c.const_entry_opaque
- then OpaqueDef (Declarations.opaque_from_val j.uj_val)
- else Def (Declarations.from_val j.uj_val)
+ let env = push_context c.const_entry_universes env in
+ let { const_entry_type = typ; const_entry_opaque = opaque } = c in
+ let { const_entry_body = body; const_entry_feedback = feedback_id } = c in
+ let (body, ctx), side_eff = Future.join body in
+ assert(Univ.ContextSet.is_empty ctx);
+ let body = handle_side_effects env body side_eff in
+ let abstract = c.const_entry_polymorphic && not (Option.is_empty kn) in
+ let usubst, univs = Univ.abstract_universes abstract c.const_entry_universes in
+ let j = infer env body in
+ let typ = constrain_type env j c.const_entry_polymorphic usubst (map_option_typ typ) in
+ let def = hcons_constr (Vars.subst_univs_level_constr usubst j.uj_val) in
+ let def =
+ if opaque then OpaqueDef (Opaqueproof.create (Future.from_val (def, Univ.ContextSet.empty)))
+ else Def (Mod_subst.from_val def)
in
- def, typ, cst, c.const_entry_secctx
- | ParameterEntry (ctx,t,nl) ->
- let (j,cst) = infer env t in
- let t = hcons_constr (Typeops.assumption_of_judgment env j) in
- Undef nl, NonPolymorphicType t, cst, ctx
+ feedback_completion_typecheck feedback_id;
+ def, typ, None, c.const_entry_polymorphic,
+ univs, c.const_entry_inline_code, c.const_entry_secctx
+
+ | ProjectionEntry {proj_entry_ind = ind; proj_entry_arg = i} ->
+ let mib, _ = Inductive.lookup_mind_specif env (ind,0) in
+ let kn, pb =
+ match mib.mind_record with
+ | Some (Some (id, kns, pbs)) ->
+ if i < Array.length pbs then
+ kns.(i), pbs.(i)
+ else assert false
+ | _ -> assert false
+ in
+ let term, typ = pb.proj_eta in
+ Def (Mod_subst.from_val (hcons_constr term)), RegularArity typ, Some pb,
+ mib.mind_polymorphic, mib.mind_universes, false, None
let global_vars_set_constant_type env = function
- | NonPolymorphicType t -> global_vars_set env t
- | PolymorphicArity (ctx,_) ->
- Sign.fold_rel_context
+ | RegularArity t -> global_vars_set env t
+ | TemplateArity (ctx,_) ->
+ Context.fold_rel_context
(fold_rel_declaration
- (fun t c -> Idset.union (global_vars_set env t) c))
- ctx ~init:Idset.empty
-
-let build_constant_declaration env kn (def,typ,cst,ctx) =
- let hyps =
- let inferred =
- let ids_typ = global_vars_set_constant_type env typ in
- let ids_def = match def with
- | Undef _ -> Idset.empty
- | Def cs -> global_vars_set env (Declarations.force cs)
- | OpaqueDef lc ->
- global_vars_set env (Declarations.force_opaque lc) in
- keep_hyps env (Idset.union ids_typ ids_def) in
- let declared = match ctx with
- | None -> inferred
- | Some declared -> declared in
- let mk_set l = List.fold_right Idset.add (List.map pi1 l) Idset.empty in
+ (fun t c -> Id.Set.union (global_vars_set env t) c))
+ ctx ~init:Id.Set.empty
+
+let record_aux env s1 s2 =
+ let v =
+ String.concat " "
+ (List.map (fun (id, _,_) -> Id.to_string id)
+ (keep_hyps env (Id.Set.union s1 s2))) in
+ Aux_file.record_in_aux "context_used" v
+
+let suggest_proof_using = ref (fun _ _ _ _ _ -> ())
+let set_suggest_proof_using f = suggest_proof_using := f
+
+let build_constant_declaration kn env (def,typ,proj,poly,univs,inline_code,ctx) =
+ let check declared inferred =
+ let mk_set l = List.fold_right Id.Set.add (List.map pi1 l) Id.Set.empty in
let inferred_set, declared_set = mk_set inferred, mk_set declared in
- if not (Idset.subset inferred_set declared_set) then
- error ("The following section variable are used but not declared:\n"^
- (String.concat ", " (List.map string_of_id
- (Idset.elements (Idset.diff inferred_set declared_set)))));
- declared in
- let tps = Cemitcodes.from_val (compile_constant_body env def) in
+ if not (Id.Set.subset inferred_set declared_set) then
+ let l = Id.Set.elements (Idset.diff inferred_set declared_set) in
+ let n = List.length l in
+ errorlabstrm "" (Pp.(str "The following section " ++
+ str (String.plural n "variable") ++
+ str " " ++ str (String.conjugate_verb_to_be n) ++
+ str " used but not declared:" ++
+ fnl () ++ pr_sequence Id.print (List.rev l) ++ str ".")) in
+ (* We try to postpone the computation of used section variables *)
+ let hyps, def =
+ let context_ids = List.map pi1 (named_context env) in
+ match ctx with
+ | None when not (List.is_empty context_ids) ->
+ (* No declared section vars, and non-empty section context:
+ we must look at the body NOW, if any *)
+ let ids_typ = global_vars_set_constant_type env typ in
+ let ids_def = match def with
+ | Undef _ -> Idset.empty
+ | Def cs -> global_vars_set env (Mod_subst.force_constr cs)
+ | OpaqueDef lc ->
+ let vars =
+ global_vars_set env
+ (Opaqueproof.force_proof (opaque_tables env) lc) in
+ (* we force so that cst are added to the env immediately after *)
+ ignore(Opaqueproof.force_constraints (opaque_tables env) lc);
+ !suggest_proof_using kn env vars ids_typ context_ids;
+ if !Flags.compilation_mode = Flags.BuildVo then
+ record_aux env ids_typ vars;
+ vars
+ in
+ keep_hyps env (Idset.union ids_typ ids_def), def
+ | None ->
+ if !Flags.compilation_mode = Flags.BuildVo then
+ record_aux env Id.Set.empty Id.Set.empty;
+ [], def (* Empty section context: no need to check *)
+ | Some declared ->
+ (* We use the declared set and chain a check of correctness *)
+ declared,
+ match def with
+ | Undef _ as x -> x (* nothing to check *)
+ | Def cs as x ->
+ let ids_typ = global_vars_set_constant_type env typ in
+ let ids_def = global_vars_set env (Mod_subst.force_constr cs) in
+ let inferred = keep_hyps env (Idset.union ids_typ ids_def) in
+ check declared inferred;
+ x
+ | OpaqueDef lc -> (* In this case we can postpone the check *)
+ OpaqueDef (Opaqueproof.iter_direct_opaque (fun c ->
+ let ids_typ = global_vars_set_constant_type env typ in
+ let ids_def = global_vars_set env c in
+ let inferred = keep_hyps env (Idset.union ids_typ ids_def) in
+ check declared inferred) lc) in
+ let tps =
+ (* FIXME: incompleteness of the bytecode vm: we compile polymorphic
+ constants like opaque definitions. *)
+ if poly then Cemitcodes.from_val Cemitcodes.BCconstant
+ else
+ match proj with
+ | None -> Cemitcodes.from_val (compile_constant_body env def)
+ | Some pb ->
+ Cemitcodes.from_val (compile_constant_body env (Def (Mod_subst.from_val pb.proj_body)))
+ in
{ const_hyps = hyps;
const_body = def;
const_type = typ;
+ const_proj = proj;
const_body_code = tps;
- const_constraints = cst }
+ const_polymorphic = poly;
+ const_universes = univs;
+ const_inline_code = inline_code }
+
(*s Global and local constant declaration. *)
let translate_constant env kn ce =
- build_constant_declaration env kn (infer_declaration env ce)
+ build_constant_declaration kn env (infer_declaration env (Some kn) ce)
+
+let translate_local_assum env t =
+ let j = infer env t in
+ let t = Typeops.assumption_of_judgment env j in
+ t
let translate_recipe env kn r =
- build_constant_declaration env kn
- (let def,typ,cst,hyps = Cooking.cook_constant env r in
- def,typ,cst,Some hyps)
+ build_constant_declaration kn env (Cooking.cook_constant env r)
+
+let translate_local_def env id centry =
+ let def,typ,proj,poly,univs,inline_code,ctx =
+ infer_declaration env None (DefinitionEntry centry) in
+ let typ = type_of_constant_type env typ in
+ def, typ, univs
(* Insertion of inductive types. *)
-let translate_mind env kn mie = check_inductive env kn mie
+let translate_mind env kn mie = Indtypes.check_inductive env kn mie
+
+let handle_entry_side_effects env ce = { ce with
+ const_entry_body = Future.chain ~greedy:true ~pure:true
+ ce.const_entry_body (fun ((body, ctx), side_eff) ->
+ (handle_side_effects env body side_eff, ctx), Declareops.no_seff);
+}