Search code examples
coqcoq-tactic

Match context pattern inside a tactic/tactic notation


I find a pattern inside my goal through a tactic.

Why does this fail:

        Tactic Notation "my_context_match" uconstr(g) :=
          match goal with
          | |- context[g] => idtac
          end.

          my_context_match _.

While this succeeds?

        match goal with
          | |- context[_] => idtac
        end.

Is there any way to write a my_context_match, such that I can pass incomplete patterns (with _ on them) and see if anything inside my goal matches the patter?


Solution

  • Support for uconstr is very patchy. I've just reported #9321. Note that even this fails:

    Goal True.
      let v := uconstr:(True) in
      lazymatch constr:(v) with
      | v => idtac
      end. (* Error: No matching clauses for match. *)
    

    As suggested by @eponier in a comment, you can use open_constr instead of uconstr. However, this will leave unresolved evars. Here is a tactic that will work, and will not leave unresolved evars:

    Tactic Notation "my_context_match" uconstr(g) :=
      (* [match] does not support [uconstr], cf COQBUG(https://github.com/coq/coq/issues/9321),
         so we use [open_constr] *)
      let g := open_constr:(g) in
      (* turning [g] into an [open_constr] creates new evars, so we must
         eventually unify them with the goal *)
      let G := match goal with |- ?G => G end in
      (* We now search for [g] in the goal, and then replace the matching
         subterm with the [open_constr] [g], so that we can unify the
         result with the goal [G] to resolve the new evars we created *)
      match G with
      | context cG[g]
        => let G' := context cG[g] in
           unify G G'
      end.
    
    Goal True /\ True.
      my_context_match _.
      my_context_match (_ /\ _).
      Fail my_context_match (_ \/ _).
      my_context_match True.
      exact (conj I I).
    Qed.