This PR fixes how we determine whether a function parameter is an
instance.
Previously, we relied on binder annotations (e.g., `[Ring A]` vs `{_ :
Ring A}`)
to make this determination. This is unreliable because users
legitimately use
`{..}` binders for class types when the instance is already available
from
context. For example:
```lean
structure OrdSet (α : Type) [Hashable α] [BEq α] where
...
def OrdSet.insert {_ : Hashable α} {_ : BEq α} (s : OrdSet α) (a : α) : OrdSet α :=
...
```
Here, `Hashable` and `BEq` are classes, but the `{..}` binder is
intentional, the
instances come from `OrdSet`'s parameters, so type class resolution is
unnecessary.
The fix checks the parameter's *type* using `isClass?` rather than its
syntax, and
caches this information in `FunInfo`. This affects several subsystems:
- **Discrimination trees**: instance parameters should not be indexed
even if marked with `{..}`
- **Congruence lemma generation**: instances require special treatment
- **`grind` canonicalizer**: must ensure canonical instances
**Potential regressions**: automation may now behave differently in
cases where it
previously misidentified instance parameters. For example, a rewrite
rule in `simp` that was
not firing due to incorrect indexing may now fire.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Claude <noreply@anthropic.com>
96 lines
2.1 KiB
Text
96 lines
2.1 KiB
Text
import Lean
|
||
open Lean Meta Elab Tactic
|
||
|
||
elab "sym_simp" "[" declNames:ident,* "]" : tactic => do
|
||
let rewrite ← Sym.mkSimprocFor (← declNames.getElems.mapM fun s => realizeGlobalConstNoOverload s.raw) Sym.Simp.dischargeSimpSelf
|
||
let methods : Sym.Simp.Methods := {
|
||
pre := Sym.Simp.simpControl.andThen Sym.Simp.simpArrowTelescope
|
||
post := Sym.Simp.evalGround.andThen rewrite
|
||
}
|
||
liftMetaTactic1 fun mvarId => Sym.SymM.run do
|
||
let mvarId ← Sym.preprocessMVar mvarId
|
||
(← Sym.simpGoal mvarId methods).toOption
|
||
|
||
example : (if true then a else b) = a := by
|
||
sym_simp []
|
||
|
||
example : (if True then a else b) = a := by
|
||
sym_simp []
|
||
|
||
example : (if False then a else b) = b := by
|
||
sym_simp []
|
||
|
||
/--
|
||
trace: α✝ : Sort u_1
|
||
x : α✝
|
||
p q : Prop
|
||
h : p → q
|
||
⊢ p → q
|
||
-/
|
||
#guard_msgs in
|
||
example (p q : Prop) (h : p → q) : True → p → x = x → q := by
|
||
sym_simp []
|
||
trace_state
|
||
exact h
|
||
|
||
example (p q : Prop) : q → p → True := by
|
||
sym_simp []
|
||
|
||
example (p q : Prop) : q → p → x = x := by
|
||
sym_simp []
|
||
|
||
example (q : Prop) : q → x ≠ x → True := by
|
||
sym_simp []
|
||
|
||
example (α : Type) (p : Prop) : α → p → x = x := by
|
||
sym_simp []
|
||
|
||
example (q : Prop) (α : Type) (p : Prop) : q → α → p → x = x := by
|
||
sym_simp []
|
||
|
||
example (α β : Type) (p q : Prop) : q → β → p → α → True := by
|
||
sym_simp []
|
||
|
||
/--
|
||
trace: α✝ : Sort ?u.1921
|
||
x : α✝
|
||
α : Type
|
||
p : Prop
|
||
h : α → p → True → α
|
||
⊢ α → p → True → α
|
||
-/
|
||
#guard_msgs in
|
||
example (α : Type) (p : Prop) (h : α → p → True → α) : α → p → x = x → α := by
|
||
sym_simp []
|
||
trace_state
|
||
exact h
|
||
|
||
set_option linter.unusedVariables false
|
||
|
||
/--
|
||
trace: α✝ : Sort u_1
|
||
x : α✝
|
||
α : Type
|
||
q : Prop
|
||
h : False
|
||
⊢ ∀ (a b : α), q
|
||
-/
|
||
#guard_msgs in
|
||
example (α : Type) (q : Prop) (h : False) : (a : α) → x = x → (b : α) → True → q := by
|
||
sym_simp []
|
||
trace_state
|
||
cases h
|
||
|
||
/--
|
||
trace: α✝ : Sort u_1
|
||
x : α✝
|
||
α : Type
|
||
p q : Prop
|
||
h : False
|
||
⊢ ∀ (a : α) {b : α}, q
|
||
-/
|
||
#guard_msgs in
|
||
example (α : Type) (p q : Prop) (h : False) : (a : α) → x = x → {b : α} → True → (q ∧ True) := by
|
||
sym_simp [and_true]
|
||
trace_state
|
||
cases h
|