aboutsummaryrefslogtreecommitdiff
path: root/mathcomp
diff options
context:
space:
mode:
authorEnrico Tassi2015-09-10 11:44:11 +0200
committerEnrico Tassi2015-12-03 09:59:45 +0100
commit4d0f111956307c5a134db701fe27f01f8ac50e9d (patch)
tree83a8175782bdd7c04d614a269878a0f9ab3e51e7 /mathcomp
parent55a5aaa22e9dd92ff1c6aba599b878c384c1a66b (diff)
fix: elim/v handles eliminator from Derive Inversion (issue #2)
Also: - fix elim trying to saturate too much and not raising the expected exn - fix fill_occ_pattern when occ is {-}, it used to lose the instantiation obtained by matching the term
Diffstat (limited to 'mathcomp')
-rw-r--r--mathcomp/ssreflect/plugin/trunk/ssreflect.ml448
-rw-r--r--mathcomp/ssreflect/plugin/trunk/ssrmatching.ml414
-rw-r--r--mathcomp/ssreflect/plugin/v8.5/ssreflect.ml448
-rw-r--r--mathcomp/ssreflect/plugin/v8.5/ssrmatching.ml414
-rw-r--r--mathcomp/ssrtest/derive_inversion.v19
5 files changed, 101 insertions, 42 deletions
diff --git a/mathcomp/ssreflect/plugin/trunk/ssreflect.ml4 b/mathcomp/ssreflect/plugin/trunk/ssreflect.ml4
index fc895a5..e82272e 100644
--- a/mathcomp/ssreflect/plugin/trunk/ssreflect.ml4
+++ b/mathcomp/ssreflect/plugin/trunk/ssreflect.ml4
@@ -3381,7 +3381,7 @@ let saturate ?(beta=false) ?(bi_types=false) env sigma c ?(ty=Retyping.get_type_
(Reductionops.whd_betadeltaiota env sigma) ty in
match kind_of_type ty with
| ProdType _ -> loop ty args sigma n
- | _ -> anomaly "saturate did not find enough products"
+ | _ -> raise NotEnoughProducts
in
loop ty [] sigma m
@@ -3904,7 +3904,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
| _ -> false in
let match_pat env p occ h cl =
let sigma0 = project orig_gl in
- pp(lazy(str"matching: " ++ pp_pattern p));
+ pp(lazy(str"matching: " ++ pr_occ occ ++ pp_pattern p));
let (c,ucst), cl =
fill_occ_pattern ~raise_NoMatch:true env sigma0 cl p occ h in
pp(lazy(str" got: " ++ pr_constr c));
@@ -3924,6 +3924,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
with e when Errors.noncritical e -> p in
(* finds the eliminator applies it to evars and c saturated as needed *)
(* obtaining "elim ??? (c ???)". pred is the higher order evar *)
+ (* cty is None when the user writes _ (hence we can't make a pattern *)
let cty, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl =
match elim with
| Some elim ->
@@ -3934,7 +3935,15 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
pf_saturate ~beta:is_case gl elim ~ty:elimty n_elim_args in
let pred = List.assoc pred_id elim_args in
let elimty = Reductionops.whd_betadeltaiota env (project gl) elimty in
- None, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl
+ let cty, gl =
+ if Option.is_empty oc then None, gl
+ else
+ let c = Option.get oc in let gl, c_ty = pf_type_of gl c in
+ let pc = match c_gen with
+ | Some p -> interp_cpattern (Option.get ist) orig_gl p None
+ | _ -> mkTpat gl c in
+ Some(c, c_ty, pc), gl in
+ cty, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl
| None ->
let c = Option.get oc in let gl, c_ty = pf_type_of gl c in
let ((kn, i) as ind, _ as indu), unfolded_c_ty =
@@ -3964,7 +3973,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
cty, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl
in
pp(lazy(str"elim= "++ pr_constr_pat elim));
- pp(lazy(str"elimty= "++ pr_constr elimty));
+ pp(lazy(str"elimty= "++ pr_constr_pat elimty));
let inf_deps_r = match kind_of_type elimty with
| AtomicType (_, args) -> List.rev (Array.to_list args)
| _ -> assert false in
@@ -3973,11 +3982,17 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
let c, c_ty, _, gl = pf_saturate gl c ~ty:c_ty n in
let gl' = f c c_ty gl in
Some (c, c_ty, gl, gl')
- with NotEnoughProducts -> None | _ -> loop (n+1) in loop 0 in
- let elim_is_dep, gl = match cty with
- | None -> true, gl
+ with
+ | NotEnoughProducts -> None
+ | e when Errors.noncritical e -> loop (n+1) in loop 0 in
+ (* Here we try to understand if the main pattern/term the user gave is
+ * the first pattern to be matched (i.e. if elimty ends in P t1 .. tn,
+ * weather tn is the t the user wrote in 'elim: t' *)
+ let c_is_head_p, gl = match cty with
+ | None -> true, gl (* The user wrote elim: _ *)
| Some (c, c_ty, _) ->
let res =
+ (* we try to see if c unifies with the last arg of elim *)
if elim_is_dep then None else
let arg = List.assoc (n_elim_args - 1) elim_args in
let gl, arg_ty = pf_type_of gl arg in
@@ -3988,21 +4003,22 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
match res with
| Some x -> x
| None ->
+ (* we try to see if c unifies with the last inferred pattern *)
let inf_arg = List.hd inf_deps_r in
let gl, inf_arg_ty = pf_type_of gl inf_arg in
match saturate_until gl c c_ty (fun _ c_ty gl ->
pf_unify_HO gl c_ty inf_arg_ty) with
| Some (c, _, _,gl) -> true, gl
| None ->
- errorstrm (str"Unable to apply the eliminator to the term"++
- spc()++pr_constr c++spc()++str"or to unify it's type with"++
- pr_constr inf_arg_ty) in
- pp(lazy(str"elim_is_dep= " ++ bool elim_is_dep));
+ errorstrm (str"Unable to apply the eliminator to the term"++
+ spc()++pr_constr c++spc()++str"or to unify it's type with"++
+ pr_constr inf_arg_ty) in
+ pp(lazy(str"c_is_head_p= " ++ bool c_is_head_p));
let gl, predty = pf_type_of gl pred in
(* Patterns for the inductive types indexes to be bound in pred are computed
* looking at the ones provided by the user and the inferred ones looking at
* the type of the elimination principle *)
- let pp_pat (_,p,_,_) = pp_pattern p in
+ let pp_pat (_,p,_,occ) = pr_occ occ ++ pp_pattern p in
let pp_inf_pat gl (_,_,t,_) = pr_constr_pat (fire_subst gl t) in
let patterns, clr, gl =
let rec loop patterns clr i = function
@@ -4018,12 +4034,12 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
loop (patterns @ [i, p, inf_t, occ])
(clr_t @ clr) (i+1) (deps, inf_deps)
| [], c :: inf_deps ->
- pp(lazy(str"adding inferred pattern " ++ pr_constr_pat c));
+ pp(lazy(str"adding inf pattern " ++ pr_constr_pat c));
loop (patterns @ [i, mkTpat gl c, c, allocc])
clr (i+1) ([], inf_deps)
| _::_, [] -> errorstrm (str "Too many dependent abstractions") in
- let deps, head_p, inf_deps_r = match what, elim_is_dep, cty with
- | `EConstr _, _, None -> anomaly "Simple welim with no term"
+ let deps, head_p, inf_deps_r = match what, c_is_head_p, cty with
+ | `EConstr _, _, None -> anomaly "Simple elim with no term"
| _, false, _ -> deps, [], inf_deps_r
| `EGen gen, true, None -> deps @ [gen], [], inf_deps_r
| _, true, Some (c, _, pc) ->
@@ -4083,7 +4099,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
let erefl, gl = mkRefl t c gl in
let erefl = fire_subst gl erefl in
apply_type new_concl [erefl], gl in
- let rel = k + if elim_is_dep then 1 else 0 in
+ let rel = k + if c_is_head_p then 1 else 0 in
let src, gl = mkProt mkProp (mkApp (eq,[|t; c; mkRel rel|])) gl in
let concl = mkArrow src (lift 1 concl) in
let clr = if deps <> [] then clr else [] in
diff --git a/mathcomp/ssreflect/plugin/trunk/ssrmatching.ml4 b/mathcomp/ssreflect/plugin/trunk/ssrmatching.ml4
index b697050..aa44fec 100644
--- a/mathcomp/ssreflect/plugin/trunk/ssrmatching.ml4
+++ b/mathcomp/ssreflect/plugin/trunk/ssrmatching.ml4
@@ -776,7 +776,7 @@ let rec uniquize = function
let sigma, _, ({up_f = pf; up_a = pa} as u) =
if all_instances then assert_done_multires upat_that_matched
else List.hd (snd(assert_done upat_that_matched)) in
- pp(lazy(str"sigma@tmatch=" ++ pr_evar_map None sigma));
+(* pp(lazy(str"sigma@tmatch=" ++ pr_evar_map None sigma)); *)
if !skip_occ then ((*ignore(k env u.up_t 0);*) c) else
let match_EQ = match_EQ env sigma u in
let pn = Array.length pa in
@@ -846,7 +846,7 @@ let pr_pattern_aux pr_constr = function
| E_As_X_In_T (e,x,t) ->
pr_constr e ++ str " as " ++ pr_constr x ++ str " in " ++ pr_constr t
let pp_pattern (sigma, p) =
- pr_pattern_aux (fun t -> pr_constr (pi3 (nf_open_term sigma sigma t))) p
+ pr_pattern_aux (fun t -> pr_constr_pat (pi3 (nf_open_term sigma sigma t))) p
let pr_cpattern = pr_term
let pr_rpattern _ _ _ = pr_pattern
@@ -1192,9 +1192,13 @@ let redex_of_pattern ?(resolve_typeclasses=false) env (sigma, p) =
Reductionops.nf_evar sigma e, Evd.evar_universe_context sigma
let fill_occ_pattern ?raise_NoMatch env sigma cl pat occ h =
- let find_R, conclude = let r = ref None in
- (fun env c _ h' -> do_once r (fun () -> c, Evd.empty_evar_universe_context);
- mkRel (h'+h-1)),
+ let do_make_rel, occ =
+ if occ = Some(true,[]) then false, Some(false,[1]) else true, occ in
+ let find_R, conclude =
+ let r = ref None in
+ (fun env c _ h' ->
+ do_once r (fun () -> c, Evd.empty_evar_universe_context);
+ if do_make_rel then mkRel (h'+h-1) else c),
(fun _ -> if !r = None then redex_of_pattern env pat else assert_done r) in
let cl = eval_pattern ?raise_NoMatch env sigma cl (Some pat) occ find_R in
let e = conclude cl in
diff --git a/mathcomp/ssreflect/plugin/v8.5/ssreflect.ml4 b/mathcomp/ssreflect/plugin/v8.5/ssreflect.ml4
index 9452aa2..d0a430a 100644
--- a/mathcomp/ssreflect/plugin/v8.5/ssreflect.ml4
+++ b/mathcomp/ssreflect/plugin/v8.5/ssreflect.ml4
@@ -3375,7 +3375,7 @@ let saturate ?(beta=false) ?(bi_types=false) env sigma c ?(ty=Retyping.get_type_
(Reductionops.whd_betadeltaiota env sigma) ty in
match kind_of_type ty with
| ProdType _ -> loop ty args sigma n
- | _ -> anomaly "saturate did not find enough products"
+ | _ -> raise NotEnoughProducts
in
loop ty [] sigma m
@@ -3898,7 +3898,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
| _ -> false in
let match_pat env p occ h cl =
let sigma0 = project orig_gl in
- pp(lazy(str"matching: " ++ pp_pattern p));
+ pp(lazy(str"matching: " ++ pr_occ occ ++ pp_pattern p));
let (c,ucst), cl =
fill_occ_pattern ~raise_NoMatch:true env sigma0 cl p occ h in
pp(lazy(str" got: " ++ pr_constr c));
@@ -3918,6 +3918,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
with e when Errors.noncritical e -> p in
(* finds the eliminator applies it to evars and c saturated as needed *)
(* obtaining "elim ??? (c ???)". pred is the higher order evar *)
+ (* cty is None when the user writes _ (hence we can't make a pattern *)
let cty, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl =
match elim with
| Some elim ->
@@ -3928,7 +3929,15 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
pf_saturate ~beta:is_case gl elim ~ty:elimty n_elim_args in
let pred = List.assoc pred_id elim_args in
let elimty = Reductionops.whd_betadeltaiota env (project gl) elimty in
- None, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl
+ let cty, gl =
+ if Option.is_empty oc then None, gl
+ else
+ let c = Option.get oc in let gl, c_ty = pf_type_of gl c in
+ let pc = match c_gen with
+ | Some p -> interp_cpattern (Option.get ist) orig_gl p None
+ | _ -> mkTpat gl c in
+ Some(c, c_ty, pc), gl in
+ cty, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl
| None ->
let c = Option.get oc in let gl, c_ty = pf_type_of gl c in
let ((kn, i) as ind, _ as indu), unfolded_c_ty =
@@ -3958,7 +3967,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
cty, elim, elimty, elim_args, n_elim_args, elim_is_dep, is_rec, pred, gl
in
pp(lazy(str"elim= "++ pr_constr_pat elim));
- pp(lazy(str"elimty= "++ pr_constr elimty));
+ pp(lazy(str"elimty= "++ pr_constr_pat elimty));
let inf_deps_r = match kind_of_type elimty with
| AtomicType (_, args) -> List.rev (Array.to_list args)
| _ -> assert false in
@@ -3967,11 +3976,17 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
let c, c_ty, _, gl = pf_saturate gl c ~ty:c_ty n in
let gl' = f c c_ty gl in
Some (c, c_ty, gl, gl')
- with NotEnoughProducts -> None | _ -> loop (n+1) in loop 0 in
- let elim_is_dep, gl = match cty with
- | None -> true, gl
+ with
+ | NotEnoughProducts -> None
+ | e when Errors.noncritical e -> loop (n+1) in loop 0 in
+ (* Here we try to understand if the main pattern/term the user gave is
+ * the first pattern to be matched (i.e. if elimty ends in P t1 .. tn,
+ * weather tn is the t the user wrote in 'elim: t' *)
+ let c_is_head_p, gl = match cty with
+ | None -> true, gl (* The user wrote elim: _ *)
| Some (c, c_ty, _) ->
let res =
+ (* we try to see if c unifies with the last arg of elim *)
if elim_is_dep then None else
let arg = List.assoc (n_elim_args - 1) elim_args in
let gl, arg_ty = pf_type_of gl arg in
@@ -3982,21 +3997,22 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
match res with
| Some x -> x
| None ->
+ (* we try to see if c unifies with the last inferred pattern *)
let inf_arg = List.hd inf_deps_r in
let gl, inf_arg_ty = pf_type_of gl inf_arg in
match saturate_until gl c c_ty (fun _ c_ty gl ->
pf_unify_HO gl c_ty inf_arg_ty) with
| Some (c, _, _,gl) -> true, gl
| None ->
- errorstrm (str"Unable to apply the eliminator to the term"++
- spc()++pr_constr c++spc()++str"or to unify it's type with"++
- pr_constr inf_arg_ty) in
- pp(lazy(str"elim_is_dep= " ++ bool elim_is_dep));
+ errorstrm (str"Unable to apply the eliminator to the term"++
+ spc()++pr_constr c++spc()++str"or to unify it's type with"++
+ pr_constr inf_arg_ty) in
+ pp(lazy(str"c_is_head_p= " ++ bool c_is_head_p));
let gl, predty = pf_type_of gl pred in
(* Patterns for the inductive types indexes to be bound in pred are computed
* looking at the ones provided by the user and the inferred ones looking at
* the type of the elimination principle *)
- let pp_pat (_,p,_,_) = pp_pattern p in
+ let pp_pat (_,p,_,occ) = pr_occ occ ++ pp_pattern p in
let pp_inf_pat gl (_,_,t,_) = pr_constr_pat (fire_subst gl t) in
let patterns, clr, gl =
let rec loop patterns clr i = function
@@ -4012,12 +4028,12 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
loop (patterns @ [i, p, inf_t, occ])
(clr_t @ clr) (i+1) (deps, inf_deps)
| [], c :: inf_deps ->
- pp(lazy(str"adding inferred pattern " ++ pr_constr_pat c));
+ pp(lazy(str"adding inf pattern " ++ pr_constr_pat c));
loop (patterns @ [i, mkTpat gl c, c, allocc])
clr (i+1) ([], inf_deps)
| _::_, [] -> errorstrm (str "Too many dependent abstractions") in
- let deps, head_p, inf_deps_r = match what, elim_is_dep, cty with
- | `EConstr _, _, None -> anomaly "Simple welim with no term"
+ let deps, head_p, inf_deps_r = match what, c_is_head_p, cty with
+ | `EConstr _, _, None -> anomaly "Simple elim with no term"
| _, false, _ -> deps, [], inf_deps_r
| `EGen gen, true, None -> deps @ [gen], [], inf_deps_r
| _, true, Some (c, _, pc) ->
@@ -4077,7 +4093,7 @@ let ssrelim ?(is_case=false) ?ist deps what ?elim eqid ipats gl =
let erefl, gl = mkRefl t c gl in
let erefl = fire_subst gl erefl in
apply_type new_concl [erefl], gl in
- let rel = k + if elim_is_dep then 1 else 0 in
+ let rel = k + if c_is_head_p then 1 else 0 in
let src, gl = mkProt mkProp (mkApp (eq,[|t; c; mkRel rel|])) gl in
let concl = mkArrow src (lift 1 concl) in
let clr = if deps <> [] then clr else [] in
diff --git a/mathcomp/ssreflect/plugin/v8.5/ssrmatching.ml4 b/mathcomp/ssreflect/plugin/v8.5/ssrmatching.ml4
index 7a58c61..74f42f6 100644
--- a/mathcomp/ssreflect/plugin/v8.5/ssrmatching.ml4
+++ b/mathcomp/ssreflect/plugin/v8.5/ssrmatching.ml4
@@ -776,7 +776,7 @@ let rec uniquize = function
let sigma, _, ({up_f = pf; up_a = pa} as u) =
if all_instances then assert_done_multires upat_that_matched
else List.hd (snd(assert_done upat_that_matched)) in
- pp(lazy(str"sigma@tmatch=" ++ pr_evar_map None sigma));
+(* pp(lazy(str"sigma@tmatch=" ++ pr_evar_map None sigma)); *)
if !skip_occ then ((*ignore(k env u.up_t 0);*) c) else
let match_EQ = match_EQ env sigma u in
let pn = Array.length pa in
@@ -846,7 +846,7 @@ let pr_pattern_aux pr_constr = function
| E_As_X_In_T (e,x,t) ->
pr_constr e ++ str " as " ++ pr_constr x ++ str " in " ++ pr_constr t
let pp_pattern (sigma, p) =
- pr_pattern_aux (fun t -> pr_constr (pi3 (nf_open_term sigma sigma t))) p
+ pr_pattern_aux (fun t -> pr_constr_pat (pi3 (nf_open_term sigma sigma t))) p
let pr_cpattern = pr_term
let pr_rpattern _ _ _ = pr_pattern
@@ -1192,9 +1192,13 @@ let redex_of_pattern ?(resolve_typeclasses=false) env (sigma, p) =
Reductionops.nf_evar sigma e, Evd.evar_universe_context sigma
let fill_occ_pattern ?raise_NoMatch env sigma cl pat occ h =
- let find_R, conclude = let r = ref None in
- (fun env c _ h' -> do_once r (fun () -> c, Evd.empty_evar_universe_context);
- mkRel (h'+h-1)),
+ let do_make_rel, occ =
+ if occ = Some(true,[]) then false, Some(false,[1]) else true, occ in
+ let find_R, conclude =
+ let r = ref None in
+ (fun env c _ h' ->
+ do_once r (fun () -> c, Evd.empty_evar_universe_context);
+ if do_make_rel then mkRel (h'+h-1) else c),
(fun _ -> if !r = None then redex_of_pattern env pat else assert_done r) in
let cl = eval_pattern ?raise_NoMatch env sigma cl (Some pat) occ find_R in
let e = conclude cl in
diff --git a/mathcomp/ssrtest/derive_inversion.v b/mathcomp/ssrtest/derive_inversion.v
new file mode 100644
index 0000000..71257d8
--- /dev/null
+++ b/mathcomp/ssrtest/derive_inversion.v
@@ -0,0 +1,19 @@
+Require Import ssreflect ssrbool.
+
+Set Implicit Arguments.
+
+ Inductive wf T : bool -> option T -> Type :=
+ | wf_f : wf false None
+ | wf_t : forall x, wf true (Some x).
+
+ Derive Inversion wf_inv with (forall T b (o : option T), wf b o) Sort Prop.
+
+ Lemma Problem T b (o : option T) :
+ wf b o ->
+ match b with
+ | true => exists x, o = Some x
+ | false => o = None
+ end.
+ Proof.
+ by case: b; elim/wf_inv=>//;case: o=>// a *; exists a.
+ Qed.