summaryrefslogtreecommitdiff
path: root/pretyping/evarutil.ml
diff options
context:
space:
mode:
Diffstat (limited to 'pretyping/evarutil.ml')
-rw-r--r--pretyping/evarutil.ml140
1 files changed, 105 insertions, 35 deletions
diff --git a/pretyping/evarutil.ml b/pretyping/evarutil.ml
index 506cd03f..307c9886 100644
--- a/pretyping/evarutil.ml
+++ b/pretyping/evarutil.ml
@@ -6,7 +6,7 @@
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(* $Id: evarutil.ml 8759 2006-04-28 12:24:14Z herbelin $ *)
+(* $Id: evarutil.ml 9154 2006-09-20 17:18:18Z corbinea $ *)
open Util
open Pp
@@ -21,13 +21,6 @@ open Evd
open Reductionops
open Pretype_errors
-
-let rec filter_unique = function
- | [] -> []
- | x::l ->
- if List.mem x l then filter_unique (List.filter (fun y -> x<>y) l)
- else x::filter_unique l
-
(* Expanding existential variables (pretyping.ml) *)
(* 1- whd_ise fails if an existential is undefined *)
@@ -63,9 +56,9 @@ let jv_nf_evar = Pretype_errors.jv_nf_evar
let tj_nf_evar = Pretype_errors.tj_nf_evar
let nf_evar_info evc info =
- { evar_concl = Reductionops.nf_evar evc info.evar_concl;
- evar_hyps = map_named_val (Reductionops.nf_evar evc) info.evar_hyps;
- evar_body = info.evar_body}
+ { info with
+ evar_concl = Reductionops.nf_evar evc info.evar_concl;
+ evar_hyps = map_named_val (Reductionops.nf_evar evc) info.evar_hyps}
let nf_evars evm = Evd.fold (fun ev evi evm' -> Evd.add evm' ev (nf_evar_info evm evi))
evm Evd.empty
@@ -310,29 +303,45 @@ let is_defined_equation env evd (ev,inst) rhs =
* ?3 <-- ?1 no pb: env of ?3 is larger than ?1's
* ?1 <-- (list ?2) pb: ?2 may depend on x, but not ?1.
* What we do is that ?2 is defined by a new evar ?4 whose context will be
- * a prefix of ?2's env, included in ?1's env. *)
+ * a prefix of ?2's env, included in ?1's env.
+
+ Concretely, the assumptions are "env |- ev : T" and "Gamma |-
+ ev[hyps:=args]" for some Gamma whose de Bruijn context has length k.
+ We create "env' |- ev' : T" for some env' <= env and define ev:=ev'
+*)
-let do_restrict_hyps evd ev args =
+let do_restrict_hyps env k evd ev args =
let args = Array.to_list args in
let evi = Evd.find (evars_of !evd) ev in
- let env = evar_env evi in
let hyps = evar_context evi in
- let (sign,ncargs) = list_filter2 (fun _ a -> closed0 a) (hyps,args) in
+ let (hyps',ncargs) = list_filter2 (fun _ a -> closedn k a) (hyps,args) in
(* No care is taken in case the evar type uses vars filtered out!
- Is it important ? *)
- let nc =
- let env =
- Sign.fold_named_context push_named sign ~init:(reset_context env) in
- e_new_evar evd env ~src:(evar_source ev !evd) evi.evar_concl in
+ Assuming that the restriction comes from a well-typed Flex/Flex
+ unification problem (see real_clean), the type of the evar cannot
+ depend on variables that are not in the scope of the other evar,
+ since this other evar has the same type (up to unification).
+ Since moreover, the evar contexts uses names only, the
+ restriction raise no de Bruijn reallocation problem *)
+ let env' =
+ Sign.fold_named_context push_named hyps' ~init:(reset_context env) in
+ let nc = e_new_evar evd env' ~src:(evar_source ev !evd) evi.evar_concl in
evd := Evd.evar_define ev nc !evd;
let (evn,_) = destEvar nc in
mkEvar(evn,Array.of_list ncargs)
-
-let need_restriction isevars args = not (array_for_all closed0 args)
+let need_restriction k args = not (array_for_all (closedn k) args)
(* We try to instantiate the evar assuming the body won't depend
- * on arguments that are not Rels or Vars, or appearing several times.
+ * on arguments that are not Rels or Vars, or appearing several times
+ (i.e. we tackle only Miller-Pfenning patterns unification)
+
+ 1) Let a unification problem "env |- ev[hyps:=args] = rhs"
+ 2) We limit it to a patterns unification problem "env |- ev[subst] = rhs"
+ where only Rel's and Var's are relevant in subst
+ 3) We recur on rhs, "imitating" the term failing if some Rel/Var not in scope
+
+ Note: we don't assume rhs in normal form, it may fail while it would
+ have succeeded after some reductions
*)
(* Note: error_not_clean should not be an error: it simply means that the
* conversion test that lead to the faulty call to [real_clean] should return
@@ -341,36 +350,52 @@ let need_restriction isevars args = not (array_for_all closed0 args)
let real_clean env isevars ev evi args rhs =
let evd = ref isevars in
- let subst = List.map (fun (x,y) -> (y,mkVar x)) (filter_unique args) in
+ let subst = List.map (fun (x,y) -> (y,mkVar x)) (list_uniquize args) in
let rec subs rigid k t =
match kind_of_term t with
| Rel i ->
if i<=k then t
- else (try List.assoc (mkRel (i-k)) subst with Not_found -> t)
+ else
+ (* Flex/Rel problem: unifiable as a pattern iff Rel in ev scope *)
+ (try List.assoc (mkRel (i-k)) subst
+ with Not_found -> if rigid then raise Exit else t)
| Evar (ev,args) ->
if Evd.is_defined_evar !evd (ev,args) then
subs rigid k (existential_value (evars_of !evd) (ev,args))
else
+ (* Flex/Flex problem: restriction to a common scope *)
let args' = Array.map (subs false k) args in
- if need_restriction !evd args' then
- do_restrict_hyps evd ev args'
+ if need_restriction k args' then
+ do_restrict_hyps (reset_context env) k evd ev args'
else
mkEvar (ev,args')
| Var id ->
+ (* Flex/Var problem: unifiable as a pattern iff Var in scope of ev *)
(try List.assoc t subst
with Not_found ->
if
not rigid
+ (* I don't understand this line: vars from evar_context evi
+ are private (especially some of them are freshly
+ generated in push_rel_context_to_named_context). They
+ have a priori nothing to do with the vars in env. I
+ remove the test [HH 25/8/06]
+
or List.exists (fun (id',_,_) -> id=id') (evar_context evi)
+ *)
then t
- else
- error_not_clean env (evars_of !evd) ev rhs
- (evar_source ev !evd))
- | _ -> map_constr_with_binders succ (subs rigid) k t
+ else raise Exit)
+
+ | _ ->
+ (* Flex/Rigid problem (or assimilated if not normal): we "imitate" *)
+ map_constr_with_binders succ (subs rigid) k t
in
- let body = subs true 0 (nf_evar (evars_of isevars) rhs) in
- if not (closed0 body)
- then error_not_clean env (evars_of !evd) ev body (evar_source ev !evd);
+ let rhs = nf_evar (evars_of isevars) rhs in
+ let rhs = whd_beta rhs (* heuristic *) in
+ let body =
+ try subs true 0 rhs
+ with Exit ->
+ error_not_clean env (evars_of !evd) ev rhs (evar_source ev !evd) in
(!evd,body)
(* [evar_define] solves the problem lhs = rhs when lhs is an uninstantiated
@@ -464,6 +489,34 @@ let head_evar =
in
hrec
+(* Check if an applied evar "?X[args] l" is a Miller's pattern; note
+ that we don't care whether args itself contains Rel's or even Rel's
+ distinct from the ones in l *)
+
+let is_unification_pattern_evar (_,args) l =
+ let l' = Array.to_list args @ l in
+ List.for_all (fun a -> isRel a or isVar a) l' & list_distinct l'
+
+let is_unification_pattern f l =
+ match kind_of_term f with
+ | Meta _ -> array_for_all isRel l & array_distinct l
+ | Evar ev -> is_unification_pattern_evar ev (Array.to_list l)
+ | _ -> false
+
+(* From a unification problem "?X l1 = term1 l2" such that l1 is made
+ of distinct rel's, build "\x1...xn.(term1 l2)" (patterns unification) *)
+
+let solve_pattern_eqn env l1 c =
+ let c' = List.fold_right (fun a c ->
+ let c' = subst_term (lift 1 a) (lift 1 c) in
+ match kind_of_term a with
+ (* Rem: if [a] links to a let-in, do as if it were an assumption *)
+ | Rel n -> let (na,_,t) = lookup_rel n env in mkLambda (na,lift n t,c')
+ | Var id -> let (id,_,t) = lookup_named id env in mkNamedLambda id t c'
+ | _ -> assert false)
+ l1 c in
+ whd_eta c'
+
(* This code (i.e. solve_pb, etc.) takes a unification
* problem, and tries to solve it. If it solves it, then it removes
* all the conversion problems, and re-runs conversion on each one, in
@@ -550,11 +603,28 @@ let solve_simple_eqn conv_algo env isevars (pbty,(n1,args1 as ev1),t2) =
let (isevars,pbs) = get_conv_pbs isevars (status_changed lsp) in
List.fold_left
(fun (isevars,b as p) (pbty,t1,t2) ->
- if b then conv_algo env isevars pbty t1 t2 else p) (isevars,true)
+ if b then conv_algo env isevars pbty t1 t2 else p) (isevars,true)
pbs
with e when precatchable_exception e ->
(isevars,false)
+
+(* [check_evars] fails if some unresolved evar remains *)
+(* it assumes that the defined existentials have already been substituted *)
+
+let check_evars env initial_sigma isevars c =
+ let sigma = evars_of isevars in
+ let c = nf_evar sigma c in
+ let rec proc_rec c =
+ match kind_of_term c with
+ | Evar (ev,args) ->
+ assert (Evd.mem sigma ev);
+ if not (Evd.mem initial_sigma ev) then
+ let (loc,k) = evar_source ev isevars in
+ error_unsolvable_implicit loc env sigma k
+ | _ -> iter_constr proc_rec c
+ in proc_rec c
+
(* Operations on value/type constraints *)
type type_constraint_type = (int * int) option * constr