Zulip Chat Archive

Stream: lean4

Topic: optConfig causes tactics to be ignored


Eric Wieser (Feb 02 2026 at 03:01):

Something fishy is going on here (minimized from #new members > Wall of warnings of `unreachableTactic`/`unusedTactic` to be Mathlib free):

module

public meta import Lean.Elab.Eval
public meta import Lean.Elab.Tactic.ElabTerm

public meta section

open Lean Parser Meta Elab Tactic Term

/-- Elaborator for the configuration in `apply (config := cfg)` syntax. -/
declare_config_elab elabApplyConfig ApplyConfig

@[tactic_alt Lean.Parser.Tactic.apply]
elab (name := applyWith) "apply" cfg:optConfig ppSpace e:term : tactic => do
  let cfg  elabApplyConfig cfg
  evalApplyLikeTactic (·.apply · cfg) e


def MyProp (n : Nat) : Prop := n = n

theorem MyProp.mk (n : Nat) : MyProp n := by rw [MyProp]

-- this emits a warning that sorry was used, but no errors
theorem foo : MyProp 1337 := by
  apply MyProp.mk "foo"
  exact "qed"

Anne Baanen (Feb 02 2026 at 10:00):

I don't think it's optConfig that causes the issue: replacing cfg with {} still results in an error about sorry, while replacing evalApplyLikeTactic with throwErrorAt e "error'd" does show an error in the infobar.

Anne Baanen (Feb 02 2026 at 10:04):

In fact, replacing the applyWith code with an identical copy of the original apply code results in the same:

module

public meta import Lean.Elab.Eval
public meta import Lean.Elab.Tactic.ElabTerm

public meta section

open Lean Parser Meta Elab Tactic Term

/-- Elaborator for the configuration in `apply (config := cfg)` syntax. -/
declare_config_elab elabApplyConfig ApplyConfig

elab "apply" t:term : tactic => do
  evalApplyLikeTactic (fun g e => g.apply e (term? := some m!"`{e}`")) t

def MyProp (n : Nat) : Prop := n = n

theorem MyProp.mk (n : Nat) : MyProp n := by rw [MyProp]

-- this emits a warning that sorry was used, but no errors
theorem foo : MyProp 1337 := by
  apply MyProp.mk "foo"
  exact "qed"

Anne Baanen (Feb 02 2026 at 10:05):

I suspect this is caused by the two variants having overlapping parsers: I don't know exactly how this works but I recall if multiple parses apply to the same tactic syntax, they are each tried in turn until one succeeds. (And apparently there is no error reporting done upon failure?)

Thomas Murrills (Feb 02 2026 at 11:02):

Interestingly, if you look at the infotrees, only the original syntax is ever actually elaborated. I guess it’s “succeeding” via errToSorry when it shouldn’t; maybe there’s a missing withoutErrToSorry near the backtracking logic used for choice nodes (like observing?)?

Anne Baanen (Feb 02 2026 at 12:13):

Indeed if I make the syntax non-overlapping the expected error occurs. So let's use that as the fix in Mathlib for now:

module

public meta import Lean.Elab.Eval
public meta import Lean.Elab.Tactic.ElabTerm

public meta section

open Lean Parser Meta Elab Tactic Term

/-- Elaborator for the configuration in `apply (config := cfg)` syntax. -/
declare_config_elab elabApplyConfig ApplyConfig

/-- At least one configuration option for tactics.

`optConfig` allows zero or more, `manyConfig` requires at least one.
 -/
syntax manyConfig := (colGt configItem)+

@[tactic_alt Lean.Parser.Tactic.apply]
elab (name := applyWith) "apply" cfg:manyConfig ppSpace e:term : tactic => do
  let cfg  elabApplyConfig cfg
  evalApplyLikeTactic (·.apply · cfg) e

def MyProp (n : Nat) : Prop := n = n

theorem MyProp.mk (n : Nat) : MyProp n := by rw [MyProp]

/--
error: Application type mismatch: The argument
  "foo"
has type
  String
but is expected to have type
  Nat
in the application
  MyProp.mk "foo"
-/
#guard_msgs in
theorem foo : MyProp 1337 := by
  apply MyProp.mk "foo"
  exact "qed"

Anne Baanen (Feb 02 2026 at 12:18):

Workaround in #34721.

Anne Baanen (Feb 09 2026 at 15:42):

I reported the lack of error message as a Lean bug: lean4#12394


Last updated: Feb 28 2026 at 14:05 UTC