feat: track type class inference time in grind (#9211)

This commit is contained in:
Leonardo de Moura 2025-07-05 13:24:32 -07:00 committed by GitHub
parent 38d4dc7058
commit 2cf6c2ddc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 125 additions and 108 deletions

View file

@ -775,7 +775,7 @@ private def cacheResult (cacheKey : SynthInstanceCacheKey) (abstResult? : Option
else
modify fun s => { s with cache.synthInstance := s.cache.synthInstance.insert cacheKey (some abstResult) }
def synthInstance? (type : Expr) (maxResultSize? : Option Nat := none) : MetaM (Option Expr) := do profileitM Exception "typeclass inference" (← getOptions) (decl := type.getAppFn.constName?.getD .anonymous) do
def synthInstanceCore? (type : Expr) (maxResultSize? : Option Nat := none) : MetaM (Option Expr) := do
let opts ← getOptions
let maxResultSize := maxResultSize?.getD (synthInstance.maxSize.get opts)
withTraceNode `Meta.synthInstance
@ -801,6 +801,9 @@ def synthInstance? (type : Expr) (maxResultSize? : Option Nat := none) : MetaM (
cacheResult cacheKey abstResult? result?
return result?
def synthInstance? (type : Expr) (maxResultSize? : Option Nat := none) : MetaM (Option Expr) := do profileitM Exception "typeclass inference" (← getOptions) (decl := type.getAppFn.constName?.getD .anonymous) do
synthInstanceCore? type maxResultSize?
/--
Return `LOption.some r` if succeeded, `LOption.none` if it failed, and `LOption.undef` if
instance cannot be synthesized right now because `type` contains metavariables. -/

View file

@ -33,6 +33,7 @@ import Lean.Meta.Tactic.Grind.MBTC
import Lean.Meta.Tactic.Grind.Lookahead
import Lean.Meta.Tactic.Grind.LawfulEqCmp
import Lean.Meta.Tactic.Grind.ReflCmp
import Lean.Meta.Tactic.Grind.SynthInstance
namespace Lean

View file

@ -7,6 +7,8 @@ prelude
import Init.Grind.Ring.Field
import Init.Grind.Ring.Envelope
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.SynthInstance
import Lean.Meta.Tactic.Grind.Arith.Insts
import Lean.Meta.Tactic.Grind.Arith.CommRing.Util
namespace Lean.Meta.Grind.Arith.CommRing
@ -23,16 +25,12 @@ def denoteNumCore (u : Level) (type : Expr) (semiringInst : Expr) (negFn : Expr)
private def internalizeFn (fn : Expr) : GoalM Expr := do
shareCommon (← canon fn)
private def getUnaryFn (type : Expr)(u : Level) (instDeclName : Name) (declName : Name) : GoalM Expr := do
let instType := mkApp (mkConst instDeclName [u]) type
let .some inst ← trySynthInstance instType
| throwError "`grind ring` failed to find instance{indentExpr instType}"
private def getUnaryFn (type : Expr) (u : Level) (instDeclName : Name) (declName : Name) : GoalM Expr := do
let inst ← synthInstance <| mkApp (mkConst instDeclName [u]) type
internalizeFn <| mkApp2 (mkConst declName [u]) type inst
private def getBinHomoFn (type : Expr)(u : Level) (instDeclName : Name) (declName : Name) : GoalM Expr := do
let instType := mkApp3 (mkConst instDeclName [u, u, u]) type type type
let .some inst ← trySynthInstance instType
| throwError "`grind ring` failed to find instance{indentExpr instType}"
private def getBinHomoFn (type : Expr) (u : Level) (instDeclName : Name) (declName : Name) : GoalM Expr := do
let inst ← synthInstance <| mkApp3 (mkConst instDeclName [u, u, u]) type type type
internalizeFn <| mkApp4 (mkConst declName [u, u, u]) type type type inst
-- Remark: we removed consistency checks such as the one that ensures `HAdd` instance matches `Semiring.toAdd`
@ -57,9 +55,7 @@ private def getInvFn (type : Expr) (u : Level) : GoalM Expr := do
getUnaryFn type u ``Inv ``Inv.inv
private def getPowFn (type : Expr) (u : Level) (semiringInst : Expr) : GoalM Expr := do
let instType := mkApp3 (mkConst ``HPow [u, 0, u]) type Nat.mkType type
let .some inst ← trySynthInstance instType |
throwError "failed to find instance for ring power operator{indentExpr instType}"
let inst ← synthInstance <| mkApp3 (mkConst ``HPow [u, 0, u]) type Nat.mkType type
let inst' := mkApp2 (mkConst ``Grind.Semiring.toHPow [u]) type semiringInst
unless (← withDefault <| isDefEq inst inst') do
throwError "instance for power operator{indentExpr inst}\nis not definitionally equal to the `Grind.Semiring` one{indentExpr inst'}"
@ -74,7 +70,7 @@ private def getIntCastFn (type : Expr) (u : Level) (ringInst : Expr) : GoalM Exp
-- does not guarantee that an `IntCast α` will be available.
-- When both are present we verify that they are defeq,
-- and otherwise fall back to the field of the `Ring α` instance that we already have.
let inst ← match (← trySynthInstance instType).toOption with
let inst ← match (← synthInstance? instType) with
| none => pure inst'
| some inst =>
unless (← withDefault <| isDefEq inst inst') do
@ -91,7 +87,7 @@ private def getNatCastFn (type : Expr) (u : Level) (semiringInst : Expr) : GoalM
-- does not guarantee that an `NatCast α` will be available.
-- When both are present we verify that they are defeq,
-- and otherwise fall back to the field of the `Semiring α` instance that we already have.
let inst ← match (← trySynthInstance instType).toOption with
let inst ← match (← synthInstance? instType) with
| none => pure inst'
| some inst =>
unless (← withDefault <| isDefEq inst inst') do
@ -121,20 +117,16 @@ def getRingId? (type : Expr) : GoalM (Option Nat) := do
where
go? : GoalM (Option Nat) := do
let u ← getDecLevel type
let semiring := mkApp (mkConst ``Grind.Semiring [u]) type
let .some semiringInst ← trySynthInstance semiring | return none
let ring := mkApp (mkConst ``Grind.Ring [u]) type
let .some ringInst ← trySynthInstance ring | return none
let commSemiring := mkApp (mkConst ``Grind.CommSemiring [u]) type
let .some commSemiringInst ← trySynthInstance commSemiring | return none
let commRing := mkApp (mkConst ``Grind.CommRing [u]) type
let .some commRingInst ← trySynthInstance commRing | return none
let some commRingInst ← synthInstance? commRing | return none
let ringInst := mkApp2 (mkConst ``Grind.CommRing.toRing [u]) type commRingInst
let semiringInst := mkApp2 (mkConst ``Grind.Ring.toSemiring [u]) type ringInst
let commSemiringInst := mkApp2 (mkConst ``Grind.CommRing.toCommSemiring [u]) type semiringInst
trace_goal[grind.ring] "new ring: {type}"
let charInst? ← getIsCharInst? u type semiringInst
let noZeroDivInst? ← getNoZeroDivInst? u type
trace_goal[grind.ring] "NoNatZeroDivisors available: {noZeroDivInst?.isSome}"
let field := mkApp (mkConst ``Grind.Field [u]) type
let fieldInst? : Option Expr ← LOption.toOption <$> trySynthInstance field
let fieldInst? ← synthInstance? <| mkApp (mkConst ``Grind.Field [u]) type
let addFn ← getAddFn type u
let mulFn ← getMulFn type u
let subFn ← getSubFn type u
@ -169,19 +161,18 @@ def getSemiringId? (type : Expr) : GoalM (Option Nat) := do
where
go? : GoalM (Option Nat) := do
let u ← getDecLevel type
let semiring := mkApp (mkConst ``Grind.Semiring [u]) type
let .some semiringInst ← trySynthInstance semiring | return none
let commSemiring := mkApp (mkConst ``Grind.CommSemiring [u]) type
let .some commSemiringInst ← trySynthInstance commSemiring | return none
let some commSemiringInst ← synthInstance? commSemiring | return none
let semiringInst := mkApp2 (mkConst ``Grind.CommSemiring.toSemiring [u]) type commSemiringInst
let toQFn ← internalizeFn <| mkApp2 (mkConst ``Grind.Ring.OfSemiring.toQ [u]) type semiringInst
let addFn ← getAddFn type u
let mulFn ← getMulFn type u
let powFn ← getPowFn type u semiringInst
let natCastFn ← getNatCastFn type u semiringInst
let add := mkApp (mkConst ``Add [u]) type
let .some addInst ← trySynthInstance add | return none
let some addInst ← synthInstance? add | return none
let addRightCancel := mkApp2 (mkConst ``Grind.AddRightCancel [u]) type addInst
let addRightCancelInst? ← LOption.toOption <$> trySynthInstance addRightCancel
let addRightCancelInst? ← synthInstance? addRightCancel
let q ← shareCommon (← canon (mkApp2 (mkConst ``Grind.Ring.OfSemiring.Q [u]) type semiringInst))
let some ringId ← getRingId? q
| throwError "`grind` unexpected failure, failure to initialize ring{indentExpr q}"

View file

@ -5,6 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Grind.ToIntLemmas
import Lean.Meta.Tactic.Grind.SynthInstance
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.Arith.Cutsat.Util
@ -20,38 +21,38 @@ private def checkDecl (declName : Name) : MetaM Unit := do
unless (← getEnv).contains declName do
throwMissingDecl declName
private def mkOfNatThm? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) : MetaM (Option Expr) := do
private def mkOfNatThm? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) : GoalM (Option Expr) := do
-- ∀ n, OfNat α n
let ofNat := mkForall `n .default (mkConst ``Nat) (mkApp2 (mkConst ``OfNat [u]) type (mkBVar 0))
let .some ofNatInst ← trySynthInstance ofNat
let some ofNatInst ← synthInstance? ofNat
| reportMissingToIntAdapter type ofNat; return none
let toIntOfNat := mkApp4 (mkConst ``Grind.ToInt.OfNat [u]) type ofNatInst rangeExpr toIntInst
let .some toIntOfNatInst ← trySynthInstance toIntOfNat
let some toIntOfNatInst ← synthInstance? toIntOfNat
| reportMissingToIntAdapter type toIntOfNat; return none
return mkApp5 (mkConst ``Grind.ToInt.ofNat_eq [u]) type rangeExpr toIntInst ofNatInst toIntOfNatInst
/-- Helper function for `mkSimpleOpThm?` and `mkPowThm?` -/
private def mkSimpleOpThmCore? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) (op : Expr) (opSuffix : Name) (thmName : Name) : MetaM (Option Expr) := do
let .some opInst ← trySynthInstance op | return none
private def mkSimpleOpThmCore? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) (op : Expr) (opSuffix : Name) (thmName : Name) : GoalM (Option Expr) := do
let some opInst ← synthInstance? op | return none
let toIntOpName := ``Grind.ToInt ++ opSuffix
checkDecl toIntOpName
let toIntOp := mkApp4 (mkConst toIntOpName [u]) type opInst rangeExpr toIntInst
let .some toIntOpInst ← trySynthInstance toIntOp
let some toIntOpInst ← synthInstance? toIntOp
| reportMissingToIntAdapter type toIntOp; return none
checkDecl thmName
return mkApp5 (mkConst thmName [u]) type rangeExpr toIntInst opInst toIntOpInst
/-- Simpler version of `mkBinOpThms` for operators that have only one congruence theorem. -/
private def mkSimpleOpThm? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) (opBaseName : Name) (thmName : Name) : MetaM (Option Expr) := do
private def mkSimpleOpThm? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) (opBaseName : Name) (thmName : Name) : GoalM (Option Expr) := do
let op := mkApp (mkConst opBaseName [u]) type
mkSimpleOpThmCore? type u toIntInst rangeExpr op opBaseName thmName
/-- Simpler version of `mkBinOpThms` for operators that have only one congruence theorem. -/
private def mkPowThm? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) : MetaM (Option Expr) := do
private def mkPowThm? (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) : GoalM (Option Expr) := do
let op := mkApp3 (mkConst ``HPow [u, 0, u]) type Nat.mkType type
mkSimpleOpThmCore? type u toIntInst rangeExpr op `Pow ``Grind.ToInt.pow_congr
private def mkBinOpThms (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) (range : Grind.IntInterval) (opBaseName : Name) (thmName : Name) : MetaM ToIntThms := do
private def mkBinOpThms (type : Expr) (u : Level) (toIntInst : Expr) (rangeExpr : Expr) (range : Grind.IntInterval) (opBaseName : Name) (thmName : Name) : GoalM ToIntThms := do
let some c ← mkSimpleOpThm? type u toIntInst rangeExpr opBaseName thmName | return {}
let opInst := c.appFn!.appArg!
let toIntOpInst := c.appArg!
@ -113,7 +114,7 @@ where
let some u ← decLevel? u' | return none
let rangeExpr ← mkFreshExprMVar (mkConst ``Grind.IntInterval)
let toIntType := mkApp2 (mkConst ``Grind.ToInt [u]) type rangeExpr
let .some toIntInst ← trySynthInstance toIntType |
let some toIntInst ← synthInstance? toIntType |
trace[grind.debug.cutsat.toInt] "failed to synthesize {indentExpr toIntType}"
return none
let rangeExpr ← instantiateMVars rangeExpr
@ -128,18 +129,18 @@ where
let ofDiseq := mkApp3 (mkConst ``Grind.ToInt.of_diseq [u]) type rangeExpr toIntInst
let (ofLE?, ofNotLE?) ← do
let toLE := mkApp (mkConst ``LE [u]) type
let .some leInst ← LOption.toOption <$> trySynthInstance toLE | pure (none, none)
let some leInst ← synthInstance? toLE | pure (none, none)
let toIntLE := mkApp4 (mkConst ``Grind.ToInt.LE [u]) type leInst rangeExpr toIntInst
let .some toIntLEInst ← LOption.toOption <$> trySynthInstance toIntLE
let some toIntLEInst ← synthInstance? toIntLE
| reportMissingToIntAdapter type toIntLE; pure (none, none)
let ofLE := mkApp5 (mkConst ``Grind.ToInt.of_le [u]) type rangeExpr toIntInst leInst toIntLEInst
let ofNotLE := mkApp5 (mkConst ``Grind.ToInt.of_not_le [u]) type rangeExpr toIntInst leInst toIntLEInst
pure (some ofLE, some ofNotLE)
let (ofLT?, ofNotLT?) ← do
let toLT := mkApp (mkConst ``LT [u]) type
let .some ltInst ← LOption.toOption <$> trySynthInstance toLT | pure (none, none)
let some ltInst ← synthInstance? toLT | pure (none, none)
let toIntLT := mkApp4 (mkConst ``Grind.ToInt.LT [u]) type ltInst rangeExpr toIntInst
let .some toIntLTInst ← LOption.toOption <$> trySynthInstance toIntLT
let some toIntLTInst ← synthInstance? toIntLT
| reportMissingToIntAdapter type toIntLT; pure (none, none)
let ofLT := mkApp5 (mkConst ``Grind.ToInt.of_lt [u]) type rangeExpr toIntInst ltInst toIntLTInst
let ofNotLT := mkApp5 (mkConst ``Grind.ToInt.of_not_lt [u]) type rangeExpr toIntInst ltInst toIntLTInst

View file

@ -0,0 +1,26 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.Tactic.Grind.SynthInstance
namespace Lean.Meta.Grind.Arith
def getIsCharInst? (u : Level) (type : Expr) (semiringInst : Expr) : GoalM (Option (Expr × Nat)) := do withNewMCtxDepth do
let n ← mkFreshExprMVar (mkConst ``Nat)
let charType := mkApp3 (mkConst ``Grind.IsCharP [u]) type semiringInst n
let some charInst ← synthInstance? charType | pure none
let n ← instantiateMVars n
let some n ← evalNat n |>.run
| pure none
pure <| some (charInst, n)
def getNoZeroDivInst? (u : Level) (type : Expr) : GoalM (Option Expr) := do
let hmulType := mkApp3 (mkConst ``HMul [0, u, u]) (mkConst ``Nat []) type type
let some hmulInst ← synthInstance? hmulType | return none
let noZeroDivType := mkApp2 (mkConst ``Grind.NoNatZeroDivisors [u]) type hmulInst
synthInstance? noZeroDivType
end Lean.Meta.Grind.Arith

View file

@ -6,6 +6,7 @@ Authors: Leonardo de Moura
prelude
import Init.Grind.Ordered.Module
import Lean.Meta.Tactic.Grind.Simp
import Lean.Meta.Tactic.Grind.SynthInstance
import Lean.Meta.Tactic.Grind.Arith.Cutsat.ToInt
import Lean.Meta.Tactic.Grind.Arith.CommRing.RingId
import Lean.Meta.Tactic.Grind.Arith.Linear.Util
@ -75,28 +76,15 @@ where
go? : GoalM (Option Nat) := do
let u ← getDecLevel type
let rec getInst? (declName : Name) : GoalM (Option Expr) := do
let instType := mkApp (mkConst declName [u]) type
return LOption.toOption (← trySynthInstance instType)
synthInstance? <| mkApp (mkConst declName [u]) type
let rec getInst (declName : Name) : GoalM Expr := do
let instType := mkApp (mkConst declName [u]) type
let .some inst ← trySynthInstance instType
| throwError "`grind linarith` failed to find instance{indentExpr instType}"
return inst
synthInstance <| mkApp (mkConst declName [u]) type
let rec getBinHomoInst (declName : Name) : GoalM Expr := do
let instType := mkApp3 (mkConst declName [u, u, u]) type type type
let .some inst ← trySynthInstance instType
| throwError "`grind linarith` failed to find instance{indentExpr instType}"
return inst
synthInstance <| mkApp3 (mkConst declName [u, u, u]) type type type
let rec getHMulIntInst : GoalM Expr := do
let instType := mkApp3 (mkConst ``HMul [0, u, u]) Int.mkType type type
let .some inst ← trySynthInstance instType
| throwError "`grind linarith` failed to find instance{indentExpr instType}"
return inst
synthInstance <| mkApp3 (mkConst ``HMul [0, u, u]) Int.mkType type type
let rec getHMulNatInst : GoalM Expr := do
let instType := mkApp3 (mkConst ``HMul [0, u, u]) Nat.mkType type type
let .some inst ← trySynthInstance instType
| throwError "`grind linarith` failed to find instance{indentExpr instType}"
return inst
synthInstance <| mkApp3 (mkConst ``HMul [0, u, u]) Nat.mkType type type
let rec checkToFieldDefEq? (parentInst? : Option Expr) (inst? : Option Expr) (toFieldName : Name) : GoalM (Option Expr) := do
let some parentInst := parentInst? | return none
let some inst := inst? | return none
@ -113,12 +101,12 @@ where
let heteroToField := mkApp2 (mkConst toHeteroName [u]) type toField
ensureDefEq parentInst heteroToField
let some intModuleInst ← getInst? ``Grind.IntModule | return none
let addCommGroupInst ← getInst ``Grind.AddCommGroup
let addCommMonoidInst ← getInst ``Grind.AddCommMonoid
let addCommGroupInst := mkApp2 (mkConst ``Grind.IntModule.toAddCommGroup [u]) type intModuleInst
let addCommMonoidInst := mkApp2 (mkConst ``Grind.AddCommGroup.toAddCommMonoid [u]) type addCommGroupInst
let zeroInst ← getInst ``Zero
let zero ← internalizeConst <| mkApp2 (mkConst ``Zero.zero [u]) type zeroInst
let ofNatZeroType := mkApp2 (mkConst ``OfNat [u]) type (mkRawNatLit 0)
let some ofNatZeroInst := LOption.toOption (← trySynthInstance ofNatZeroType) | return none
let some ofNatZeroInst ← synthInstance? ofNatZeroType | return none
-- `ofNatZero` is used internally, we don't need to internalize
let ofNatZero ← preprocess <| mkApp3 (mkConst ``OfNat.ofNat [u]) type (mkRawNatLit 0) ofNatZeroInst
ensureDefEq zero ofNatZero
@ -132,8 +120,6 @@ where
let zsmulFn ← internalizeFn <| mkApp4 (mkConst ``HMul.hMul [0, u, u]) Int.mkType type type zsmulInst
let nsmulInst ← getHMulNatInst
let nsmulFn ← internalizeFn <| mkApp4 (mkConst ``HMul.hMul [0, u, u]) Nat.mkType type type nsmulInst
ensureToFieldDefEq addCommGroupInst intModuleInst ``Grind.IntModule.toAddCommGroup
ensureToFieldDefEq addCommMonoidInst addCommGroupInst ``Grind.AddCommGroup.toAddCommMonoid
ensureToFieldDefEq zeroInst addCommMonoidInst ``Grind.AddCommMonoid.toZero
ensureToHomoFieldDefEq addInst addCommMonoidInst ``Grind.AddCommMonoid.toAdd ``instHAdd
ensureToHomoFieldDefEq subInst addCommGroupInst ``Grind.AddCommGroup.toSub ``instHSub
@ -142,8 +128,7 @@ where
ensureToFieldDefEq nsmulInst intModuleInst ``Grind.IntModule.nsmul
let preorderInst? ← getInst? ``Grind.Preorder
let orderedAddInst? ← if let some preorderInst := preorderInst? then
let isOrderedType := mkApp3 (mkConst ``Grind.OrderedAdd [u]) type addInst preorderInst
pure <| LOption.toOption (← trySynthInstance isOrderedType)
synthInstance? <| mkApp3 (mkConst ``Grind.OrderedAdd [u]) type addInst preorderInst
else
pure none
let preorderInst? := if orderedAddInst?.isNone then none else preorderInst?
@ -161,11 +146,11 @@ where
pure (none, none)
let rec getHSMulFn? : GoalM (Option Expr) := do
let smulType := mkApp3 (mkConst ``HSMul [0, u, u]) Int.mkType type type
let .some smulInst ← trySynthInstance smulType | return none
let some smulInst ← synthInstance? smulType | return none
internalizeFn <| mkApp4 (mkConst ``HSMul.hSMul [0, u, u]) Int.mkType type smulInst smulInst
let rec getHSMulNatFn? : GoalM (Option Expr) := do
let smulType := mkApp3 (mkConst ``HSMul [0, u, u]) Nat.mkType type type
let .some smulInst ← trySynthInstance smulType | return none
let some smulInst ← synthInstance? smulType | return none
internalizeFn <| mkApp4 (mkConst ``HSMul.hSMul [0, u, u]) Nat.mkType type smulInst smulInst
let zsmulFn? ← getHSMulFn?
let nsmulFn? ← getHSMulNatFn?
@ -190,7 +175,7 @@ where
let some semiringInst := semiringInst? | return none
let some preorderInst := preorderInst? | return none
let isOrdType := mkApp3 (mkConst ``Grind.OrderedRing [u]) type semiringInst preorderInst
let .some inst ← trySynthInstance isOrdType
let some inst ← synthInstance? isOrdType
| reportIssue! "type has a `Preorder` and is a `Semiring`, but is not an ordered ring, failed to synthesize{indentExpr isOrdType}"
return none
return some inst
@ -198,9 +183,8 @@ where
let charInst? ← if let some semiringInst := semiringInst? then getIsCharInst? u type semiringInst else pure none
let rec getNoNatZeroDivInst? : GoalM (Option Expr) := do
let hmulNat := mkApp3 (mkConst ``HMul [0, u, u]) Nat.mkType type type
let .some hmulInst ← trySynthInstance hmulNat | return none
let noNatZeroDivType := mkApp2 (mkConst ``Grind.NoNatZeroDivisors [u]) type hmulInst
return LOption.toOption (← trySynthInstance noNatZeroDivType)
let some hmulInst ← synthInstance? hmulNat | return none
synthInstance? <| mkApp2 (mkConst ``Grind.NoNatZeroDivisors [u]) type hmulInst
let noNatDivInst? ← getNoNatZeroDivInst?
let id := (← get').structs.size
let struct : Struct := {

View file

@ -7,13 +7,14 @@ prelude
import Init.Grind.Ring.Basic
import Init.Simproc
import Lean.Meta.Tactic.Simp.Simproc
import Lean.Meta.Tactic.Grind.SynthInstance
namespace Lean.Meta.Grind.Arith
private def mkSemiringThm (declName : Name) (α : Expr) : MetaM (Option Expr) := do
let some u ← getDecLevel? α | return none
let semiring := mkApp (mkConst ``Grind.Semiring [u]) α
let .some semiringInst ← trySynthInstance semiring | return none
let some semiringInst ← synthInstanceMeta? semiring | return none
return mkApp2 (mkConst declName [u]) α semiringInst
/--

View file

@ -152,21 +152,6 @@ def isIntModuleVirtualParent (parent? : Option Expr) : Bool :=
| none => false
| some parent => parent == getIntModuleVirtualParent
def getIsCharInst? (u : Level) (type : Expr) (semiringInst : Expr) : MetaM (Option (Expr × Nat)) := do withNewMCtxDepth do
let n ← mkFreshExprMVar (mkConst ``Nat)
let charType := mkApp3 (mkConst ``Grind.IsCharP [u]) type semiringInst n
let .some charInst ← trySynthInstance charType | pure none
let n ← instantiateMVars n
let some n ← evalNat n |>.run
| pure none
pure <| some (charInst, n)
def getNoZeroDivInst? (u : Level) (type : Expr) : MetaM (Option Expr) := do
let hmulType := mkApp3 (mkConst ``HMul [0, u, u]) (mkConst ``Nat []) type type
let .some hmulInst ← trySynthInstance hmulType | return none
let noZeroDivType := mkApp2 (mkConst ``Grind.NoNatZeroDivisors [u]) type hmulInst
LOption.toOption <$> trySynthInstance noZeroDivType
@[specialize] def split (cs : PArray α) (getCoeff : α → Int) : PArray α × Array (Int × α) := Id.run do
let mut cs' := {}
let mut todo := #[]

View file

@ -135,7 +135,7 @@ private def matchArg? (c : Choice) (pArg : Expr) (eArg : Expr) : OptionT GoalM C
assign? c pArg.bvarIdx! eArg
else if let some pArg := groundPattern? pArg then
/-
We need to use `withReducibleAndIntances` because ground patterns are often instances.
We need to use `withReducibleAndInstances` because ground patterns are often instances.
Here is an example
```
instance : Max Nat where
@ -348,7 +348,7 @@ private def synthesizeInsts (mvars : Array Expr) (bis : Array BinderInfo) : Opti
for mvar in mvars, bi in bis do
if bi.isInstImplicit && !(← mvar.mvarId!.isAssigned) then
let type ← inferType mvar
unless (← synthesizeInstanceAndAssign mvar type) do
unless (← synthInstanceAndAssign mvar type) do
reportIssue! "failed to synthesize instance when instantiating {← thm.origin.pp}{indentExpr type}"
failure

