Zulip Chat Archive

Stream: lean4

Topic: Strange linter behaviour


IntGrah (Feb 02 2026 at 02:58):

I get a discrepancy with linter behaviour after adding seemingly innocuous parentheses.

import Mathlib.Tactic.Linter.UnusedTactic

def foo (n : Nat) : Option (Fin (0 + n + 1)) := some n, by omega

/-- warning:
'simpa only [Nat.zero_add] using ← foo n' tactic does nothing

Note: This linter can be disabled with `set_option linter.unusedTactic false`
-/
#guard_msgs in
def bad (n : Nat) : Option (Fin (n + 1)) := do
  return by simpa only [Nat.zero_add] using  foo n

def good (n : Nat) : Option (Fin (n + 1)) := do
  return by simpa only [Nat.zero_add] using ( foo n)

The cause seems to be that the "← foo n" is getting lifted out

  let __foo_n  foo n
  return by simpa only [Nat.zero_add] using __foo_n

and the simpa tactic source span isn't taking ownership of the synthetic __foo_n, causing the linter to see a broken simpa. Whereas with the parentheses, there is still some original syntax, and everything works.
I looked at the linter and it seems to rely on source spans. Is the bug in the linter, or in the elaborator?

IntGrah (Feb 02 2026 at 03:08):

I'm able to silence the error by editing
src/Lean/Elab/Do/Legacy.lean,
replacing line 1340

      let id  mkIdentFromRef (.num baseId ( get).length)

with

      let id := mkIdentFrom term (.num baseId ( get).length) (canonical := true)

IntGrah (Feb 06 2026 at 09:48):

issue is still open, as the above message is only my guess of a solution hack


Last updated: Feb 28 2026 at 14:05 UTC