This PR adds a linter (`linter.unusedSimpArgs`) that complains when a simp argument (`simp [foo]`) is unused. It should do the right thing if the `simp` invocation is run multiple times, e.g. inside `all_goals`. It does not trigger when the `simp` call is inside a macro. The linter message contains a clickable hint to remove the simp argument. I chose to display a separate warning for each unused argument. This means that the user has to click multiple times to remove all of them (and wait for re-elaboration in between). But this just means multiple endorphine kicks, and the main benefit over a single warning that would have to span the whole argument list is that already the squigglies tell the users about unused arguments. This closes #4483. Making Init and Std clean wrt to this linter revealed close to 1000 unused simp args, a pleasant experience for anyone enjoying tidying things: #8905
147 lines
2.4 KiB
Text
147 lines
2.4 KiB
Text
/-!
|
||
This test should catch intentional or accidental changes to how projections are rewritten by
|
||
various tactics
|
||
-/
|
||
|
||
structure S where
|
||
proj : Nat
|
||
|
||
variable (P : Nat → Prop)
|
||
|
||
section structure_abstract
|
||
|
||
variable (s : S)
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
s : S
|
||
⊢ P s.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (s.proj) := by
|
||
rw [S.proj]
|
||
-- Cannot use
|
||
-- guard_target =ₛ P s.1
|
||
-- here as, as that elaborates as `P s.proj`
|
||
fail
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
s : S
|
||
⊢ P s.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (s.proj) := by
|
||
unfold S.proj
|
||
fail
|
||
|
||
/-- error: simp made no progress -/
|
||
#guard_msgs in
|
||
example : P (s.proj) := by
|
||
simp [S.proj]
|
||
fail
|
||
|
||
end structure_abstract
|
||
|
||
section structure_concrete
|
||
|
||
variable (n : Nat)
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
n : Nat
|
||
⊢ P { proj := n }.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (S.proj ⟨n⟩) := by rw [S.proj]; fail
|
||
-- Cannot use
|
||
-- guard_target =ₛ P s.1
|
||
-- here as, as that elaborates as `P s.proj`
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
n : Nat
|
||
⊢ P { proj := n }.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (S.proj ⟨n⟩) := by unfold S.proj; fail
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
n : Nat
|
||
⊢ P n
|
||
-/
|
||
#guard_msgs in
|
||
set_option linter.unusedSimpArgs false in
|
||
example : P (S.proj ⟨n⟩) := by simp [S.proj]; fail -- NB: reduces the projectino
|
||
|
||
end structure_concrete
|
||
|
||
class C (α : Type) where
|
||
meth : Nat
|
||
|
||
section class_abstract
|
||
|
||
instance : C Bool where
|
||
meth := 42
|
||
|
||
variable (α : Type) [C α]
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
α : Type
|
||
inst✝ : C α
|
||
⊢ P inst✝.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (C.meth α) := by rw [C.meth]; fail
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
α : Type
|
||
inst✝ : C α
|
||
⊢ P inst✝.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (C.meth α) := by unfold C.meth; fail
|
||
|
||
/-- error: simp made no progress -/
|
||
#guard_msgs in
|
||
example : P (C.meth α) := by simp [C.meth]; fail
|
||
|
||
end class_abstract
|
||
|
||
section class_concrete
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
⊢ P instCBool.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (C.meth Bool) := by rw [C.meth]; fail
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
⊢ P instCBool.1
|
||
-/
|
||
#guard_msgs in
|
||
example : P (C.meth Bool) := by unfold C.meth; fail
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
P : Nat → Prop
|
||
⊢ P 42
|
||
-/
|
||
#guard_msgs in
|
||
example : P (C.meth Bool) := by simp [C.meth]; fail -- NB: Unfolds the instance `instCBool`!
|
||
|
||
|
||
end class_concrete
|