View file

@ -5,6 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.SynthInstance
namespace Lean.Meta.Grind
/-! Extensionality theorems support. -/
@ -20,7 +21,7 @@ def instantiateExtTheorem (thm : Ext.ExtTheorem) (e : Expr) : GoalM Unit := with
for mvar in mvars, bi in bis do
if bi.isInstImplicit && !(← mvar.mvarId!.isAssigned) then
let type ← inferType mvar
unless (← synthesizeInstanceAndAssign mvar type) do
unless (← synthInstanceAndAssign mvar type) do
reportIssue! "failed to synthesize instance when instantiating extensionality theorem `{thm.declName}` for {indentExpr e}"
return ()
-- Remark: `proof c mvars` has type `e`

View file

@ -256,7 +256,7 @@ builtin_simproc_decl simpExists (Exists _) := fun e => do
else
let u := ex.constLevels!
let nonempty := mkApp (mkConst ``Nonempty u) α
if let .some nonemptyInst ← trySynthInstance nonempty then
if let some nonemptyInst ← synthInstanceMeta? nonempty then
return .visit { expr := b, proof? := mkApp3 (mkConst ``Grind.exists_const u) α nonemptyInst b }
return .continue

View file

@ -5,6 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.SynthInstance
/-!
Support for type class `LawfulEqCmp`.
@ -38,7 +39,7 @@ where
let u ← getLevel α
let some u ← decLevel? u | return none
let lawfulEqCmp := mkApp2 (mkConst ``Std.LawfulEqCmp [u]) α op
let .some lawfulEqCmpInst ← trySynthInstance lawfulEqCmp | return none
let some lawfulEqCmpInst ← synthInstanceMeta? lawfulEqCmp | return none
return some <| mkApp3 (mkConst ``Std.LawfulEqCmp.eq_of_compare [u]) α op lawfulEqCmpInst
def propagateLawfulEqCmp (e : Expr) : GoalM Unit := do

