Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: grind parameter issues and configuration #6686

Merged
merged 3 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Lean/Declaration.lean
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,10 @@ def isInductive : ConstantInfo → Bool
| .inductInfo _ => true
| _ => false

def isDefinition : ConstantInfo → Bool
| .defnInfo _ => true
| _ => false

def isTheorem : ConstantInfo → Bool
| .thmInfo _ => true
| _ => false
Expand Down
24 changes: 18 additions & 6 deletions src/Lean/Elab/Tactic/Grind.lean
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,25 @@ def elabGrindParams (params : Grind.Params) (ps : TSyntaxArray ``Parser.Tactic.
let kind ← if let some mod := mod? then Grind.getTheoremKindCore mod else pure .default
if (← isInductivePredicate declName) then
throwErrorAt p "NIY"
else if (← getConstInfo declName).isTheorem then
params := { params with extra := params.extra.push (← Grind.mkEMatchTheoremForDecl declName kind) }
else if let some eqns ← getEqnsFor? declName then
for eqn in eqns do
params := { params with extra := params.extra.push (← Grind.mkEMatchTheoremForDecl eqn kind) }
else
throwError "invalid `grind` parameter, `{declName}` is not a theorem, definition, or inductive type"
let info ← getConstInfo declName
match info with
| .thmInfo _ =>
if kind == .eqBoth then
params := { params with extra := params.extra.push (← Grind.mkEMatchTheoremForDecl declName .eqLhs) }
params := { params with extra := params.extra.push (← Grind.mkEMatchTheoremForDecl declName .eqRhs) }
else
params := { params with extra := params.extra.push (← Grind.mkEMatchTheoremForDecl declName kind) }
| .defnInfo _ =>
if (← isReducible declName) then
throwErrorAt p "`{declName}` is a reducible definition, `grind` automatically unfolds them"
if kind != .eqLhs && kind != .default then
throwErrorAt p "invalid `grind` parameter, `{declName}` is a definition, the only acceptable (and redundant) modifier is '='"
let some thms ← Grind.mkEMatchEqTheoremsForDef? declName
| throwErrorAt p "failed to genereate equation theorems for `{declName}`"
params := { params with extra := params.extra ++ thms.toPArray' }
| _ =>
throwErrorAt p "invalid `grind` parameter, `{declName}` is not a theorem, definition, or inductive type"
| _ => throwError "unexpected `grind` parameter{indentD p}"
return params

Expand Down
2 changes: 2 additions & 0 deletions src/Lean/Meta/Tactic/Grind.lean
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ builtin_initialize registerTraceClass `grind.debug.split
builtin_initialize registerTraceClass `grind.debug.canon
builtin_initialize registerTraceClass `grind.debug.offset
builtin_initialize registerTraceClass `grind.debug.offset.proof
builtin_initialize registerTraceClass `grind.debug.ematch.pattern

end Lean
26 changes: 16 additions & 10 deletions src/Lean/Meta/Tactic/Grind/EMatchTheorem.lean
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,9 @@ def mkEMatchEqTheoremCore (origin : Origin) (levelParams : Array Name) (proof :
| HEq _ lhs _ rhs => pure (lhs, rhs)
| _ => throwError "invalid E-matching equality theorem, conclusion must be an equality{indentExpr type}"
let pat := if useLhs then lhs else rhs
trace[grind.debug.ematch.pattern] "mkEMatchEqTheoremCore: origin: {← origin.pp}, pat: {pat}, useLhs: {useLhs}"
let pat ← preprocessPattern pat normalizePattern
trace[grind.debug.ematch.pattern] "mkEMatchEqTheoremCore: after preprocessing: {pat}, {← normalize pat}"
let pats := splitWhileForbidden (pat.abstract xs)
return (xs.size, pats)
mkEMatchTheoremCore origin levelParams numParams proof patterns
Expand Down Expand Up @@ -651,9 +653,9 @@ private def collectPatterns? (proof : Expr) (xs : Array Expr) (searchPlaces : Ar

def mkEMatchTheoremWithKind? (origin : Origin) (levelParams : Array Name) (proof : Expr) (kind : TheoremKind) : MetaM (Option EMatchTheorem) := do
if kind == .eqLhs then
return (← mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := false) (useLhs := true))
return (← mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := true) (useLhs := true))
else if kind == .eqRhs then
return (← mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := false) (useLhs := false))
return (← mkEMatchEqTheoremCore origin levelParams proof (normalizePattern := true) (useLhs := false))
let type ← inferType proof
forallTelescopeReducing type fun xs type => do
let searchPlaces ← match kind with
Expand Down Expand Up @@ -694,22 +696,26 @@ def getTheoremKindFromOpt (stx : Syntax) : CoreM TheoremKind := do
else
getTheoremKindCore stx[1][0]

def mkEMatchTheoremForDecl (declName : Name) (thmKind : TheoremKind) : MetaM EMatchTheorem := do
let some thm ← mkEMatchTheoremWithKind? (.decl declName) #[] (← getProofFor declName) thmKind
| throwError "`@{thmKind.toAttribute} theorem {declName}` {thmKind.explainFailure}, consider using different options or the `grind_pattern` command"
return thm

def mkEMatchEqTheoremsForDef? (declName : Name) : MetaM (Option (Array EMatchTheorem)) := do
let some eqns ← getEqnsFor? declName | return none
eqns.mapM fun eqn => do
mkEMatchEqTheorem eqn (normalizePattern := true)

private def addGrindEqAttr (declName : Name) (attrKind : AttributeKind) (thmKind : TheoremKind) (useLhs := true) : MetaM Unit := do
if (← getConstInfo declName).isTheorem then
ematchTheoremsExt.add (← mkEMatchEqTheorem declName (normalizePattern := true) (useLhs := useLhs)) attrKind
else if let some eqnsgetEqnsFor? declName then
else if let some thmsmkEMatchEqTheoremsForDef? declName then
unless useLhs do
throwError "`{declName}` is a definition, you must only use the left-hand side for extracting patterns"
for eqn in eqns do
ematchTheoremsExt.add (← mkEMatchEqTheorem eqn) attrKind
thms.forM (ematchTheoremsExt.add · attrKind)
else
throwError s!"`{thmKind.toAttribute}` attribute can only be applied to equational theorems or function definitions"

def mkEMatchTheoremForDecl (declName : Name) (thmKind : TheoremKind) : MetaM EMatchTheorem := do
let some thm ← mkEMatchTheoremWithKind? (.decl declName) #[] (← getProofFor declName) thmKind
| throwError "`@{thmKind.toAttribute} theorem {declName}` {thmKind.explainFailure}, consider using different options or the `grind_pattern` command"
return thm

private def addGrindAttr (declName : Name) (attrKind : AttributeKind) (thmKind : TheoremKind) : MetaM Unit := do
if thmKind == .eqLhs then
addGrindEqAttr declName attrKind thmKind (useLhs := true)
Expand Down
18 changes: 17 additions & 1 deletion src/Lean/Meta/Tactic/Grind/SimpUtil.lean
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,30 @@ prelude
import Lean.Meta.Tactic.Simp.Simproc
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.DoNotSimp
import Lean.Meta.Tactic.Simp.BuiltinSimprocs.List

namespace Lean.Meta.Grind

/-- Returns the array of simprocs used by `grind`. -/
protected def getSimprocs : MetaM (Array Simprocs) := do
let s ← grindNormSimprocExt.getSimprocs
let s ← addDoNotSimp s
return #[s, (← Simp.getSEvalSimprocs)]
let e ← Simp.getSEvalSimprocs
/-
We don't want to apply `List.reduceReplicate` as a normalization operation in
`grind`. Consider the following example:
```
example (ys : List α) : n = 0 → List.replicate n ys = [] := by
grind only [List.replicate]
```
The E-matching module generates the following instance for `List.replicate.eq_1`
```
List.replicate 0 [] = []
```
We don't want it to be simplified to `[] = []`.
-/
let e := e.erase ``List.reduceReplicate
return #[s, e]

/-- Returns the simplification context used by `grind`. -/
protected def getSimpContext : MetaM Simp.Context := do
Expand Down
48 changes: 48 additions & 0 deletions tests/lean/run/grind_ematch_patterns.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
def replicate : (n : Nat) → (a : α) → List α
| 0, _ => []
| n+1, a => a :: replicate n a

/--
info: [grind.ematch.pattern] replicate.eq_1: [@replicate #1 `[0] #0]
[grind.ematch.pattern] replicate.eq_2: [@replicate #2 (Lean.Grind.offset #0 (1)) #1]
-/
#guard_msgs (info) in
set_option trace.grind.ematch.pattern true in
attribute [grind] replicate

example : ys = [] → replicate 0 [] = ys := by
grind only [replicate]

/--
error: invalid `grind` parameter, `replicate` is a definition, the only acceptable (and redundant) modifier is '='
-/
#guard_msgs (error) in
example : ys = [] → replicate 0 [] = ys := by
grind only [←replicate]

example : ys = [] → replicate 0 [] = ys := by
fail_if_success grind only
sorry

example (ys : List α) : n = 0 → replicate n ys = [] := by
grind only [replicate]

example (ys : List α) : n = 0 → List.replicate n ys = [] := by
grind only [List.replicate]

opaque foo : Nat → Nat
opaque bla : Nat → Nat

theorem foo_bla : foo x = bla x := sorry

example : foo x = bla x := by
grind only [_=_ foo_bla]

@[reducible] def inc (_ : Nat) := 1

/--
error: `inc` is a reducible definition, `grind` automatically unfolds them
-/
#guard_msgs (error) in
example : a = 1 → inc x = a := by
grind [inc]
Loading