Compare commits

...

3 Commits

Author SHA1 Message Date
Leonardo de Moura
ca99bf3aee feat: track type class inference time in grind 2025-07-05 12:55:44 -07:00
Leonardo de Moura
b10cd76849 refactor: avoid trySynthInstance 2025-07-05 12:07:44 -07:00
Leonardo de Moura
56ad1b3bd8 perf: minimize number of type class inferences 2025-07-05 10:37:55 -07:00
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}"