View file

@ -174,11 +174,8 @@ builtin_grind_propagator propagateEqDown ↓Eq := fun e => do
for thm in (← getExtTheorems α) do
instantiateExtTheorem thm e
private def getLawfulBEqInst? (u : List Level) (α : Expr) (binst : Expr) : MetaM (Option Expr) := do
let lawfulBEq := mkApp2 (mkConst ``LawfulBEq u) α binst
let .some linst ← trySynthInstance lawfulBEq | return none
return some linst
private def getLawfulBEqInst? (u : List Level) (α : Expr) (binst : Expr) : GoalM (Option Expr) := do
synthInstance? <| mkApp2 (mkConst ``LawfulBEq u) α binst
/-
Note about `BEq.beq`
Given `a b : α` in a context where we have `[BEq α] [LawfulBEq α]`

View file

@ -5,6 +5,7 @@ Authors: Kim Morrison
-/
prelude
import Lean.Meta.Tactic.Grind.Types
import Lean.Meta.Tactic.Grind.SynthInstance
/-!
Support for type class `ReflCmp`.
@ -38,7 +39,7 @@ where
let u ← getLevel α
let some u ← decLevel? u | return none
let reflCmp := mkApp2 (mkConst ``Std.ReflCmp [u]) α op
let .some reflCmpInst ← trySynthInstance reflCmp | return none
let some reflCmpInst ← synthInstanceMeta? reflCmp | return none
return some <| mkApp3 (mkConst ``Std.ReflCmp.cmp_eq_of_eq [u]) α op reflCmpInst
def propagateReflCmp (e : Expr) : GoalM Unit := do

