|
1 | 1 | /- |
2 | 2 | Copyright (c) 2025 Lean FRO, LLC. All rights reserved. |
3 | 3 | Released under Apache 2.0 license as described in the file LICENSE. |
4 | | -Authors: Anne Baanen |
| 4 | +Authors: Anne Baanen, Edward van de Meent |
5 | 5 | -/ |
6 | 6 | import Mathlib.Tactic.TacticAnalysis |
7 | 7 | import Mathlib.Tactic.ExtractGoal |
@@ -183,3 +183,30 @@ def terminalToGrind : TacticAnalysis.Config where |
183 | 183 | logWarningAt stx m!"replace the proof with 'grind': {seq}" |
184 | 184 | if oldHeartbeats * 2 < newHeartbeats then |
185 | 185 | logWarningAt stx m!"'grind' is slower than the original: {oldHeartbeats} -> {newHeartbeats}" |
| 186 | + |
| 187 | +-- TODO: add compatibility with `rintro` and `intros` |
| 188 | +/-- Suggest merging two adjacent `intro` tactics which don't pattern match. -/ |
| 189 | +register_option linter.tacticAnalysis.introMerge : Bool := { |
| 190 | + defValue := true |
| 191 | +} |
| 192 | + |
| 193 | +@[tacticAnalysis linter.tacticAnalysis.introMerge, inherit_doc linter.tacticAnalysis.introMerge] |
| 194 | +def introMerge : TacticAnalysis.Config := .ofComplex { |
| 195 | + out := Option (TSyntax `tactic) |
| 196 | + ctx := Array (Array Term) |
| 197 | + trigger ctx stx := |
| 198 | + match stx with |
| 199 | + | `(tactic| intro%$x $args*) => .continue ((ctx.getD #[]).push |
| 200 | + -- if `intro` is used without arguments, treat it as `intro _` |
| 201 | + <| if args.size = 0 then #[⟨mkHole x⟩] else args) |
| 202 | + | _ => if let some args := ctx then if args.size > 1 then .accept args else .skip else .skip |
| 203 | + test ctx goal := do |
| 204 | + let ctxT := ctx.flatten |
| 205 | + let tac ← `(tactic| intro $ctxT*) |
| 206 | + try |
| 207 | + let _ ← Lean.Elab.runTactic goal tac |
| 208 | + return some tac |
| 209 | + catch _e => -- if for whatever reason we can't run `intro` here. |
| 210 | + return none |
| 211 | + tell _stx _old _oldHeartbeats new _newHeartbeats := |
| 212 | + if let some tac := new then m!"Try this: {tac}" else none} |
0 commit comments