aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--contrib/funind/indfun.ml2
-rw-r--r--contrib/subtac/subtac_command.ml4
-rw-r--r--contrib/subtac/subtac_command.mli2
-rw-r--r--doc/refman/RefMan-ltac.tex68
-rw-r--r--interp/constrintern.ml16
-rw-r--r--interp/constrintern.mli4
-rw-r--r--parsing/g_constr.ml45
-rw-r--r--pretyping/pattern.ml2
-rw-r--r--tactics/tacinterp.ml2
-rw-r--r--test-suite/success/ltac.v13
11 files changed, 83 insertions, 40 deletions
diff --git a/CHANGES b/CHANGES
index 9101ace26..6bb9e268b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@ Changes from V8.1gamma to ...
- Added option Global to "Implicit Arguments" and "Arguments Scope" for
section surviving.
+Tactic Language
+
+- Second-order pattern-matching now working in Ltac "match" clauses
+ (syntax for second-order unification variable is "@?X").
+
Tactics
- New tactic ring, ring_simplify and new tactic field now able to manage
diff --git a/contrib/funind/indfun.ml b/contrib/funind/indfun.ml
index 82bb28695..a131c95a5 100644
--- a/contrib/funind/indfun.ml
+++ b/contrib/funind/indfun.ml
@@ -146,7 +146,7 @@ let rec abstract_rawconstr c = function
let interp_casted_constr_with_implicits sigma env impls c =
(* Constrintern.interp_rawconstr_with_implicits sigma env [] impls c *)
Constrintern.intern_gen false sigma env ~impls:([],impls)
- ~allow_soapp:false ~ltacvars:([],[]) c
+ ~allow_patvar:false ~ltacvars:([],[]) c
(*
diff --git a/contrib/subtac/subtac_command.ml b/contrib/subtac/subtac_command.ml
index e624b5f32..cab8829db 100644
--- a/contrib/subtac/subtac_command.ml
+++ b/contrib/subtac/subtac_command.ml
@@ -53,9 +53,9 @@ let evar_nf isevars c =
Evarutil.nf_isevar !isevars c
let interp_gen kind isevars env
- ?(impls=([],[])) ?(allow_soapp=false) ?(ltacvars=([],[]))
+ ?(impls=([],[])) ?(allow_patvar=false) ?(ltacvars=([],[]))
c =
- let c' = Constrintern.intern_gen (kind=IsType) ~impls ~allow_soapp ~ltacvars (Evd.evars_of !isevars) env c in
+ let c' = Constrintern.intern_gen (kind=IsType) ~impls ~allow_patvar ~ltacvars (Evd.evars_of !isevars) env c in
let c' = Subtac_utils.rewrite_cases env c' in
(* (try trace (str "Pretyping " ++ my_print_constr_expr c) with _ -> ()); *)
let c' = SPretyping.pretype_gen isevars env ([],[]) kind c' in
diff --git a/contrib/subtac/subtac_command.mli b/contrib/subtac/subtac_command.mli
index 846e06cfb..6de45d17f 100644
--- a/contrib/subtac/subtac_command.mli
+++ b/contrib/subtac/subtac_command.mli
@@ -14,7 +14,7 @@ val interp_gen :
evar_defs ref ->
env ->
?impls:full_implicits_env ->
- ?allow_soapp:bool ->
+ ?allow_patvar:bool ->
?ltacvars:ltac_sign ->
constr_expr -> constr
val interp_constr :
diff --git a/doc/refman/RefMan-ltac.tex b/doc/refman/RefMan-ltac.tex
index ad2ffdc63..79a33712d 100644
--- a/doc/refman/RefMan-ltac.tex
+++ b/doc/refman/RefMan-ltac.tex
@@ -29,18 +29,28 @@ problems.
The syntax of the tactic language is given Figures~\ref{ltac}
and~\ref{ltac_aux}. See page~\pageref{BNF-syntax} for a description of
-the BNF metasyntax used in these grammar rules. Various already defined
-entries will be used in this chapter: entries {\naturalnumber},
-{\integer}, {\ident}, {\qualid}, {\term}, {\cpattern} and {\atomictac}
-represent respectively the natural and integer numbers, the authorized
-identificators and qualified names, {\Coq}'s terms and patterns and
-all the atomic tactics described in chapter~\ref{Tactics}. The syntax
-of {\cpattern} is the same as that of terms, but there can be specific
-variables like {\tt ?id} where {\tt id} is a {\ident} or {\tt \_},
-which are metavariables for pattern matching. {\tt ?id} allows us to
+the BNF metasyntax used in these grammar rules. Various already
+defined entries will be used in this chapter: entries
+{\naturalnumber}, {\integer}, {\ident}, {\qualid}, {\term},
+{\cpattern} and {\atomictac} represent respectively the natural and
+integer numbers, the authorized identificators and qualified names,
+{\Coq}'s terms and patterns and all the atomic tactics described in
+chapter~\ref{Tactics}. The syntax of {\cpattern} is the same as that
+of terms, but it is extended with pattern matching metavariables. In
+{\cpattern}, a pattern-matching metavariable is represented with the
+syntax {\tt ?id} where {\tt id} is a {\ident}. The notation {\tt \_}
+can also be used to denote metavariable whose instance is
+irrelevant. In the notation {\tt ?id}, the identifier allows us to
keep instantiations and to make constraints whereas {\tt \_} shows
that we are not interested in what will be matched. On the right hand
-side, they are used without the question mark.
+side of pattern-matching clauses, the named metavariable are used
+without the question mark prefix. There is also a special notation for
+second-order pattern-matching problems: in an applicative pattern of
+the form {\tt @?id id$_1$ \ldots id$_n$}, the variable {\tt id}
+matches any complex expression with (possible) dependencies in the
+variables {\tt id$_1$ \ldots id$_n$} and returns a functional term of
+the form {\tt fun id$_1$ \ldots id$_n$ => {\term}}.
+
The main entry of the grammar is {\tacexpr}. This language is used in
proof mode but it can also be used in toplevel definitions as shown in
@@ -483,19 +493,33 @@ We can carry out pattern matching on terms with:
~{\tt |} {\tt \_} {\tt =>} {\tacexpr}$_{n+1}$\\
{\tt end}
\end{quote}
-The {\tacexpr} is evaluated and should yield a term which is matched
-(non-linear first order unification) against {\cpattern}$_1$ then
-{\tacexpr}$_1$ is evaluated into some value by substituting the
-pattern matching instantiations to the metavariables. If the matching
-with {\cpattern}$_1$ fails, {\cpattern}$_2$ is used and so on. The
+The expression {\tacexpr} is evaluated and should yield a term which
+is matched against {\cpattern}$_1$. The matching is non-linear: if a
+metavariable occurs more than once, it should match the same
+expression every time. It is first-order except on the
+variables of the form {\tt @?id} that occur in head position of an
+application. For these variables, the matching is second-order and
+returns a functional term.
+
+If the matching with {\cpattern}$_1$ succeeds, then {\tacexpr}$_1$ is
+evaluated into some value by substituting the pattern matching
+instantiations to the metavariables. If {\tacexpr}$_1$ evaluates to a
+tactic and the {\tt match} expression is in position to be applied to
+a goal (e.g. it is not bound to a variable by a {\tt let in}), then
+this tactic is applied. If the tactic succeeds, the list of resulting
+subgoals is the result of the {\tt match} expression. If
+{\tacexpr}$_1$ does not evaluate to a tactic or if the {\tt match}
+expression is not in position to be applied to a goal, then the result
+of the evaluation of {\tacexpr}$_1$ is the result of the {\tt match}
+expression.
+
+If the matching with {\cpattern}$_1$ fails, or if it succeeds but the
+evaluation of {\tacexpr}$_1$ fails, or if the evaluation of
+{\tacexpr}$_1$ succeeds but returns a tactic in execution position
+whose execution fails, then {\cpattern}$_2$ is used and so on. The
pattern {\_} matches any term and shunts all remaining patterns if
-any. If {\tacexpr}$_1$ evaluates to a tactic and the {\tt match}
-expression is in position to be applied to a goal (e.g. it is not
-bound to a variable by a {\tt let in}, then this tactic is applied. If
-the tactic succeeds, the list of resulting subgoals is the result of
-the {\tt match} expression. On the opposite, if it fails, the next
-pattern is tried. If all clauses fail (in particular, there is no
-pattern {\_}) then a no-matching error is raised.
+any. If all clauses fail (in particular, there is no pattern {\_})
+then a no-matching-clause error is raised.
\begin{ErrMsgs}
diff --git a/interp/constrintern.ml b/interp/constrintern.ml
index 0a42d2ba9..244f8228a 100644
--- a/interp/constrintern.ml
+++ b/interp/constrintern.ml
@@ -776,7 +776,7 @@ let reset_tmp_scope (ids,tmp_scope,scopes) =
(**********************************************************************)
(* Main loop *)
-let internalise sigma globalenv env allow_soapp lvar c =
+let internalise sigma globalenv env allow_patvar lvar c =
let rec intern (ids,tmp_scope,scopes as env) = function
| CRef ref as x ->
let (c,imp,subscopes,l) = intern_reference env lvar ref in
@@ -916,10 +916,8 @@ let internalise sigma globalenv env allow_soapp lvar c =
RIf (loc, c', (na', p'), intern env b1, intern env b2)
| CHole loc ->
RHole (loc, Evd.QuestionMark)
- | CPatVar (loc, n) when allow_soapp ->
+ | CPatVar (loc, n) when allow_patvar ->
RPatVar (loc, n)
- | CPatVar (loc, (false,n)) ->
- error_unbound_patvar loc n
| CPatVar (loc, _) ->
raise (InternalisationError (loc,NegativeMetavariable))
| CEvar (loc, n) ->
@@ -1078,12 +1076,12 @@ let extract_ids env =
Idset.empty
let intern_gen isarity sigma env
- ?(impls=([],[])) ?(allow_soapp=false) ?(ltacvars=([],[]))
+ ?(impls=([],[])) ?(allow_patvar=false) ?(ltacvars=([],[]))
c =
let tmp_scope =
if isarity then Some Notation.type_scope else None in
internalise sigma env (extract_ids env, tmp_scope,[])
- allow_soapp (ltacvars,Environ.named_context env, [], impls) c
+ allow_patvar (ltacvars,Environ.named_context env, [], impls) c
let intern_constr sigma env c = intern_gen false sigma env c
@@ -1102,10 +1100,10 @@ let intern_ltac isarity ltacvars sigma env c =
(* Functions to parse and interpret constructions *)
let interp_gen kind sigma env
- ?(impls=([],[])) ?(allow_soapp=false) ?(ltacvars=([],[]))
+ ?(impls=([],[])) ?(allow_patvar=false) ?(ltacvars=([],[]))
c =
Default.understand_gen kind sigma env
- (intern_gen (kind=IsType) ~impls ~allow_soapp ~ltacvars sigma env c)
+ (intern_gen (kind=IsType) ~impls ~allow_patvar ~ltacvars sigma env c)
let interp_constr sigma env c =
interp_gen (OfType None) sigma env c
@@ -1140,7 +1138,7 @@ let interp_constr_judgment_evars isevars env c =
type ltac_sign = identifier list * unbound_ltac_var_map
let interp_constrpattern sigma env c =
- pattern_of_rawconstr (intern_gen false sigma env ~allow_soapp:true c)
+ pattern_of_rawconstr (intern_gen false sigma env ~allow_patvar:true c)
let interp_aconstr impls vars a =
let env = Global.env () in
diff --git a/interp/constrintern.mli b/interp/constrintern.mli
index 12aaeec17..1af6854d3 100644
--- a/interp/constrintern.mli
+++ b/interp/constrintern.mli
@@ -52,7 +52,7 @@ type ltac_sign = identifier list * unbound_ltac_var_map
val intern_constr : evar_map -> env -> constr_expr -> rawconstr
val intern_gen : bool -> evar_map -> env ->
- ?impls:full_implicits_env -> ?allow_soapp:bool -> ?ltacvars:ltac_sign ->
+ ?impls:full_implicits_env -> ?allow_patvar:bool -> ?ltacvars:ltac_sign ->
constr_expr -> rawconstr
val intern_pattern : env -> cases_pattern_expr ->
@@ -68,7 +68,7 @@ val intern_pattern : env -> cases_pattern_expr ->
(* Main interpretation function *)
val interp_gen : typing_constraint -> evar_map -> env ->
- ?impls:full_implicits_env -> ?allow_soapp:bool -> ?ltacvars:ltac_sign ->
+ ?impls:full_implicits_env -> ?allow_patvar:bool -> ?ltacvars:ltac_sign ->
constr_expr -> constr
(* Particular instances *)
diff --git a/parsing/g_constr.ml4 b/parsing/g_constr.ml4
index b29b82607..1a721a2e3 100644
--- a/parsing/g_constr.ml4
+++ b/parsing/g_constr.ml4
@@ -151,7 +151,10 @@ GEXTEND Gram
| c1 = operconstr; "->"; c2 = SELF -> CArrow(loc,c1,c2)]
| "10" LEFTA
[ f=operconstr; args=LIST1 appl_arg -> CApp(loc,(None,f),args)
- | "@"; f=global; args=LIST0 NEXT -> CAppExpl(loc,(None,f),args) ]
+ | "@"; f=global; args=LIST0 NEXT -> CAppExpl(loc,(None,f),args)
+ | "@"; "?"; (locid,id) = identref; args=LIST1 identref ->
+ let args = List.map (fun x -> CRef (Ident x), None) args in
+ CApp(loc,(None,CPatVar(locid,(true,id))),args) ]
| "9"
[ ".."; c = operconstr LEVEL "0"; ".." ->
CAppExpl (loc,(None,Ident (loc,Topconstr.ldots_var)),[c]) ]
diff --git a/pretyping/pattern.ml b/pretyping/pattern.ml
index 979ecb0b1..b0fd76cb7 100644
--- a/pretyping/pattern.ml
+++ b/pretyping/pattern.ml
@@ -216,7 +216,7 @@ let rec pat_of_raw metas vars = function
PRef r
(* Hack pour ne pas réécrire une interprétation complète des patterns*)
| RApp (_, RPatVar (_,(true,n)), cl) ->
- PSoApp (n, List.map (pat_of_raw metas vars) cl)
+ metas := n::!metas; PSoApp (n, List.map (pat_of_raw metas vars) cl)
| RApp (_,c,cl) ->
PApp (pat_of_raw metas vars c,
Array.of_list (List.map (pat_of_raw metas vars) cl))
diff --git a/tactics/tacinterp.ml b/tactics/tacinterp.ml
index 799361a27..1bbf87a40 100644
--- a/tactics/tacinterp.ml
+++ b/tactics/tacinterp.ml
@@ -536,7 +536,7 @@ let intern_hyp_location ist ((occs,id),hl) =
((List.map (intern_or_var ist) occs,intern_hyp ist (skip_metaid id)), hl)
let interp_constrpattern_gen sigma env ltacvar c =
- let c = intern_gen false ~allow_soapp:true ~ltacvars:(ltacvar,[])
+ let c = intern_gen false ~allow_patvar:true ~ltacvars:(ltacvar,[])
sigma env c in
pattern_of_rawconstr c
diff --git a/test-suite/success/ltac.v b/test-suite/success/ltac.v
index 3f25f7035..05a6a70f3 100644
--- a/test-suite/success/ltac.v
+++ b/test-suite/success/ltac.v
@@ -175,3 +175,16 @@ Abort.
Goal True.
match None with @None => exact I end.
Abort.
+
+(* Check second-order pattern unification *)
+
+Ltac to_exist :=
+ match goal with
+ |- forall x y, @?P x y =>
+ let Q := eval lazy beta in (exists x, forall y, P x y) in
+ assert (Q->Q)
+ end.
+
+Goal forall x y : nat, x = y.
+to_exist. exact (fun H => H).
+Abort.