View file

@ -0,0 +1,33 @@
/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.SynthInstance
import Lean.Meta.Tactic.Grind.Types
namespace Lean.Meta.Grind
def synthInstanceMeta? (type : Expr) : MetaM (Option Expr) := do profileitM Exception "grind typeclass inference" (← getOptions) (decl := type.getAppFn.constName?.getD .anonymous) do
catchInternalId isDefEqStuckExceptionId
(synthInstanceCore? type none)
(fun _ => pure none)
abbrev synthInstance? (type : Expr) : GoalM (Option Expr) :=
synthInstanceMeta? type
def synthInstance (type : Expr) : GoalM Expr := do
let some inst ← synthInstance? type
| throwError "`grind` failed to find instance{indentExpr type}"
return inst
/--
Helper function for instantiating a type class `type`, and
then using the result to perform `isDefEq x val`.
-/
def synthInstanceAndAssign (x type : Expr) : GoalM Bool := do
let some val ← synthInstance? type | return false
isDefEq x val
end Lean.Meta.Grind

View file

@ -1539,14 +1539,6 @@ def getExtTheorems (type : Expr) : GoalM (Array Ext.ExtTheorem) := do
modify fun s => { s with extThms := s.extThms.insert { expr := type } thms }
return thms
/--
Helper function for instantiating a type class `type`, and
then using the result to perform `isDefEq x val`.
-/
def synthesizeInstanceAndAssign (x type : Expr) : MetaM Bool := do
let .some val ← trySynthInstance type | return false
isDefEq x val
/-- Add a new lookahead candidate. -/
def addLookaheadCandidate (sinfo : SplitInfo) : GoalM Unit := do
trace_goal[grind.lookahead.add] "{sinfo.getExpr}"