(************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) (* t -> bool val identity : t val filter_list : t -> 'a list -> 'a list val filter_array : t -> 'a array -> 'a array val extend : int -> t -> t val compose : t -> t -> t val apply_subfilter : t -> bool list -> t val restrict_upon : t -> int -> (int -> bool) -> t option val map_along : (bool -> 'a -> bool) -> t -> 'a list -> t val make : bool list -> t val repr : t -> bool list option end = struct type t = bool list option (** We guarantee through the interface that if a filter is [Some _] then it contains at least one [false] somewhere. *) let identity = None let rec equal l1 l2 = match l1, l2 with | [], [] -> true | h1 :: l1, h2 :: l2 -> (if h1 then h2 else not h2) && equal l1 l2 | _ -> false let equal l1 l2 = match l1, l2 with | None, None -> true | Some _, None | None, Some _ -> false | Some l1, Some l2 -> equal l1 l2 let rec is_identity = function | [] -> true | true :: l -> is_identity l | false :: _ -> false let normalize f = if is_identity f then None else Some f let filter_list f l = match f with | None -> l | Some f -> CList.filter_with f l let filter_array f v = match f with | None -> v | Some f -> CArray.filter_with f v let rec extend n l = if n = 0 then l else extend (pred n) (true :: l) let extend n = function | None -> None | Some f -> Some (extend n f) let compose f1 f2 = match f1 with | None -> f2 | Some f1 -> match f2 with | None -> None | Some f2 -> normalize (CList.filter_with f1 f2) let apply_subfilter_array filter subfilter = (** In both cases we statically know that the argument will contain at least one [false] *) match filter with | None -> Some (Array.to_list subfilter) | Some f -> let len = Array.length subfilter in let fold b (i, ans) = if b then let () = assert (0 <= i) in (pred i, Array.unsafe_get subfilter i :: ans) else (i, false :: ans) in Some (snd (List.fold_right fold f (pred len, []))) let apply_subfilter filter subfilter = apply_subfilter_array filter (Array.of_list subfilter) let restrict_upon f len p = let newfilter = Array.init len p in if Array.for_all (fun id -> id) newfilter then None else Some (apply_subfilter_array f newfilter) let map_along f flt l = let ans = match flt with | None -> List.map (fun x -> f true x) l | Some flt -> List.map2 f flt l in normalize ans let make l = normalize l let repr f = f end (* The kinds of existential variables are now defined in [Evar_kinds] *) (* The type of mappings for existential variables *) module Dummy = struct end module Store = Store.Make(Dummy) type evar = Term.existential_key let string_of_existential evk = "?X" ^ string_of_int (Evar.repr evk) type evar_body = | Evar_empty | Evar_defined of constr type evar_info = { evar_concl : constr; evar_hyps : named_context_val; evar_body : evar_body; evar_filter : Filter.t; evar_source : Evar_kinds.t Loc.located; evar_candidates : constr list option; (* if not None, list of allowed instances *) evar_extra : Store.t } let make_evar hyps ccl = { evar_concl = ccl; evar_hyps = hyps; evar_body = Evar_empty; evar_filter = Filter.identity; evar_source = (Loc.ghost,Evar_kinds.InternalHole); evar_candidates = None; evar_extra = Store.empty } let instance_mismatch () = anomaly (Pp.str "Signature and its instance do not match") let evar_concl evi = evi.evar_concl let evar_filter evi = evi.evar_filter let evar_body evi = evi.evar_body let evar_context evi = named_context_of_val evi.evar_hyps let evar_filtered_context evi = Filter.filter_list (evar_filter evi) (evar_context evi) let evar_hyps evi = evi.evar_hyps let evar_filtered_hyps evi = match Filter.repr (evar_filter evi) with | None -> evar_hyps evi | Some filter -> let rec make_hyps filter ctxt = match filter, ctxt with | [], [] -> empty_named_context_val | false :: filter, _ :: ctxt -> make_hyps filter ctxt | true :: filter, decl :: ctxt -> let hyps = make_hyps filter ctxt in push_named_context_val decl hyps | _ -> instance_mismatch () in make_hyps filter (evar_context evi) let evar_env evi = Global.env_of_context evi.evar_hyps let evar_filtered_env evi = match Filter.repr (evar_filter evi) with | None -> evar_env evi | Some filter -> let rec make_env filter ctxt = match filter, ctxt with | [], [] -> reset_context (Global.env ()) | false :: filter, _ :: ctxt -> make_env filter ctxt | true :: filter, decl :: ctxt -> let env = make_env filter ctxt in push_named decl env | _ -> instance_mismatch () in make_env filter (evar_context evi) let map_evar_body f = function | Evar_empty -> Evar_empty | Evar_defined d -> Evar_defined (f d) let map_evar_info f evi = {evi with evar_body = map_evar_body f evi.evar_body; evar_hyps = map_named_val f evi.evar_hyps; evar_concl = f evi.evar_concl; evar_candidates = Option.map (List.map f) evi.evar_candidates } (* This exception is raised by *.existential_value *) exception NotInstantiatedEvar (* Note: let-in contributes to the instance *) let evar_instance_array test_id info args = let len = Array.length args in let rec instrec filter ctxt i = match filter, ctxt with | [], [] -> if Int.equal i len then [] else instance_mismatch () | false :: filter, _ :: ctxt -> instrec filter ctxt i | true :: filter, (id,_,_ as d) :: ctxt -> if i < len then let c = Array.unsafe_get args i in if test_id d c then instrec filter ctxt (succ i) else (id, c) :: instrec filter ctxt (succ i) else instance_mismatch () | _ -> instance_mismatch () in match Filter.repr (evar_filter info) with | None -> let map i (id,_,_ as d) = if (i < len) then let c = Array.unsafe_get args i in if test_id d c then None else Some (id,c) else instance_mismatch () in List.map_filter_i map (evar_context info) | Some filter -> instrec filter (evar_context info) 0 let make_evar_instance_array info args = evar_instance_array (fun (id,_,_) -> isVarId id) info args let instantiate_evar_array info c args = let inst = make_evar_instance_array info args in match inst with | [] -> c | _ -> replace_vars inst c module StringOrd = struct type t = string let compare = String.compare end module UNameMap = struct include Map.Make(StringOrd) let union s t = if s == t then s else merge (fun k l r -> match l, r with | Some _, _ -> l | _, _ -> r) s t end (* 2nd part used to check consistency on the fly. *) type evar_universe_context = { uctx_names : Univ.Level.t UNameMap.t * string Univ.LMap.t; uctx_local : Univ.universe_context_set; (** The local context of variables *) uctx_univ_variables : Universes.universe_opt_subst; (** The local universes that are unification variables *) uctx_univ_algebraic : Univ.universe_set; (** The subset of unification variables that can be instantiated with algebraic universes as they appear in inferred types only. *) uctx_universes : Univ.universes; (** The current graph extended with the local constraints *) uctx_initial_universes : Univ.universes; (** The graph at the creation of the evar_map *) } let empty_evar_universe_context = { uctx_names = UNameMap.empty, Univ.LMap.empty; uctx_local = Univ.ContextSet.empty; uctx_univ_variables = Univ.LMap.empty; uctx_univ_algebraic = Univ.LSet.empty; uctx_universes = Univ.initial_universes; uctx_initial_universes = Univ.initial_universes } let evar_universe_context_from e = let u = universes e in {empty_evar_universe_context with uctx_universes = u; uctx_initial_universes = u} let is_empty_evar_universe_context ctx = Univ.ContextSet.is_empty ctx.uctx_local && Univ.LMap.is_empty ctx.uctx_univ_variables let union_evar_universe_context ctx ctx' = if ctx == ctx' then ctx else if is_empty_evar_universe_context ctx' then ctx else let local = Univ.ContextSet.union ctx.uctx_local ctx'.uctx_local in let names = UNameMap.union (fst ctx.uctx_names) (fst ctx'.uctx_names) in let newus = Univ.LSet.diff (Univ.ContextSet.levels ctx'.uctx_local) (Univ.ContextSet.levels ctx.uctx_local) in let newus = Univ.LSet.diff newus (Univ.LMap.domain ctx.uctx_univ_variables) in let declarenew g = Univ.LSet.fold (fun u g -> Univ.add_universe u false g) newus g in let names_rev = Univ.LMap.union (snd ctx.uctx_names) (snd ctx'.uctx_names) in { uctx_names = (names, names_rev); uctx_local = local; uctx_univ_variables = Univ.LMap.subst_union ctx.uctx_univ_variables ctx'.uctx_univ_variables; uctx_univ_algebraic = Univ.LSet.union ctx.uctx_univ_algebraic ctx'.uctx_univ_algebraic; uctx_initial_universes = declarenew ctx.uctx_initial_universes; uctx_universes = if local == ctx.uctx_local then ctx.uctx_universes else let cstrsr = Univ.ContextSet.constraints ctx'.uctx_local in Univ.merge_constraints cstrsr (declarenew ctx.uctx_universes) } (* let union_evar_universe_context_key = Profile.declare_profile "union_evar_universe_context";; *) (* let union_evar_universe_context = *) (* Profile.profile2 union_evar_universe_context_key union_evar_universe_context;; *) type 'a in_evar_universe_context = 'a * evar_universe_context let evar_universe_context_set diff ctx = let initctx = ctx.uctx_local in let cstrs = Univ.LSet.fold (fun l cstrs -> try match Univ.LMap.find l ctx.uctx_univ_variables with | Some u -> Univ.Constraint.add (l, Univ.Eq, Option.get (Univ.Universe.level u)) cstrs | None -> cstrs with Not_found | Option.IsNone -> cstrs) (Univ.Instance.levels (Univ.UContext.instance diff)) Univ.Constraint.empty in Univ.ContextSet.add_constraints cstrs initctx let evar_universe_context_constraints ctx = snd ctx.uctx_local let evar_context_universe_context ctx = Univ.ContextSet.to_context ctx.uctx_local let evar_universe_context_of ctx = { empty_evar_universe_context with uctx_local = ctx } let evar_universe_context_subst ctx = ctx.uctx_univ_variables let add_uctx_names s l (names, names_rev) = (UNameMap.add s l names, Univ.LMap.add l s names_rev) let evar_universe_context_of_binders b = let ctx = empty_evar_universe_context in let names = List.fold_left (fun acc (id, l) -> add_uctx_names (Id.to_string id) l acc) ctx.uctx_names b in { ctx with uctx_names = names } let instantiate_variable l b v = v := Univ.LMap.add l (Some b) !v exception UniversesDiffer let process_universe_constraints univs vars alg cstrs = let vars = ref vars in let normalize = Universes.normalize_universe_opt_subst vars in let rec unify_universes fo l d r local = let l = normalize l and r = normalize r in if Univ.Universe.equal l r then local else let varinfo x = match Univ.Universe.level x with | None -> Inl x | Some l -> Inr (l, Univ.LMap.mem l !vars, Univ.LSet.mem l alg) in if d == Universes.ULe then if Univ.check_leq univs l r then (** Keep Prop/Set <= var around if var might be instantiated by prop or set later. *) if Univ.Universe.is_level l then match Univ.Universe.level r with | Some r -> Univ.Constraint.add (Option.get (Univ.Universe.level l),Univ.Le,r) local | _ -> local else local else match Univ.Universe.level r with | None -> error ("Algebraic universe on the right") | Some rl -> if Univ.Level.is_small rl then let levels = Univ.Universe.levels l in Univ.LSet.fold (fun l local -> if Univ.Level.is_small l || Univ.LMap.mem l !vars then unify_universes fo (Univ.Universe.make l) Universes.UEq r local else raise (Univ.UniverseInconsistency (Univ.Le, Univ.Universe.make l, r, None))) levels local else Univ.enforce_leq l r local else if d == Universes.ULub then match varinfo l, varinfo r with | (Inr (l, true, _), Inr (r, _, _)) | (Inr (r, _, _), Inr (l, true, _)) -> instantiate_variable l (Univ.Universe.make r) vars; Univ.enforce_eq_level l r local | Inr (_, _, _), Inr (_, _, _) -> unify_universes true l Universes.UEq r local | _, _ -> assert false else (* d = Universes.UEq *) match varinfo l, varinfo r with | Inr (l', lloc, _), Inr (r', rloc, _) -> let () = if lloc then instantiate_variable l' r vars else if rloc then instantiate_variable r' l vars else if not (Univ.check_eq univs l r) then (* Two rigid/global levels, none of them being local, one of them being Prop/Set, disallow *) if Univ.Level.is_small l' || Univ.Level.is_small r' then raise (Univ.UniverseInconsistency (Univ.Eq, l, r, None)) else if fo then raise UniversesDiffer in Univ.enforce_eq_level l' r' local | Inr (l, loc, alg), Inl r | Inl r, Inr (l, loc, alg) -> let inst = Univ.univ_level_rem l r r in if alg then (instantiate_variable l inst vars; local) else let lu = Univ.Universe.make l in if Univ.univ_level_mem l r then Univ.enforce_leq inst lu local else raise (Univ.UniverseInconsistency (Univ.Eq, lu, r, None)) | _, _ (* One of the two is algebraic or global *) -> if Univ.check_eq univs l r then local else raise (Univ.UniverseInconsistency (Univ.Eq, l, r, None)) in let local = Universes.Constraints.fold (fun (l,d,r) local -> unify_universes false l d r local) cstrs Univ.Constraint.empty in !vars, local let add_constraints_context ctx cstrs = let univs, local = ctx.uctx_local in let cstrs' = Univ.Constraint.fold (fun (l,d,r) acc -> let l = Univ.Universe.make l and r = Univ.Universe.make r in let cstr' = if d == Univ.Lt then (Univ.Universe.super l, Universes.ULe, r) else (l, (if d == Univ.Le then Universes.ULe else Universes.UEq), r) in Universes.Constraints.add cstr' acc) cstrs Universes.Constraints.empty in let vars, local' = process_universe_constraints ctx.uctx_universes ctx.uctx_univ_variables ctx.uctx_univ_algebraic cstrs' in { ctx with uctx_local = (univs, Univ.Constraint.union local local'); uctx_univ_variables = vars; uctx_universes = Univ.merge_constraints local' ctx.uctx_universes } (* let addconstrkey = Profile.declare_profile "add_constraints_context";; *) (* let add_constraints_context = Profile.profile2 addconstrkey add_constraints_context;; *) let add_universe_constraints_context ctx cstrs = let univs, local = ctx.uctx_local in let vars, local' = process_universe_constraints ctx.uctx_universes ctx.uctx_univ_variables ctx.uctx_univ_algebraic cstrs in { ctx with uctx_local = (univs, Univ.Constraint.union local local'); uctx_univ_variables = vars; uctx_universes = Univ.merge_constraints local' ctx.uctx_universes } (* let addunivconstrkey = Profile.declare_profile "add_universe_constraints_context";; *) (* let add_universe_constraints_context = *) (* Profile.profile2 addunivconstrkey add_universe_constraints_context;; *) (*******************************************************************) (* Metamaps *) (*******************************************************************) (* Constraints for existential variables *) (*******************************************************************) type 'a freelisted = { rebus : 'a; freemetas : Int.Set.t } (* Collects all metavars appearing in a constr *) let metavars_of c = let rec collrec acc c = match kind_of_term c with | Meta mv -> Int.Set.add mv acc | _ -> fold_constr collrec acc c in collrec Int.Set.empty c let mk_freelisted c = { rebus = c; freemetas = metavars_of c } let map_fl f cfl = { cfl with rebus=f cfl.rebus } (* Status of an instance found by unification wrt to the meta it solves: - a supertype of the meta (e.g. the solution to ?X <= T is a supertype of ?X) - a subtype of the meta (e.g. the solution to T <= ?X is a supertype of ?X) - a term that can be eta-expanded n times while still being a solution (e.g. the solution [P] to [?X u v = P u v] can be eta-expanded twice) *) type instance_constraint = IsSuperType | IsSubType | Conv let eq_instance_constraint c1 c2 = c1 == c2 (* Status of the unification of the type of an instance against the type of the meta it instantiates: - CoerceToType means that the unification of types has not been done and that a coercion can still be inserted: the meta should not be substituted freely (this happens for instance given via the "with" binding clause). - TypeProcessed means that the information obtainable from the unification of types has been extracted. - TypeNotProcessed means that the unification of types has not been done but it is known that no coercion may be inserted: the meta can be substituted freely. *) type instance_typing_status = CoerceToType | TypeNotProcessed | TypeProcessed (* Status of an instance together with the status of its type unification *) type instance_status = instance_constraint * instance_typing_status (* Clausal environments *) type clbinding = | Cltyp of Name.t * constr freelisted | Clval of Name.t * (constr freelisted * instance_status) * constr freelisted let map_clb f = function | Cltyp (na,cfl) -> Cltyp (na,map_fl f cfl) | Clval (na,(cfl1,pb),cfl2) -> Clval (na,(map_fl f cfl1,pb),map_fl f cfl2) (* name of defined is erased (but it is pretty-printed) *) let clb_name = function Cltyp(na,_) -> (na,false) | Clval (na,_,_) -> (na,true) (***********************) module Metaset = Int.Set module Metamap = Int.Map let metamap_to_list m = Metamap.fold (fun n v l -> (n,v)::l) m [] (*************************) (* Unification state *) type conv_pb = Reduction.conv_pb type evar_constraint = conv_pb * Environ.env * constr * constr module EvMap = Evar.Map module EvNames : sig open Misctypes type t val empty : t val add_name_newly_undefined : intro_pattern_naming_expr -> Evar.t -> evar_info -> t -> t val add_name_undefined : intro_pattern_naming_expr -> Evar.t -> evar_info -> t -> t val remove_name_defined : Evar.t -> t -> t val rename : Evar.t -> Id.t -> t -> t val reassign_name_defined : Evar.t -> Evar.t -> t -> t val ident : Evar.t -> t -> Id.t option val key : Id.t -> t -> Evar.t end = struct type t = Id.t EvMap.t * existential_key Idmap.t let empty = (EvMap.empty, Idmap.empty) let add_name_newly_undefined naming evk evi (evtoid, idtoev as names) = let id = match naming with | Misctypes.IntroAnonymous -> None | Misctypes.IntroIdentifier id -> if Idmap.mem id idtoev then user_err_loc (Loc.ghost,"",str "Already an existential evar of name " ++ pr_id id); Some id | Misctypes.IntroFresh id -> let id = Namegen.next_ident_away_from id (fun id -> Idmap.mem id idtoev) in Some id in match id with | None -> names | Some id -> (EvMap.add evk id evtoid, Idmap.add id evk idtoev) let add_name_undefined naming evk evi (evtoid,idtoev as evar_names) = if EvMap.mem evk evtoid then evar_names else add_name_newly_undefined naming evk evi evar_names let remove_name_defined evk (evtoid, idtoev as names) = let id = try Some (EvMap.find evk evtoid) with Not_found -> None in match id with | None -> names | Some id -> (EvMap.remove evk evtoid, Idmap.remove id idtoev) let rename evk id (evtoid, idtoev) = let id' = try Some (EvMap.find evk evtoid) with Not_found -> None in match id' with | None -> (EvMap.add evk id evtoid, Idmap.add id evk idtoev) | Some id' -> if Idmap.mem id idtoev then anomaly (str "Evar name already in use"); (EvMap.update evk id evtoid (* overwrite old name *), Idmap.add id evk (Idmap.remove id' idtoev)) let reassign_name_defined evk evk' (evtoid, idtoev as names) = let id = try Some (EvMap.find evk evtoid) with Not_found -> None in match id with | None -> names (** evk' must not be defined *) | Some id -> (EvMap.add evk' id (EvMap.remove evk evtoid), Idmap.add id evk' (Idmap.remove id idtoev)) let ident evk (evtoid, _) = try Some (EvMap.find evk evtoid) with Not_found -> None let key id (_, idtoev) = Idmap.find id idtoev end type evar_map = { (** Existential variables *) defn_evars : evar_info EvMap.t; undf_evars : evar_info EvMap.t; evar_names : EvNames.t; (** Universes *) universes : evar_universe_context; (** Conversion problems *) conv_pbs : evar_constraint list; last_mods : Evar.Set.t; (** Metas *) metas : clbinding Metamap.t; (** Interactive proofs *) effects : Safe_typing.private_constants; future_goals : Evar.t list; (** list of newly created evars, to be eventually turned into goals if not solved.*) principal_future_goal : Evar.t option; (** if [Some e], [e] must be contained [future_goals]. The evar [e] will inherit properties (now: the name) of the evar which will be instantiated with a term containing [e]. *) extras : Store.t; } (*** Lifting primitive from Evar.Map. ***) let rename evk id evd = { evd with evar_names = EvNames.rename evk id evd.evar_names } let add d e i = match i.evar_body with | Evar_empty -> let evar_names = EvNames.add_name_undefined Misctypes.IntroAnonymous e i d.evar_names in { d with undf_evars = EvMap.add e i d.undf_evars; evar_names } | Evar_defined _ -> let evar_names = EvNames.remove_name_defined e d.evar_names in { d with defn_evars = EvMap.add e i d.defn_evars; evar_names } let remove d e = let undf_evars = EvMap.remove e d.undf_evars in let defn_evars = EvMap.remove e d.defn_evars in let principal_future_goal = match d.principal_future_goal with | None -> None | Some e' -> if Evar.equal e e' then None else d.principal_future_goal in let future_goals = List.filter (fun e' -> not (Evar.equal e e')) d.future_goals in { d with undf_evars; defn_evars; principal_future_goal; future_goals } let find d e = try EvMap.find e d.undf_evars with Not_found -> EvMap.find e d.defn_evars let find_undefined d e = EvMap.find e d.undf_evars let mem d e = EvMap.mem e d.undf_evars || EvMap.mem e d.defn_evars (* spiwack: this function loses information from the original evar_map it might be an idea not to export it. *) let to_list d = (* Workaround for change in Map.fold behavior in ocaml 3.08.4 *) let l = ref [] in EvMap.iter (fun evk x -> l := (evk,x)::!l) d.defn_evars; EvMap.iter (fun evk x -> l := (evk,x)::!l) d.undf_evars; !l let undefined_map d = d.undf_evars let drop_all_defined d = { d with defn_evars = EvMap.empty } (* spiwack: not clear what folding over an evar_map, for now we shall simply fold over the inner evar_map. *) let fold f d a = EvMap.fold f d.defn_evars (EvMap.fold f d.undf_evars a) let fold_undefined f d a = EvMap.fold f d.undf_evars a let raw_map f d = let f evk info = let ans = f evk info in let () = match info.evar_body, ans.evar_body with | Evar_defined _, Evar_empty | Evar_empty, Evar_defined _ -> anomaly (str "Unrespectful mapping function.") | _ -> () in ans in let defn_evars = EvMap.smartmapi f d.defn_evars in let undf_evars = EvMap.smartmapi f d.undf_evars in { d with defn_evars; undf_evars; } let raw_map_undefined f d = let f evk info = let ans = f evk info in let () = match ans.evar_body with | Evar_defined _ -> anomaly (str "Unrespectful mapping function.") | _ -> () in ans in { d with undf_evars = EvMap.smartmapi f d.undf_evars; } let is_evar = mem let is_defined d e = EvMap.mem e d.defn_evars let is_undefined d e = EvMap.mem e d.undf_evars let existential_value d (n, args) = let info = find d n in match evar_body info with | Evar_defined c -> instantiate_evar_array info c args | Evar_empty -> raise NotInstantiatedEvar let existential_opt_value d ev = try Some (existential_value d ev) with NotInstantiatedEvar -> None let existential_type d (n, args) = let info = try find d n with Not_found -> anomaly (str "Evar " ++ str (string_of_existential n) ++ str " was not declared") in instantiate_evar_array info info.evar_concl args let add_constraints d c = { d with universes = add_constraints_context d.universes c } let add_universe_constraints d c = { d with universes = add_universe_constraints_context d.universes c } (*** /Lifting... ***) (* evar_map are considered empty disregarding histories *) let is_empty d = EvMap.is_empty d.defn_evars && EvMap.is_empty d.undf_evars && List.is_empty d.conv_pbs && Metamap.is_empty d.metas let cmap f evd = { evd with metas = Metamap.map (map_clb f) evd.metas; defn_evars = EvMap.map (map_evar_info f) evd.defn_evars; undf_evars = EvMap.map (map_evar_info f) evd.undf_evars } (* spiwack: deprecated *) let create_evar_defs sigma = { sigma with conv_pbs=[]; last_mods=Evar.Set.empty; metas=Metamap.empty } (* spiwack: tentatively deprecated *) let create_goal_evar_defs sigma = { sigma with (* conv_pbs=[]; last_mods=Evar.Set.empty; metas=Metamap.empty } *) metas=Metamap.empty } let empty = { defn_evars = EvMap.empty; undf_evars = EvMap.empty; universes = empty_evar_universe_context; conv_pbs = []; last_mods = Evar.Set.empty; metas = Metamap.empty; effects = Safe_typing.empty_private_constants; evar_names = EvNames.empty; (* id<->key for undefined evars *) future_goals = []; principal_future_goal = None; extras = Store.empty; } let from_env e = { empty with universes = evar_universe_context_from e } let from_ctx ctx = { empty with universes = ctx } let has_undefined evd = not (EvMap.is_empty evd.undf_evars) let evars_reset_evd ?(with_conv_pbs=false) ?(with_univs=true) evd d = let conv_pbs = if with_conv_pbs then evd.conv_pbs else d.conv_pbs in let last_mods = if with_conv_pbs then evd.last_mods else d.last_mods in let universes = if not with_univs then evd.universes else union_evar_universe_context evd.universes d.universes in { evd with metas = d.metas; last_mods; conv_pbs; universes } let merge_universe_context evd uctx' = { evd with universes = union_evar_universe_context evd.universes uctx' } let set_universe_context evd uctx' = { evd with universes = uctx' } let add_conv_pb ?(tail=false) pb d = if tail then {d with conv_pbs = d.conv_pbs @ [pb]} else {d with conv_pbs = pb::d.conv_pbs} let evar_source evk d = (find d evk).evar_source let evar_ident evk evd = EvNames.ident evk evd.evar_names let evar_key id evd = EvNames.key id evd.evar_names let define_aux def undef evk body = let oldinfo = try EvMap.find evk undef with Not_found -> if EvMap.mem evk def then anomaly ~label:"Evd.define" (Pp.str "cannot define an evar twice") else anomaly ~label:"Evd.define" (Pp.str "cannot define undeclared evar") in let () = assert (oldinfo.evar_body == Evar_empty) in let newinfo = { oldinfo with evar_body = Evar_defined body } in EvMap.add evk newinfo def, EvMap.remove evk undef (* define the existential of section path sp as the constr body *) let define evk body evd = let (defn_evars, undf_evars) = define_aux evd.defn_evars evd.undf_evars evk body in let last_mods = match evd.conv_pbs with | [] -> evd.last_mods | _ -> Evar.Set.add evk evd.last_mods in let evar_names = EvNames.remove_name_defined evk evd.evar_names in { evd with defn_evars; undf_evars; last_mods; evar_names } let evar_declare hyps evk ty ?(src=(Loc.ghost,Evar_kinds.InternalHole)) ?(filter=Filter.identity) ?candidates ?(store=Store.empty) ?(naming=Misctypes.IntroAnonymous) evd = let () = match Filter.repr filter with | None -> () | Some filter -> assert (Int.equal (List.length filter) (List.length (named_context_of_val hyps))) in let evar_info = { evar_hyps = hyps; evar_concl = ty; evar_body = Evar_empty; evar_filter = filter; evar_source = src; evar_candidates = candidates; evar_extra = store; } in let evar_names = EvNames.add_name_newly_undefined naming evk evar_info evd.evar_names in { evd with undf_evars = EvMap.add evk evar_info evd.undf_evars; evar_names } let restrict evk evk' filter ?candidates evd = let evar_info = EvMap.find evk evd.undf_evars in let evar_info' = { evar_info with evar_filter = filter; evar_candidates = candidates; evar_extra = Store.empty } in let evar_names = EvNames.reassign_name_defined evk evk' evd.evar_names in let ctxt = Filter.filter_list filter (evar_context evar_info) in let id_inst = Array.map_of_list (fun (id,_,_) -> mkVar id) ctxt in let body = mkEvar(evk',id_inst) in let (defn_evars, undf_evars) = define_aux evd.defn_evars evd.undf_evars evk body in { evd with undf_evars = EvMap.add evk' evar_info' undf_evars; defn_evars; evar_names } let downcast evk ccl evd = let evar_info = EvMap.find evk evd.undf_evars in let evar_info' = { evar_info with evar_concl = ccl } in { evd with undf_evars = EvMap.add evk evar_info' evd.undf_evars } (* extracts conversion problems that satisfy predicate p *) (* Note: conv_pbs not satisying p are stored back in reverse order *) let extract_conv_pbs evd p = let (pbs,pbs1) = List.fold_left (fun (pbs,pbs1) pb -> if p pb then (pb::pbs,pbs1) else (pbs,pb::pbs1)) ([],[]) evd.conv_pbs in {evd with conv_pbs = pbs1; last_mods = Evar.Set.empty}, pbs let extract_changed_conv_pbs evd p = extract_conv_pbs evd (fun pb -> p evd.last_mods pb) let extract_all_conv_pbs evd = extract_conv_pbs evd (fun _ -> true) let loc_of_conv_pb evd (pbty,env,t1,t2) = match kind_of_term (fst (decompose_app t1)) with | Evar (evk1,_) -> fst (evar_source evk1 evd) | _ -> match kind_of_term (fst (decompose_app t2)) with | Evar (evk2,_) -> fst (evar_source evk2 evd) | _ -> Loc.ghost (** The following functions return the set of evars immediately contained in the object *) (* excluding defined evars *) let evar_list c = let rec evrec acc c = match kind_of_term c with | Evar (evk, _ as ev) -> ev :: acc | _ -> fold_constr evrec acc c in evrec [] c let evars_of_term c = let rec evrec acc c = match kind_of_term c with | Evar (n, l) -> Evar.Set.add n (Array.fold_left evrec acc l) | _ -> fold_constr evrec acc c in evrec Evar.Set.empty c let evars_of_named_context nc = List.fold_right (fun (_, b, t) s -> Option.fold_left (fun s t -> Evar.Set.union s (evars_of_term t)) (Evar.Set.union s (evars_of_term t)) b) nc Evar.Set.empty let evars_of_filtered_evar_info evi = Evar.Set.union (evars_of_term evi.evar_concl) (Evar.Set.union (match evi.evar_body with | Evar_empty -> Evar.Set.empty | Evar_defined b -> evars_of_term b) (evars_of_named_context (evar_filtered_context evi))) (**********************************************************) (* Sort variables *) type rigid = | UnivRigid | UnivFlexible of bool (** Is substitution by an algebraic ok? *) let univ_rigid = UnivRigid let univ_flexible = UnivFlexible false let univ_flexible_alg = UnivFlexible true let evar_universe_context d = d.universes let universe_context_set d = d.universes.uctx_local let pr_uctx_level uctx = let map, map_rev = uctx.uctx_names in fun l -> try str(Univ.LMap.find l map_rev) with Not_found -> Universes.pr_with_global_universes l let universe_context ?names evd = match names with | None -> [], Univ.ContextSet.to_context evd.universes.uctx_local | Some pl -> let levels = Univ.ContextSet.levels evd.universes.uctx_local in let newinst, map, left = List.fold_right (fun (loc,id) (newinst, map, acc) -> let l = try UNameMap.find (Id.to_string id) (fst evd.universes.uctx_names) with Not_found -> user_err_loc (loc, "universe_context", str"Universe " ++ pr_id id ++ str" is not bound anymore.") in (l :: newinst, (id, l) :: map, Univ.LSet.remove l acc)) pl ([], [], levels) in if not (Univ.LSet.is_empty left) then let n = Univ.LSet.cardinal left in errorlabstrm "universe_context" (str(CString.plural n "Universe") ++ spc () ++ Univ.LSet.pr (pr_uctx_level evd.universes) left ++ spc () ++ str (CString.conjugate_verb_to_be n) ++ str" unbound.") else let inst = Univ.Instance.of_array (Array.of_list newinst) in let ctx = Univ.UContext.make (inst, Univ.ContextSet.constraints evd.universes.uctx_local) in map, ctx let restrict_universe_context evd vars = let uctx = evd.universes in let uctx' = Universes.restrict_universe_context uctx.uctx_local vars in { evd with universes = { uctx with uctx_local = uctx' } } let universe_subst evd = evd.universes.uctx_univ_variables let merge_uctx sideff rigid uctx ctx' = let open Univ in let levels = ContextSet.levels ctx' in let uctx = if sideff then uctx else match rigid with | UnivRigid -> uctx | UnivFlexible b -> let fold u accu = if LMap.mem u accu then accu else LMap.add u None accu in let uvars' = LSet.fold fold levels uctx.uctx_univ_variables in if b then { uctx with uctx_univ_variables = uvars'; uctx_univ_algebraic = LSet.union uctx.uctx_univ_algebraic levels } else { uctx with uctx_univ_variables = uvars' } in let uctx_local = if sideff then uctx.uctx_local else ContextSet.append ctx' uctx.uctx_local in let declare g = LSet.fold (fun u g -> try Univ.add_universe u false g with Univ.AlreadyDeclared when sideff -> g) levels g in let initial = declare uctx.uctx_initial_universes in let univs = declare uctx.uctx_universes in let uctx_universes = merge_constraints (ContextSet.constraints ctx') univs in { uctx with uctx_local; uctx_universes; uctx_initial_universes = initial } let merge_context_set ?(sideff=false) rigid evd ctx' = {evd with universes = merge_uctx sideff rigid evd.universes ctx'} let merge_uctx_subst uctx s = { uctx with uctx_univ_variables = Univ.LMap.subst_union uctx.uctx_univ_variables s } let merge_universe_subst evd subst = {evd with universes = merge_uctx_subst evd.universes subst } let with_context_set rigid d (a, ctx) = (merge_context_set rigid d ctx, a) let emit_universe_side_effects eff u = let uctxs = Safe_typing.universes_of_private eff in List.fold_left (merge_uctx true univ_rigid) u uctxs let uctx_new_univ_variable rigid name predicative ({ uctx_local = ctx; uctx_univ_variables = uvars; uctx_univ_algebraic = avars} as uctx) = let u = Universes.new_univ_level (Global.current_dirpath ()) in let ctx' = Univ.ContextSet.add_universe u ctx in let uctx', pred = match rigid with | UnivRigid -> uctx, true | UnivFlexible b -> let uvars' = Univ.LMap.add u None uvars in if b then {uctx with uctx_univ_variables = uvars'; uctx_univ_algebraic = Univ.LSet.add u avars}, false else {uctx with uctx_univ_variables = uvars'}, false in let names = match name with | Some n -> add_uctx_names n u uctx.uctx_names | None -> uctx.uctx_names in let initial = Univ.add_universe u false uctx.uctx_initial_universes in let uctx' = {uctx' with uctx_names = names; uctx_local = ctx'; uctx_universes = Univ.add_universe u false uctx.uctx_universes; uctx_initial_universes = initial} in uctx', u let new_univ_level_variable ?name ?(predicative=true) rigid evd = let uctx', u = uctx_new_univ_variable rigid name predicative evd.universes in ({evd with universes = uctx'}, u) let new_univ_variable ?name ?(predicative=true) rigid evd = let uctx', u = uctx_new_univ_variable rigid name predicative evd.universes in ({evd with universes = uctx'}, Univ.Universe.make u) let new_sort_variable ?name ?(predicative=true) rigid d = let (d', u) = new_univ_variable rigid ?name ~predicative d in (d', Type u) let add_global_univ d u = let uctx = d.universes in let initial = Univ.add_universe u true uctx.uctx_initial_universes in let univs = Univ.add_universe u true uctx.uctx_universes in { d with universes = { uctx with uctx_local = Univ.ContextSet.add_universe u uctx.uctx_local; uctx_initial_universes = initial; uctx_universes = univs } } let make_flexible_variable evd b u = let {uctx_univ_variables = uvars; uctx_univ_algebraic = avars} as ctx = evd.universes in let uvars' = Univ.LMap.add u None uvars in let avars' = if b then let uu = Univ.Universe.make u in let substu_not_alg u' v = Option.cata (fun vu -> Univ.Universe.equal uu vu && not (Univ.LSet.mem u' avars)) false v in if not (Univ.LMap.exists substu_not_alg uvars) then Univ.LSet.add u avars else avars else avars in {evd with universes = {ctx with uctx_univ_variables = uvars'; uctx_univ_algebraic = avars'}} let make_evar_universe_context e l = let uctx = evar_universe_context_from e in match l with | None -> uctx | Some us -> List.fold_left (fun uctx (loc,id) -> fst (uctx_new_univ_variable univ_rigid (Some (Id.to_string id)) true uctx)) uctx us (****************************************) (* Operations on constants *) (****************************************) let fresh_sort_in_family ?(rigid=univ_flexible) env evd s = with_context_set rigid evd (Universes.fresh_sort_in_family env s) let fresh_constant_instance env evd c = with_context_set univ_flexible evd (Universes.fresh_constant_instance env c) let fresh_inductive_instance env evd i = with_context_set univ_flexible evd (Universes.fresh_inductive_instance env i) let fresh_constructor_instance env evd c = with_context_set univ_flexible evd (Universes.fresh_constructor_instance env c) let fresh_global ?(rigid=univ_flexible) ?names env evd gr = with_context_set rigid evd (Universes.fresh_global_instance ?names env gr) let whd_sort_variable evd t = t let is_sort_variable evd s = match s with | Type u -> (match Univ.universe_level u with | Some l as x -> let uctx = evd.universes in if Univ.LSet.mem l (Univ.ContextSet.levels uctx.uctx_local) then x else None | None -> None) | _ -> None let is_flexible_level evd l = let uctx = evd.universes in Univ.LMap.mem l uctx.uctx_univ_variables let is_eq_sort s1 s2 = if Sorts.equal s1 s2 then None else let u1 = univ_of_sort s1 and u2 = univ_of_sort s2 in if Univ.Universe.equal u1 u2 then None else Some (u1, u2) let normalize_universe evd = let vars = ref evd.universes.uctx_univ_variables in let normalize = Universes.normalize_universe_opt_subst vars in normalize let normalize_universe_instance evd l = let vars = ref evd.universes.uctx_univ_variables in let normalize = Univ.level_subst_of (Universes.normalize_univ_variable_opt_subst vars) in Univ.Instance.subst_fn normalize l let normalize_sort evars s = match s with | Prop _ -> s | Type u -> let u' = normalize_universe evars u in if u' == u then s else Type u' (* FIXME inefficient *) let set_eq_sort env d s1 s2 = let s1 = normalize_sort d s1 and s2 = normalize_sort d s2 in match is_eq_sort s1 s2 with | None -> d | Some (u1, u2) -> if not (type_in_type env) then add_universe_constraints d (Universes.Constraints.singleton (u1,Universes.UEq,u2)) else d let has_lub evd u1 u2 = (* let normalize = Universes.normalize_universe_opt_subst (ref univs.uctx_univ_variables) in *) (* (\* let dref, norm = memo_normalize_universe d in *\) *) (* let u1 = normalize u1 and u2 = normalize u2 in *) if Univ.Universe.equal u1 u2 then evd else add_universe_constraints evd (Universes.Constraints.singleton (u1,Universes.ULub,u2)) let set_eq_level d u1 u2 = add_constraints d (Univ.enforce_eq_level u1 u2 Univ.Constraint.empty) let set_leq_level d u1 u2 = add_constraints d (Univ.enforce_leq_level u1 u2 Univ.Constraint.empty) let set_eq_instances ?(flex=false) d u1 u2 = add_universe_constraints d (Universes.enforce_eq_instances_univs flex u1 u2 Universes.Constraints.empty) let set_leq_sort env evd s1 s2 = let s1 = normalize_sort evd s1 and s2 = normalize_sort evd s2 in match is_eq_sort s1 s2 with | None -> evd | Some (u1, u2) -> (* if Univ.is_type0_univ u2 then *) (* if Univ.is_small_univ u1 then evd *) (* else raise (Univ.UniverseInconsistency (Univ.Le, u1, u2, [])) *) (* else if Univ.is_type0m_univ u2 then *) (* raise (Univ.UniverseInconsistency (Univ.Le, u1, u2, [])) *) (* else *) if not (type_in_type env) then add_universe_constraints evd (Universes.Constraints.singleton (u1,Universes.ULe,u2)) else evd let check_eq evd s s' = Univ.check_eq evd.universes.uctx_universes s s' let check_leq evd s s' = Univ.check_leq evd.universes.uctx_universes s s' let subst_univs_context_with_def def usubst (ctx, cst) = (Univ.LSet.diff ctx def, Univ.subst_univs_constraints usubst cst) let normalize_evar_universe_context_variables uctx = let normalized_variables, undef, def, subst = Universes.normalize_univ_variables uctx.uctx_univ_variables in let ctx_local = subst_univs_context_with_def def (Univ.make_subst subst) uctx.uctx_local in let ctx_local', univs = Universes.refresh_constraints uctx.uctx_initial_universes ctx_local in subst, { uctx with uctx_local = ctx_local'; uctx_univ_variables = normalized_variables; uctx_universes = univs } (* let normvarsconstrkey = Profile.declare_profile "normalize_evar_universe_context_variables";; *) (* let normalize_evar_universe_context_variables = *) (* Profile.profile1 normvarsconstrkey normalize_evar_universe_context_variables;; *) let abstract_undefined_variables uctx = let vars' = Univ.LMap.fold (fun u v acc -> if v == None then Univ.LSet.remove u acc else acc) uctx.uctx_univ_variables uctx.uctx_univ_algebraic in { uctx with uctx_local = Univ.ContextSet.empty; uctx_univ_algebraic = vars' } let fix_undefined_variables ({ universes = uctx } as evm) = let algs', vars' = Univ.LMap.fold (fun u v (algs, vars as acc) -> if v == None then (Univ.LSet.remove u algs, Univ.LMap.remove u vars) else acc) uctx.uctx_univ_variables (uctx.uctx_univ_algebraic, uctx.uctx_univ_variables) in {evm with universes = { uctx with uctx_univ_variables = vars'; uctx_univ_algebraic = algs' } } let refresh_undefined_univ_variables uctx = let subst, ctx' = Universes.fresh_universe_context_set_instance uctx.uctx_local in let alg = Univ.LSet.fold (fun u acc -> Univ.LSet.add (Univ.subst_univs_level_level subst u) acc) uctx.uctx_univ_algebraic Univ.LSet.empty in let vars = Univ.LMap.fold (fun u v acc -> Univ.LMap.add (Univ.subst_univs_level_level subst u) (Option.map (Univ.subst_univs_level_universe subst) v) acc) uctx.uctx_univ_variables Univ.LMap.empty in let declare g = Univ.LSet.fold (fun u g -> Univ.add_universe u false g) (Univ.ContextSet.levels ctx') g in let initial = declare uctx.uctx_initial_universes in let univs = declare Univ.initial_universes in let uctx' = {uctx_names = uctx.uctx_names; uctx_local = ctx'; uctx_univ_variables = vars; uctx_univ_algebraic = alg; uctx_universes = univs; uctx_initial_universes = initial } in uctx', subst let refresh_undefined_universes evd = let uctx', subst = refresh_undefined_univ_variables evd.universes in let evd' = cmap (subst_univs_level_constr subst) {evd with universes = uctx'} in evd', subst let normalize_evar_universe_context uctx = let rec fixpoint uctx = let ((vars',algs'), us') = Universes.normalize_context_set uctx.uctx_local uctx.uctx_univ_variables uctx.uctx_univ_algebraic in if Univ.ContextSet.equal us' uctx.uctx_local then uctx else let us', universes = Universes.refresh_constraints uctx.uctx_initial_universes us' in let uctx' = { uctx_names = uctx.uctx_names; uctx_local = us'; uctx_univ_variables = vars'; uctx_univ_algebraic = algs'; uctx_universes = universes; uctx_initial_universes = uctx.uctx_initial_universes } in fixpoint uctx' in fixpoint uctx let nf_univ_variables evd = let subst, uctx' = normalize_evar_universe_context_variables evd.universes in let evd' = {evd with universes = uctx'} in evd', subst let nf_constraints evd = let subst, uctx' = normalize_evar_universe_context_variables evd.universes in let uctx' = normalize_evar_universe_context uctx' in {evd with universes = uctx'} let nf_constraints = if Flags.profile then let nfconstrkey = Profile.declare_profile "nf_constraints" in Profile.profile1 nfconstrkey nf_constraints else nf_constraints let universe_of_name evd s = UNameMap.find s (fst evd.universes.uctx_names) let add_universe_name evd s l = let names' = add_uctx_names s l evd.universes.uctx_names in {evd with universes = {evd.universes with uctx_names = names'}} let universes evd = evd.universes.uctx_universes let update_sigma_env evd env = let univs = Environ.universes env in let eunivs = { evd.universes with uctx_initial_universes = univs; uctx_universes = univs } in let eunivs = merge_uctx true univ_rigid eunivs eunivs.uctx_local in { evd with universes = eunivs } (* Conversion w.r.t. an evar map and its local universes. *) let test_conversion_gen env evd pb t u = match pb with | Reduction.CONV -> Reduction.trans_conv_universes full_transparent_state ~evars:(existential_opt_value evd) env evd.universes.uctx_universes t u | Reduction.CUMUL -> Reduction.trans_conv_leq_universes full_transparent_state ~evars:(existential_opt_value evd) env evd.universes.uctx_universes t u let test_conversion env d pb t u = try test_conversion_gen env d pb t u; true with _ -> false let eq_constr_univs evd t u = let b, c = Universes.eq_constr_univs_infer evd.universes.uctx_universes t u in if b then try let evd' = add_universe_constraints evd c in evd', b with Univ.UniverseInconsistency _ | UniversesDiffer -> evd, false else evd, b let e_eq_constr_univs evdref t u = let evd, b = eq_constr_univs !evdref t u in evdref := evd; b (**********************************************************) (* Side effects *) let emit_side_effects eff evd = { evd with effects = Safe_typing.concat_private eff evd.effects; universes = emit_universe_side_effects eff evd.universes } let drop_side_effects evd = { evd with effects = Safe_typing.empty_private_constants; } let eval_side_effects evd = evd.effects (* Future goals *) let declare_future_goal evk evd = { evd with future_goals = evk::evd.future_goals } let declare_principal_goal evk evd = match evd.principal_future_goal with | None -> { evd with future_goals = evk::evd.future_goals; principal_future_goal=Some evk; } | Some _ -> Errors.error "Only one main subgoal per instantiation." let future_goals evd = evd.future_goals let principal_future_goal evd = evd.principal_future_goal let reset_future_goals evd = { evd with future_goals = [] ; principal_future_goal=None } let restore_future_goals evd gls pgl = { evd with future_goals = gls ; principal_future_goal = pgl } (**********************************************************) (* Accessing metas *) (** We use this function to overcome OCaml compiler limitations and to prevent the use of costly in-place modifications. *) let set_metas evd metas = { defn_evars = evd.defn_evars; undf_evars = evd.undf_evars; universes = evd.universes; conv_pbs = evd.conv_pbs; last_mods = evd.last_mods; metas; effects = evd.effects; evar_names = evd.evar_names; future_goals = evd.future_goals; principal_future_goal = evd.principal_future_goal; extras = evd.extras; } let meta_list evd = metamap_to_list evd.metas let undefined_metas evd = let filter = function | (n,Clval(_,_,typ)) -> None | (n,Cltyp (_,typ)) -> Some n in let m = List.map_filter filter (meta_list evd) in List.sort Int.compare m let map_metas_fvalue f evd = let map = function | Clval(id,(c,s),typ) -> Clval(id,(mk_freelisted (f c.rebus),s),typ) | x -> x in set_metas evd (Metamap.smartmap map evd.metas) let map_metas f evd = let map cl = map_clb f cl in set_metas evd (Metamap.smartmap map evd.metas) let meta_opt_fvalue evd mv = match Metamap.find mv evd.metas with | Clval(_,b,_) -> Some b | Cltyp _ -> None let meta_defined evd mv = match Metamap.find mv evd.metas with | Clval _ -> true | Cltyp _ -> false let try_meta_fvalue evd mv = match Metamap.find mv evd.metas with | Clval(_,b,_) -> b | Cltyp _ -> raise Not_found let meta_fvalue evd mv = try try_meta_fvalue evd mv with Not_found -> anomaly ~label:"meta_fvalue" (Pp.str "meta has no value") let meta_value evd mv = (fst (try_meta_fvalue evd mv)).rebus let meta_ftype evd mv = match Metamap.find mv evd.metas with | Cltyp (_,b) -> b | Clval(_,_,b) -> b let meta_type evd mv = (meta_ftype evd mv).rebus let meta_declare mv v ?(name=Anonymous) evd = let metas = Metamap.add mv (Cltyp(name,mk_freelisted v)) evd.metas in set_metas evd metas let meta_assign mv (v, pb) evd = let modify _ = function | Cltyp (na, ty) -> Clval (na, (mk_freelisted v, pb), ty) | _ -> anomaly ~label:"meta_assign" (Pp.str "already defined") in let metas = Metamap.modify mv modify evd.metas in set_metas evd metas let meta_reassign mv (v, pb) evd = let modify _ = function | Clval(na, _, ty) -> Clval (na, (mk_freelisted v, pb), ty) | _ -> anomaly ~label:"meta_reassign" (Pp.str "not yet defined") in let metas = Metamap.modify mv modify evd.metas in set_metas evd metas (* If the meta is defined then forget its name *) let meta_name evd mv = try fst (clb_name (Metamap.find mv evd.metas)) with Not_found -> Anonymous let explain_no_such_bound_variable evd id = let mvl = List.rev (Metamap.fold (fun n clb l -> let na = fst (clb_name clb) in if na != Anonymous then out_name na :: l else l) evd.metas []) in errorlabstrm "Evd.meta_with_name" (str"No such bound variable " ++ pr_id id ++ (if mvl == [] then str " (no bound variables at all in the expression)." else (str" (possible name" ++ str (if List.length mvl == 1 then " is: " else "s are: ") ++ pr_enum pr_id mvl ++ str")."))) let meta_with_name evd id = let na = Name id in let (mvl,mvnodef) = Metamap.fold (fun n clb (l1,l2 as l) -> let (na',def) = clb_name clb in if Name.equal na na' then if def then (n::l1,l2) else (n::l1,n::l2) else l) evd.metas ([],[]) in match mvnodef, mvl with | _,[] -> explain_no_such_bound_variable evd id | ([n],_|_,[n]) -> n | _ -> errorlabstrm "Evd.meta_with_name" (str "Binder name \"" ++ pr_id id ++ strbrk "\" occurs more than once in clause.") let clear_metas evd = {evd with metas = Metamap.empty} let meta_merge ?(with_univs = true) evd1 evd2 = let metas = Metamap.fold Metamap.add evd1.metas evd2.metas in let universes = if with_univs then union_evar_universe_context evd2.universes evd1.universes else evd2.universes in {evd2 with universes; metas; } type metabinding = metavariable * constr * instance_status let retract_coercible_metas evd = let mc = ref [] in let map n v = match v with | Clval (na, (b, (Conv, CoerceToType as s)), typ) -> let () = mc := (n, b.rebus, s) :: !mc in Cltyp (na, typ) | v -> v in let metas = Metamap.smartmapi map evd.metas in !mc, set_metas evd metas let subst_defined_metas_evars (bl,el) c = let rec substrec c = match kind_of_term c with | Meta i -> let select (j,_,_) = Int.equal i j in substrec (pi2 (List.find select bl)) | Evar (evk,args) -> let select (_,(evk',args'),_) = Evar.equal evk evk' && Array.equal Constr.equal args args' in (try substrec (pi3 (List.find select el)) with Not_found -> map_constr substrec c) | _ -> map_constr substrec c in try Some (substrec c) with Not_found -> None let evar_source_of_meta mv evd = match meta_name evd mv with | Anonymous -> (Loc.ghost,Evar_kinds.GoalEvar) | Name id -> (Loc.ghost,Evar_kinds.VarInstance id) let dependent_evar_ident ev evd = let evi = find evd ev in match evi.evar_source with | (_,Evar_kinds.VarInstance id) -> id | _ -> anomaly (str "Not an evar resulting of a dependent binding") (**********************************************************) (* Extra data *) let get_extra_data evd = evd.extras let set_extra_data extras evd = { evd with extras } (*******************************************************************) type pending = (* before: *) evar_map * (* after: *) evar_map type pending_constr = pending * constr type open_constr = evar_map * constr (*******************************************************************) (* The type constructor ['a sigma] adds an evar map to an object of type ['a] *) type 'a sigma = { it : 'a ; sigma : evar_map } let sig_it x = x.it let sig_sig x = x.sigma let on_sig s f = let sigma', v = f s.sigma in { s with sigma = sigma' }, v (*******************************************************************) (* The state monad with state an evar map. *) module MonadR = Monad.Make (struct type +'a t = evar_map -> evar_map * 'a let return a = fun s -> (s,a) let (>>=) x f = fun s -> let (s',a) = x s in f a s' let (>>) x y = fun s -> let (s',()) = x s in y s' let map f x = fun s -> on_snd f (x s) end) module Monad = Monad.Make (struct type +'a t = evar_map -> 'a * evar_map let return a = fun s -> (a,s) let (>>=) x f = fun s -> let (a,s') = x s in f a s' let (>>) x y = fun s -> let ((),s') = x s in y s' let map f x = fun s -> on_fst f (x s) end) (**********************************************************) (* Failure explanation *) type unsolvability_explanation = SeveralInstancesFound of int (**********************************************************) (* Pretty-printing *) let pr_evar_suggested_name evk sigma = let base_id evk' evi = match evar_ident evk' sigma with | Some id -> id | None -> match evi.evar_source with | _,Evar_kinds.ImplicitArg (c,(n,Some id),b) -> id | _,Evar_kinds.VarInstance id -> id | _,Evar_kinds.GoalEvar -> Id.of_string "Goal" | _ -> let env = reset_with_named_context evi.evar_hyps (Global.env()) in Namegen.id_of_name_using_hdchar env evi.evar_concl Anonymous in let names = EvMap.mapi base_id sigma.undf_evars in let id = EvMap.find evk names in let fold evk' id' (seen, n) = if seen then (seen, n) else if Evar.equal evk evk' then (true, n) else if Id.equal id id' then (seen, succ n) else (seen, n) in let (_, n) = EvMap.fold fold names (false, 0) in if n = 0 then id else Nameops.add_suffix id (string_of_int (pred n)) let pr_existential_key sigma evk = match evar_ident evk sigma with | None -> str "?" ++ pr_id (pr_evar_suggested_name evk sigma) | Some id -> str "?" ++ pr_id id let pr_instance_status (sc,typ) = begin match sc with | IsSubType -> str " [or a subtype of it]" | IsSuperType -> str " [or a supertype of it]" | Conv -> mt () end ++ begin match typ with | CoerceToType -> str " [up to coercion]" | TypeNotProcessed -> mt () | TypeProcessed -> str " [type is checked]" end let pr_meta_map mmap = let pr_name = function Name id -> str"[" ++ pr_id id ++ str"]" | _ -> mt() in let pr_meta_binding = function | (mv,Cltyp (na,b)) -> hov 0 (pr_meta mv ++ pr_name na ++ str " : " ++ print_constr b.rebus ++ fnl ()) | (mv,Clval(na,(b,s),t)) -> hov 0 (pr_meta mv ++ pr_name na ++ str " := " ++ print_constr b.rebus ++ str " : " ++ print_constr t.rebus ++ spc () ++ pr_instance_status s ++ fnl ()) in prlist pr_meta_binding (metamap_to_list mmap) let pr_decl ((id,b,_),ok) = match b with | None -> if ok then pr_id id else (str "{" ++ pr_id id ++ str "}") | Some c -> str (if ok then "(" else "{") ++ pr_id id ++ str ":=" ++ print_constr c ++ str (if ok then ")" else "}") let rec pr_evar_source = function | Evar_kinds.QuestionMark _ -> str "underscore" | Evar_kinds.CasesType false -> str "pattern-matching return predicate" | Evar_kinds.CasesType true -> str "subterm of pattern-matching return predicate" | Evar_kinds.BinderType (Name id) -> str "type of " ++ Nameops.pr_id id | Evar_kinds.BinderType Anonymous -> str "type of anonymous binder" | Evar_kinds.ImplicitArg (c,(n,ido),b) -> let id = Option.get ido in str "parameter " ++ pr_id id ++ spc () ++ str "of" ++ spc () ++ print_constr (printable_constr_of_global c) | Evar_kinds.InternalHole -> str "internal placeholder" | Evar_kinds.TomatchTypeParameter (ind,n) -> pr_nth n ++ str " argument of type " ++ print_constr (mkInd ind) | Evar_kinds.GoalEvar -> str "goal evar" | Evar_kinds.ImpossibleCase -> str "type of impossible pattern-matching clause" | Evar_kinds.MatchingVar _ -> str "matching variable" | Evar_kinds.VarInstance id -> str "instance of " ++ pr_id id | Evar_kinds.SubEvar evk -> str "subterm of " ++ str (string_of_existential evk) let pr_evar_info evi = let phyps = try let decls = match Filter.repr (evar_filter evi) with | None -> List.map (fun c -> (c, true)) (evar_context evi) | Some filter -> List.combine (evar_context evi) filter in prlist_with_sep spc pr_decl (List.rev decls) with Invalid_argument _ -> str "Ill-formed filtered context" in let pty = print_constr evi.evar_concl in let pb = match evi.evar_body with | Evar_empty -> mt () | Evar_defined c -> spc() ++ str"=> " ++ print_constr c in let candidates = match evi.evar_body, evi.evar_candidates with | Evar_empty, Some l -> spc () ++ str "{" ++ prlist_with_sep (fun () -> str "|") print_constr l ++ str "}" | _ -> mt () in let src = str "(" ++ pr_evar_source (snd evi.evar_source) ++ str ")" in hov 2 (str"[" ++ phyps ++ spc () ++ str"|- " ++ pty ++ pb ++ str"]" ++ candidates ++ spc() ++ src) let compute_evar_dependency_graph (sigma : evar_map) = (* Compute the map binding ev to the evars whose body depends on ev *) let fold evk evi acc = let fold_ev evk' acc = let tab = try EvMap.find evk' acc with Not_found -> Evar.Set.empty in EvMap.add evk' (Evar.Set.add evk tab) acc in match evar_body evi with | Evar_empty -> assert false | Evar_defined c -> Evar.Set.fold fold_ev (evars_of_term c) acc in EvMap.fold fold sigma.defn_evars EvMap.empty let evar_dependency_closure n sigma = (** Create the DAG of depth [n] representing the recursive dependencies of undefined evars. *) let graph = compute_evar_dependency_graph sigma in let rec aux n curr accu = if Int.equal n 0 then Evar.Set.union curr accu else let fold evk accu = try let deps = EvMap.find evk graph in Evar.Set.union deps accu with Not_found -> accu in (** Consider only the newly added evars *) let ncurr = Evar.Set.fold fold curr Evar.Set.empty in (** Merge the others *) let accu = Evar.Set.union curr accu in aux (n - 1) ncurr accu in let undef = EvMap.domain (undefined_map sigma) in aux n undef Evar.Set.empty let evar_dependency_closure n sigma = let deps = evar_dependency_closure n sigma in let map = EvMap.bind (fun ev -> find sigma ev) deps in EvMap.bindings map let has_no_evar sigma = EvMap.is_empty sigma.defn_evars && EvMap.is_empty sigma.undf_evars let pr_evd_level evd = pr_uctx_level evd.universes let pr_evar_universe_context ctx = let prl = pr_uctx_level ctx in if is_empty_evar_universe_context ctx then mt () else (str"UNIVERSES:"++brk(0,1)++ h 0 (Univ.pr_universe_context_set prl ctx.uctx_local) ++ fnl () ++ str"ALGEBRAIC UNIVERSES:"++brk(0,1)++ h 0 (Univ.LSet.pr prl ctx.uctx_univ_algebraic) ++ fnl() ++ str"UNDEFINED UNIVERSES:"++brk(0,1)++ h 0 (Universes.pr_universe_opt_subst ctx.uctx_univ_variables) ++ fnl()) let print_env_short env = let pr_body n = function | None -> pr_name n | Some b -> str "(" ++ pr_name n ++ str " := " ++ print_constr b ++ str ")" in let pr_named_decl (n, b, _) = pr_body (Name n) b in let pr_rel_decl (n, b, _) = pr_body n b in let nc = List.rev (named_context env) in let rc = List.rev (rel_context env) in str "[" ++ pr_sequence pr_named_decl nc ++ str "]" ++ spc () ++ str "[" ++ pr_sequence pr_rel_decl rc ++ str "]" let pr_evar_constraints pbs = let pr_evconstr (pbty, env, t1, t2) = print_env_short env ++ spc () ++ str "|-" ++ spc () ++ print_constr_env env t1 ++ spc () ++ str (match pbty with | Reduction.CONV -> "==" | Reduction.CUMUL -> "<=") ++ spc () ++ print_constr_env env t2 in prlist_with_sep fnl pr_evconstr pbs let pr_evar_map_gen with_univs pr_evars sigma = let { universes = uvs } = sigma in let evs = if has_no_evar sigma then mt () else pr_evars sigma ++ fnl () and svs = if with_univs then pr_evar_universe_context uvs else mt () and cstrs = if List.is_empty sigma.conv_pbs then mt () else str "CONSTRAINTS:" ++ brk (0, 1) ++ pr_evar_constraints sigma.conv_pbs ++ fnl () and metas = if Metamap.is_empty sigma.metas then mt () else str "METAS:" ++ brk (0, 1) ++ pr_meta_map sigma.metas in evs ++ svs ++ cstrs ++ metas let pr_evar_list sigma l = let pr (ev, evi) = h 0 (str (string_of_existential ev) ++ str "==" ++ pr_evar_info evi ++ (if evi.evar_body == Evar_empty then str " {" ++ pr_existential_key sigma ev ++ str "}" else mt ())) in h 0 (prlist_with_sep fnl pr l) let pr_evar_by_depth depth sigma = match depth with | None -> (* Print all evars *) str"EVARS:"++brk(0,1)++pr_evar_list sigma (to_list sigma)++fnl() | Some n -> (* Print all evars *) str"UNDEFINED EVARS:"++ (if Int.equal n 0 then mt() else str" (+level "++int n++str" closure):")++ brk(0,1)++ pr_evar_list sigma (evar_dependency_closure n sigma)++fnl() let pr_evar_by_filter filter sigma = let defined = Evar.Map.filter filter sigma.defn_evars in let undefined = Evar.Map.filter filter sigma.undf_evars in let prdef = if Evar.Map.is_empty defined then mt () else str "DEFINED EVARS:" ++ brk (0, 1) ++ pr_evar_list sigma (Evar.Map.bindings defined) in let prundef = if Evar.Map.is_empty undefined then mt () else str "UNDEFINED EVARS:" ++ brk (0, 1) ++ pr_evar_list sigma (Evar.Map.bindings undefined) in prdef ++ prundef let pr_evar_map ?(with_univs=true) depth sigma = pr_evar_map_gen with_univs (fun sigma -> pr_evar_by_depth depth sigma) sigma let pr_evar_map_filter ?(with_univs=true) filter sigma = pr_evar_map_gen with_univs (fun sigma -> pr_evar_by_filter filter sigma) sigma let pr_metaset metas = str "[" ++ pr_sequence pr_meta (Metaset.elements metas) ++ str "]"