aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pretyping/evarconv.ml120
-rw-r--r--pretyping/evarconv.mli2
-rw-r--r--pretyping/evarutil.ml9
-rw-r--r--pretyping/evarutil.mli4
-rw-r--r--pretyping/typing.ml4
-rw-r--r--pretyping/typing.mli2
6 files changed, 139 insertions, 2 deletions
diff --git a/pretyping/evarconv.ml b/pretyping/evarconv.ml
index b384cdf28..121de57bf 100644
--- a/pretyping/evarconv.ml
+++ b/pretyping/evarconv.ml
@@ -567,6 +567,118 @@ let choose_less_dependent_instance evk evd term args =
if subst' = [] then error "Too complex unification problem." else
Evd.define evk (mkVar (fst (List.hd subst'))) evd
+let apply_on_subterm f c t =
+ let rec applyrec (k,c as kc) t =
+ (* By using eq_constr, we make an approximation, for instance, we *)
+ (* could also be interested in finding a term u convertible to t *)
+ (* such that c occurs in u *)
+ if eq_constr c t then f k
+ else
+ map_constr_with_binders_left_to_right (fun d (k,c) -> (k+1,lift 1 c))
+ applyrec kc t
+ in
+ applyrec (0,c) t
+
+let filter_possible_projections c args =
+ let fv1 = free_rels c in
+ let fv2 = collect_vars c in
+ List.map (fun a ->
+ a == c ||
+ (* Here we make an approximation, for instance, we could also be *)
+ (* interested in finding a term u convertible to c such that a occurs *)
+ (* in u *)
+ isRel a && Intset.mem (destRel a) fv1 ||
+ isVar a && Idset.mem (destVar a) fv2)
+ args
+
+let initial_evar_data evi =
+ let ids = List.map pi1 (evar_context evi) in
+ (evar_filter evi, List.map mkVar ids)
+
+let solve_evars = ref (fun _ -> failwith "solve_evars not installed")
+let set_solve_evars f = solve_evars := f
+
+(* We solve the problem env_rhs |- ?e[u1..un] = rhs knowing env_ev |- ev : ty
+ * by looking for a maximal well-typed abtraction over u1..un in rhs
+ *
+ * We first build \x1..\xn.C[e11..e1p1,..,en1..enpn] where all occurrences of
+ * u1..un have been replaced by evars eij (in practice, this is a bit more
+ * complicated as shown above since each eij depends on x1..xi-1 and because
+ * occurrences of u1..ui can occur in the types of xi+1..xn).
+ *
+ * Then, we use typing to infer the relations between the different
+ * occurrences. If some occurrence is still unconstrained after typing,
+ * we instantiate successively the unresolved occurrences of un by xn,
+ * of un-1 by xn-1, etc [the idea comes from Chung-Kil Hur, that he
+ * used for his Heq plugin; extensions to several arguments based on a
+ * proposition from Dan Grayson]
+ *)
+
+let second_order_matching ts env_rhs evd (evk,args) rhs =
+ try
+ let args = Array.to_list args in
+ let evi = Evd.find_undefined evd evk in
+ let sign = evar_hyps evi in
+ let ctxt = named_context_of_val sign in
+ let filter = evar_filter evi in
+ let instance = List.map mkVar (List.map pi1 ctxt) in
+ let rec set_holes evd subst rhs = function
+ | (id,_,t)::ctxt, c::l ->
+ let ty = Retyping.get_type_of env_rhs evd c in
+ let evd,b = evar_conv_x ts env_rhs evd CUMUL ty (replace_vars subst t) in
+ if not b then raise Exit;
+ let subst = (id,c)::subst in
+ let evd,evoccs,rhs = set_holes evd subst rhs (ctxt,l) in
+ let evs = ref [] in
+ let evdref = ref evd in
+ let filter = List.map2 (&&) filter (filter_possible_projections c args) in
+ let set_var k =
+ let evd,ev = new_evar_instance sign !evdref t ~filter instance in
+ evdref := evd;
+ evs := fst (destEvar ev)::!evs;
+ ev in
+ let rhs = apply_on_subterm set_var c rhs in
+ (!evdref, (id,c,!evs)::evoccs, rhs)
+ | [],[] ->
+ (evd, [], rhs)
+ | _ ->
+ anomaly "Signature and instance do not match" in
+
+ let evd,evoccs,rhs = set_holes evd [] rhs (ctxt,args) in
+
+ (* We instantiate the evars of which the value is forced by typing *)
+ let evd,rhs =
+ try !solve_evars env_rhs evd rhs
+ with e when Pretype_errors.precatchable_exception e ->
+ (* Could not revert all subterms *)
+ raise Exit in
+
+ let rec abstract_free_holes evd = function
+ | (id,c,evs)::l ->
+ let rec force_instantiation evd = function
+ | evk::evs ->
+ let evd =
+ if is_undefined evd evk then
+ (* We force abstraction over this unconstrained occurrence *)
+ (* and we use typing to propagate this instantiation *)
+ (* This is an arbitrary choice *)
+ let evd = Evd.define evk (mkVar id) evd in
+ let evd,b = reconsider_conv_pbs (evar_conv_x ts) evd in
+ if b then evd else error "Cannot find an instance for ..."
+ else
+ evd
+ in
+ force_instantiation evd evs
+ | [] ->
+ abstract_free_holes evd l
+ in
+ force_instantiation evd evs
+ | [] ->
+ Evd.define evk rhs evd in
+
+ abstract_free_holes evd evoccs, true
+ with Exit -> evd, false
+
let apply_conversion_problem_heuristic ts env evd pbty t1 t2 =
let t1 = apprec_nohdbeta ts env evd (whd_head_evar evd t1) in
let t2 = apprec_nohdbeta ts env evd (whd_head_evar evd t2) in
@@ -589,6 +701,14 @@ let apply_conversion_problem_heuristic ts env evd pbty t1 t2 =
| _,Evar ev2 when List.length l2 <= List.length l1 ->
(* On "u u1 .. u(n+p) = ?n t1 .. tn", try first-order unification *)
first_order_unification ts env evd (ev2,l2) appr1
+ | Evar ev1,_ ->
+ (* Try second-order pattern-matching *)
+ let evd,ev1 = evar_absorb_arguments env evd ev1 l1 in
+ second_order_matching ts env evd ev1 (applist appr2)
+ | _,Evar ev2 ->
+ (* Try second-order pattern-matching *)
+ let evd,ev2 = evar_absorb_arguments env evd ev2 l2 in
+ second_order_matching ts env evd ev2 (applist appr1)
| _ ->
(* Some head evar have been instantiated, or unknown kind of problem *)
evar_conv_x ts env evd pbty t1 t2
diff --git a/pretyping/evarconv.mli b/pretyping/evarconv.mli
index e1f507b0a..270d3f1e6 100644
--- a/pretyping/evarconv.mli
+++ b/pretyping/evarconv.mli
@@ -39,3 +39,5 @@ val check_conv_record : constr * types list -> constr * types list ->
(constr list * types list) *
(constr list * types list) * constr *
(int * constr)
+
+val set_solve_evars : (env -> evar_map -> constr -> evar_map * constr) -> unit
diff --git a/pretyping/evarutil.ml b/pretyping/evarutil.ml
index 0fa1111ff..860a2c830 100644
--- a/pretyping/evarutil.ml
+++ b/pretyping/evarutil.ml
@@ -1582,6 +1582,15 @@ let define_evar_as_lambda env evd (evk,args) =
let evbody = mkEvar (fst (destEvar body), evbodyargs) in
evd,mkLambda (na, dom, evbody)
+let rec evar_absorb_arguments env evd (evk,args as ev) = function
+ | [] -> evd,ev
+ | a::l ->
+ (* TODO: optimize and avoid introducing intermediate evars *)
+ let evd,lam = define_pure_evar_as_lambda env evd evk in
+ let _,_,body = destLambda lam in
+ let evk = fst (destEvar body) in
+ evar_absorb_arguments env evd (evk, array_cons a args) l
+
(* Refining an evar to a sort *)
let define_evar_as_sort evd (ev,args) =
diff --git a/pretyping/evarutil.mli b/pretyping/evarutil.mli
index 7c06d41c9..d5f70b08d 100644
--- a/pretyping/evarutil.mli
+++ b/pretyping/evarutil.mli
@@ -100,6 +100,10 @@ val is_unification_pattern_evar : env -> existential -> constr list ->
constr -> bool
val is_unification_pattern : env * int -> constr -> constr array ->
constr -> bool
+
+val evar_absorb_arguments : env -> evar_map -> existential -> constr list ->
+ evar_map * existential
+
val solve_pattern_eqn : env -> constr list -> constr -> constr
(** The following functions return the set of evars immediately
diff --git a/pretyping/typing.ml b/pretyping/typing.ml
index 85abe2569..2298209af 100644
--- a/pretyping/typing.ml
+++ b/pretyping/typing.ml
@@ -227,4 +227,6 @@ let solve_evars env evd c =
let evdref = ref evd in
let c = (execute env evdref c).uj_val in
(* side-effect on evdref *)
- nf_evar !evdref c
+ !evdref, nf_evar !evdref c
+
+let _ = Evarconv.set_solve_evars solve_evars
diff --git a/pretyping/typing.mli b/pretyping/typing.mli
index e2fd6a9d8..2c9a6c6c0 100644
--- a/pretyping/typing.mli
+++ b/pretyping/typing.mli
@@ -27,7 +27,7 @@ val check : env -> evar_map -> constr -> types -> unit
val meta_type : evar_map -> metavariable -> types
(** Solve existential variables using typing *)
-val solve_evars : env -> evar_map -> constr -> constr
+val solve_evars : env -> evar_map -> constr -> evar_map * constr
(** Raise an error message if incorrect elimination for this inductive *)
(** (first constr is term to match, second is return predicate) *)