File: Mathlib/Tactic/Propose.lean

full_name: Mathlib.Tactic.Propose.initFn._@.Mathlib.Tactic.Propose._hyg.6
code: initialize registerTraceClass `Tactic.propose
goal: IO Unit

full_name: Mathlib.Tactic.Propose.discrTreeConfig
code: /-- Configuration for `DiscrTree`. -/
def discrTreeConfig : WhnfCoreConfig 
goal: Lean.Meta.WhnfCoreConfig

full_name: Mathlib.Tactic.Propose.proposeLemmas
code: initialize proposeLemmas : DeclCache (DiscrTree Name) ←
  DeclCache.mk "have?: init cache" failure {} fun name constInfo lemmas => do
    if constInfo.isUnsafe then return lemmas
    if ← name.isBlackListed then return lemmas
    withNewMCtxDepth do withReducible do
      let (mvars, _, _) ← forallMetaTelescope constInfo.type
      let mut lemmas := lemmas
      for m in mvars do
        lemmas ← lemmas.insertIfSpecific (← inferType m) name discrTreeConfig
      pure lemmas
goal: Batteries.Tactic.DeclCache (Lean.Meta.DiscrTree Lean.Name)

full_name: Mathlib.Tactic.Propose.initFn._@.Mathlib.Tactic.Propose._hyg.57
code: initialize proposeLemmas : DeclCache (DiscrTree Name) ←
  DeclCache.mk "have?: init cache" failure {} fun name constInfo lemmas => do
    if constInfo.isUnsafe then return lemmas
    if ← name.isBlackListed then return lemmas
    withNewMCtxDepth do withReducible do
      let (mvars, _, _) ← forallMetaTelescope constInfo.type
      let mut lemmas := lemmas
      for m in mvars do
        lemmas ← lemmas.insertIfSpecific (← inferType m) name discrTreeConfig
      pure lemmas
goal: IO (Batteries.Tactic.DeclCache (Lean.Meta.DiscrTree Lean.Name))

full_name: Mathlib.Tactic.Propose.solveByElim
code: /-- Shortcut for calling `solveByElim`. -/
def solveByElim (orig : MVarId) (goals : Array MVarId) (use : Array Expr) (required : Array Expr)
    (depth) 
goal: Lean.MetaM PUnit

full_name: Mathlib.Tactic.Propose.propose
code: /--
Attempts to find lemmas which use all of the `required` expressions as arguments, and
can be unified with the given `type` (which may contain metavariables, which we avoid assigning).
We look up candidate lemmas from a discrimination tree using the first such expression.

Returns an array of pairs, containing the names of found lemmas and the resulting application.
-/
def propose (lemmas : DiscrTree Name) (type : Expr) (required : Array Expr)
    (solveByElimDepth := 15) : MetaM (Array (Name × Expr)) 
goal: Lean.MetaM (Array (Lean.Name × Lean.Expr))

full_name: Mathlib.Tactic.Propose.propose'
code: /--
* `have? using a, b, c` tries to find a lemma
which makes use of each of the local hypotheses `a, b, c`,
and reports any results via trace messages.
* `have? : h using a, b, c` only returns lemmas whose type matches `h` (which may contain `_`).
* `have?! using a, b, c` will also call `have` to add results to the local goal state.

Note that `have?` (unlike `apply?`) does not inspect the goal at all,
only the types of the lemmas in the `using` clause.

`have?` should not be left in proofs; it is a search tool, like `apply?`.

Suggestions are printed as `have := f a b c`.
-/
syntax (name := propose') "have?" "!"? (ident)? (" : " term)? " using " (colGt term),+ : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Propose._aux_Mathlib_Tactic_Propose___elabRules_Mathlib_Tactic_Propose_propose'_1
code: elab_rules : tactic
  | `(tactic| have?%$tk $[!%$lucky]? $[$h:ident]? $[ : $type:term]? using $[$terms:term],*) => do
    let stx ← getRef
    let goal ← getMainGoal
    goal.withContext do
      let required ← terms.mapM (elabTerm · none)
      let type ← match type with
      | some stx => elabTermWithHoles stx none (← getMainTag) true <&> (·.1)
      | none => mkFreshTypeMVar
      let proposals ← propose (← proposeLemmas.get) type required
      if proposals.isEmpty then
        throwError "propose could not find any lemmas using the given hypotheses"
      -- TODO we should have `proposals` return a lazy list, to avoid unnecessary computation here.
      for p in proposals.toList.take 10 do
        addHaveSuggestion tk (h.map (·.getId)) (← inferType p.2) p.2 stx
      if lucky.isSome then
        let mut g := goal
        for p in proposals.toList.take 10 do
          (_, g) ← g.let p.1 p.2
        replaceMainGoal [g]
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.Propose.«tacticHave?!:_Using__»
code: @[inherit_doc propose'] syntax "have?!" (" : " term)? " using " (colGt term),+ : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Propose.«tacticHave!?:_Using__»
code: @[inherit_doc propose'] syntax "have!?" (" : " term)? " using " (colGt term),+ : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Propose.«_aux_Mathlib_Tactic_Propose___macroRules_Mathlib_Tactic_Propose_tacticHave!?:_Using___1»
code: macro_rules
  | `(tactic| have?!%$tk $[: $type]? using $terms,*) =>
    `(tactic| have?%$tk ! $[: $type]? using $terms,*)
  | `(tactic| have!?%$tk $[: $type]? using $terms,*) =>
    `(tactic| have?%$tk ! $[: $type]? using $terms,*)
goal: Lean.Macro

full_name: Mathlib.Tactic.Propose.«_aux_Mathlib_Tactic_Propose___macroRules_Mathlib_Tactic_Propose_tacticHave?!:_Using___1»
code: macro_rules
  | `(tactic| have?!%$tk $[: $type]? using $terms,*) =>
    `(tactic| have?%$tk ! $[: $type]? using $terms,*)
  | `(tactic| have!?%$tk $[: $type]? using $terms,*) =>
    `(tactic| have?%$tk ! $[: $type]? using $terms,*)
goal: Lean.Macro