aboutsummaryrefslogtreecommitdiffhomepage
path: root/pretyping/evarutil.ml
diff options
context:
space:
mode:
Diffstat (limited to 'pretyping/evarutil.ml')
-rw-r--r--pretyping/evarutil.ml138
1 files changed, 83 insertions, 55 deletions
diff --git a/pretyping/evarutil.ml b/pretyping/evarutil.ml
index d2c05b913..5c7006dd0 100644
--- a/pretyping/evarutil.ml
+++ b/pretyping/evarutil.ml
@@ -422,8 +422,7 @@ let shrink_context env subst ty =
in
shrink_named subst [] rev_named_sign
-let extend_evar env evdref k (evk1,args1) c =
- let ty = get_type_of env !evdref c in
+let extend_evar env evdref k (evk1,args1) ty =
let overwrite_first v1 v2 =
let v = Array.copy v1 in
let n = Array.length v - Array.length v2 in
@@ -813,7 +812,20 @@ let filter_along f projs v =
* such that "hyps' |- ?e : T"
*)
-let restrict_hyps evd evk filter =
+exception IllTypedFilter
+
+let check_restricted_occur refine env filter constr =
+ let rec aux k filter c =
+ match kind_of_term c with
+ | Var id ->
+ let idx = list_try_find_i (fun i (id', _, _) -> if id' = id then i else raise (Failure "")) 0 env in
+ if not (List.nth filter idx)
+ then if refine then list_assign filter idx true else raise IllTypedFilter
+ else filter
+ | _ -> fold_constr_with_binders succ aux k filter c
+ in aux 0 filter constr
+
+let restrict_hyps ?(refine=false) evd evk filter =
(* What to do with dependencies?
Assume we have x:A, y:B(x), z:C(x,y) |- ?e:T(x,y,z) and restrict on y.
- If y is in a non-erasable position in C(x,y) (i.e. it is not below an
@@ -829,7 +841,8 @@ let restrict_hyps evd evk filter =
let oldfilter = evar_filter evi in
let filter,_ = List.fold_right (fun oldb (l,filter) ->
if oldb then List.hd filter::l,List.tl filter else (false::l,filter))
- oldfilter ([],List.rev filter) in
+ oldfilter ([], List.rev filter) in
+ let filter = check_restricted_occur refine (named_context env) filter evi.evar_concl in
(env,evar_source evk evd,filter,evi.evar_concl)
let do_restrict_hyps evd evk projs =
@@ -925,15 +938,19 @@ let solve_evar_evar_l2r f env evd (evk1,args1) (evk2,args2 as ev2) =
list_fold_map (instance_of_projection f env (mkEvar ev2)) evd proj1' in
let evd,evk1' = do_restrict_hyps evd evk1 proj1 in
Evd.define evk2 (mkEvar(evk1',Array.of_list args1')) evd
- with NotUnique ->
+ with NotUnique | IllTypedFilter ->
raise (CannotProject proj1)
let solve_evar_evar f env evd ev1 ev2 =
- try solve_evar_evar_l2r f env evd ev1 ev2
- with CannotProject projs1 ->
- try solve_evar_evar_l2r f env evd ev2 ev1
- with CannotProject projs2 ->
- postpone_evar_evar env evd projs1 ev1 projs2 ev2
+ try
+ try solve_evar_evar_l2r f env evd ev1 ev2
+ with CannotProject projs1 ->
+ try solve_evar_evar_l2r f env evd ev2 ev1
+ with CannotProject projs2 ->
+ postpone_evar_evar env evd projs1 ev1 projs2 ev2
+ with IllTypedFilter ->
+ user_err_loc (fst (evar_source (fst ev1) evd),"",
+ str "Unable to find a well-typed restriction of the context")
(* Solve pbs (?i x1..xn) = (?i y1..yn) which arises often in fixpoint
* definitions. We try to unify the xi with the yi pairwise. The pairs
@@ -971,7 +988,7 @@ let solve_refl conv_algo env evd evk argsv1 argsv2 =
* Note: we don't assume rhs in normal form, it may fail while it would
* have succeeded after some reductions.
*
- * This is the work of [invert_definition Γ Σ ?ev[hyps:=args]
+ * This is the work of [invert_definition Γ Σ ?ev[hyps:=args] c]
* Precondition: Σ; Γ, y1..yk |- c /\ Σ; Γ |- u1..un
* Postcondition: if φ(x1..xn) is returned then
* Σ; Γ, y1..yk |- φ(u1..un) = c /\ x1..xn |- φ(x1..xn)
@@ -1012,8 +1029,8 @@ let rec invert_definition choose env evd (evk,argsv as ev) rhs =
let ts = expansions_of_var aliases t in
let test c = isEvar c or List.mem c ts in
let filter = array_map_to_list test argsv in
+ let evarenv,src,filter,_ = restrict_hyps ~refine:true !evdref evk filter in
let args' = filter_along (fun x -> x) filter argsv in
- let evarenv,src,filter,_ = restrict_hyps !evdref evk filter in
let evd,evar = new_evar !evdref evarenv ~src ~filter ty in
let evk',_ = destEvar evar in
let pb = (Reduction.CONV,env,mkEvar(evk',args'),t) in
@@ -1032,27 +1049,32 @@ let rec invert_definition choose env evd (evk,argsv as ev) rhs =
array_map_to_list
(invert_arg_from_subst aliases k !evdref subst) args'
in
- (try
- (* Try to project (a restriction of) the right evar *)
- let eprojs' = effective_projections projs' in
- let evd,args' =
- list_fold_map (instance_of_projection evar_define env' t)
- !evdref eprojs' in
- let evd,evk' = do_restrict_hyps evd evk' projs' in
- evdref := evd;
- mkEvar (evk',Array.of_list args')
- with NotUnique ->
- assert !progress;
- (* Make the virtual left evar real *)
- let (evar'',ev'') = extend_evar env' evdref k ev t in
- let evd =
- (* Try to project (a restriction of) the left evar ... *)
- try solve_evar_evar_l2r evar_define env' !evdref ev'' ev'
- with CannotProject projs'' ->
- (* ... or postpone the problem *)
- postpone_evar_evar env' !evdref projs'' ev'' projs' ev' in
- evdref := evd;
- evar'')
+ (try
+ (* Try to project (a restriction of) the right evar *)
+ let eprojs' = effective_projections projs' in
+ let evd,args' =
+ list_fold_map (instance_of_projection evar_define env' t)
+ !evdref eprojs' in
+ let evd,evk' = do_restrict_hyps evd evk' projs' in
+ evdref := evd;
+ mkEvar (evk',Array.of_list args')
+ with NotUnique | IllTypedFilter ->
+ assert !progress;
+ (* Make the virtual left evar real *)
+ let ty = get_type_of env' !evdref t in
+ let nc, ty, _ = push_rel_context_to_named_context env' ty in
+ let env' = reset_with_named_context nc env' in
+ let (evar'',ev'') = extend_evar env' evdref k ev ty in
+ try let evd =
+ (* Try to project (a restriction of) the left evar ... *)
+ try solve_evar_evar_l2r evar_define env' !evdref ev'' ev'
+ with CannotProject projs'' ->
+ (* ... or postpone the problem *)
+ postpone_evar_evar env' !evdref projs'' ev'' projs' ev'
+ in
+ evdref := evd;
+ evar''
+ with IllTypedFilter -> raise (NotInvertibleUsingOurAlgorithm t))
| _ ->
match
let c,args = decompose_app_vect t in
@@ -1300,6 +1322,27 @@ let status_changed lev (pbty,_,t1,t2) =
* Returns an optional list of evars that were instantiated, or None
* if the problem couldn't be solved. *)
+let check_evar_instance evd evk1 conv_algo =
+ let evi = Evd.find evd evk1 in
+ let evenv = evar_unfiltered_env evi in
+ let evc = nf_evar evd evi.evar_concl in
+ match evi.evar_body with
+ | Evar_defined body ->
+ (* FIXME: The body might be ill-typed when this is called from w_merge *)
+ let ty =
+ try Retyping.get_type_of evenv evd body
+ with _ -> error "Ill-typed evar instance"
+ in
+ let ty = nf_evar evd ty in
+(* if occur_existential evd evc || occur_existential evd ty *)
+(* then add_conv_pb (Reduction.CUMUL,evenv,ty,evc) evd *)
+(* else *)
+ let evd,b = conv_algo evenv evd Reduction.CUMUL ty evc in
+ if b then evd else
+ user_err_loc (fst (evar_source evk1 evd),"",
+ str "Unable to find a well-typed instantiation")
+ | Evar_empty -> evd (* Resulted in a constraint *)
+
(* Rq: uncomplete algorithm if pbty = CONV_X_LEQ ! *)
let solve_simple_eqn conv_algo ?(choose=false) env evd (pbty,(evk1,args1 as ev1),t2) =
try
@@ -1310,33 +1353,18 @@ let solve_simple_eqn conv_algo ?(choose=false) env evd (pbty,(evk1,args1 as ev1)
solve_refl conv_algo env evd evk1 args1 args2
else
if pbty = None
- then solve_evar_evar evar_define env evd ev1 ev2
+ then
+ solve_evar_evar
+ (fun env ex c evm ->
+ check_evar_instance (evar_define env ex c evm) (fst ex) conv_algo)
+ env evd ev1 ev2
else if pbty = Some true then
add_conv_pb (Reduction.CUMUL,env,mkEvar ev1,t2) evd
else
add_conv_pb (Reduction.CUMUL,env,t2,mkEvar ev1) evd
| _ ->
let evd = evar_define ~choose env ev1 t2 evd in
- let evi = Evd.find evd evk1 in
- let evenv = evar_unfiltered_env evi in
- let evc = nf_evar evd evi.evar_concl in
- match evi.evar_body with
- | Evar_defined body ->
- (* FIXME: The body might be ill-typed when this is called from w_merge *)
- let ty =
- try Retyping.get_type_of evenv evd body
- with _ -> error "Ill-typed evar instance"
- in
- let ty = nf_evar evd ty in
- if occur_existential evd evi.evar_concl
- || occur_existential evd ty
- then add_conv_pb (Reduction.CUMUL,evenv,ty,evc) evd
- else
- let evd,b = conv_algo evenv evd Reduction.CUMUL ty evc in
- if b then evd else
- user_err_loc (fst (evar_source (fst ev1) evd),"",
- str "Unable to find a well-typed instantiation")
- | Evar_empty -> evd (* Resulted in a constraint *)
+ check_evar_instance evd evk1 conv_algo
in
let (evd,pbs) = extract_changed_conv_pbs evd status_changed in
List.fold_left
@@ -1523,7 +1551,7 @@ let define_pure_evar_as_lambda env evd evk =
let newenv = push_named (id, None, dom) evenv in
let filter = true::evar_filter evi in
let src = evar_source evk evd1 in
- let evd2,body = new_evar evd1 newenv ~src rng ~filter in
+ let evd2,body = new_evar evd1 newenv ~src (subst1 (mkVar id) rng) ~filter in
let lam = mkLambda (Name id, dom, subst_var id body) in
Evd.define evk lam evd2, lam