File: .lake/packages/lean4/src/lean/Lean/Meta/Tactic/SolveByElim.lean

full_name: Lean.Meta.SolveByElim.initFn._@..lake.packages.lean4.src.lean.Lean.Meta.Tactic.SolveByElim._hyg.6
code: initialize registerTraceClass `Meta.Tactic.solveByElim
goal: IO Unit

full_name: Lean.Meta.SolveByElim.applyTactics
code: /--
`applyTactics lemmas goal` will return an iterator that applies the
lemmas to the goal `goal` and returns ones that succeed.

Providing this to the `backtracking` tactic,
we can perform backtracking search based on applying a list of lemmas.

``applyTactics (trace := `name)`` will construct trace nodes for ``name` indicating which
calls to `apply` succeeded or failed.
-/
def applyTactics (cfg : ApplyConfig := {}) (transparency : TransparencyMode := .default)
    (lemmas : List Expr) (g : MVarId) : MetaM (Lean.Meta.Iterator (List Lean.MVarId)) 
goal: Lean.MetaM (Lean.Meta.Iterator (List Lean.MVarId))

full_name: Lean.Meta.SolveByElim.applyFirst
code: /--
`applyFirst lemmas goal` applies the first of the `lemmas`
which can be successfully applied to `goal`, and fails if none apply.

We use this in `apply_rules` and `apply_assumption` where backtracking is not needed.
-/
def applyFirst (cfg : ApplyConfig := {}) (transparency : TransparencyMode := .default)
    (lemmas : List Expr) (g : MVarId) : MetaM (List MVarId) 
goal: Lean.MetaM (List Lean.MVarId)

full_name: Lean.Meta.SolveByElim.ApplyRulesConfig
code: /-- The default `maxDepth` for `apply_rules` is higher. -/
structure ApplyRulesConfig extends BacktrackConfig, ApplyConfig where
  /-- Transparency mode for calls to `apply`. -/
  transparency : TransparencyMode := .default
  /-- Also use symmetric versions (via `@[symm]`) of local hypotheses. -/
  symm : Bool := true
  /-- Try proving the goal via `exfalso` if `solve_by_elim` otherwise fails.
  This is only used when operating on a single goal. -/
  exfalso : Bool := true
  maxDepth := 50
goal: Type

full_name: Lean.Meta.SolveByElim.ApplyRulesConfig.symm
code: /-- The default `maxDepth` for `apply_rules` is higher. -/
structure ApplyRulesConfig extends BacktrackConfig, ApplyConfig where
  /-- Transparency mode for calls to `apply`. -/
  transparency : TransparencyMode := .default
  /-- Also use symmetric versions (via `@[symm]`) of local hypotheses. -/
  symm : Bool := true
  /-- Try proving the goal via `exfalso` if `solve_by_elim` otherwise fails.
  This is only used when operating on a single goal. -/
  exfalso : Bool := true
  maxDepth := 50
goal: Bool

full_name: Lean.Meta.SolveByElim.ApplyRulesConfig.exfalso
code: /-- The default `maxDepth` for `apply_rules` is higher. -/
structure ApplyRulesConfig extends BacktrackConfig, ApplyConfig where
  /-- Transparency mode for calls to `apply`. -/
  transparency : TransparencyMode := .default
  /-- Also use symmetric versions (via `@[symm]`) of local hypotheses. -/
  symm : Bool := true
  /-- Try proving the goal via `exfalso` if `solve_by_elim` otherwise fails.
  This is only used when operating on a single goal. -/
  exfalso : Bool := true
  maxDepth := 50
goal: Bool

full_name: Lean.Meta.SolveByElim.ApplyRulesConfig.transparency
code: /-- The default `maxDepth` for `apply_rules` is higher. -/
structure ApplyRulesConfig extends BacktrackConfig, ApplyConfig where
  /-- Transparency mode for calls to `apply`. -/
  transparency : TransparencyMode := .default
  /-- Also use symmetric versions (via `@[symm]`) of local hypotheses. -/
  symm : Bool := true
  /-- Try proving the goal via `exfalso` if `solve_by_elim` otherwise fails.
  This is only used when operating on a single goal. -/
  exfalso : Bool := true
  maxDepth := 50
goal: Lean.Meta.TransparencyMode

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.backtracking
code: /--
Configuration structure to control the behaviour of `solve_by_elim`:
* transparency mode for calls to `apply`
* whether to use `symm` on hypotheses and `exfalso` on the goal as needed,
* see also `BacktrackConfig` for hooks allowing flow control.
-/
structure SolveByElimConfig extends ApplyRulesConfig where
  /-- Enable backtracking search. -/
  backtracking : Bool := true
  maxDepth := 6
  /-- Trying calling `intro` if no lemmas apply. -/
  intro : Bool := true
  /-- Try calling `constructor` if no lemmas apply. -/
  constructor : Bool := true
goal: Bool

full_name: Lean.Meta.SolveByElim.SolveByElimConfig
code: /--
Configuration structure to control the behaviour of `solve_by_elim`:
* transparency mode for calls to `apply`
* whether to use `symm` on hypotheses and `exfalso` on the goal as needed,
* see also `BacktrackConfig` for hooks allowing flow control.
-/
structure SolveByElimConfig extends ApplyRulesConfig where
  /-- Enable backtracking search. -/
  backtracking : Bool := true
  maxDepth := 6
  /-- Trying calling `intro` if no lemmas apply. -/
  intro : Bool := true
  /-- Try calling `constructor` if no lemmas apply. -/
  constructor : Bool := true
goal: Type

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.intro
code: /--
Configuration structure to control the behaviour of `solve_by_elim`:
* transparency mode for calls to `apply`
* whether to use `symm` on hypotheses and `exfalso` on the goal as needed,
* see also `BacktrackConfig` for hooks allowing flow control.
-/
structure SolveByElimConfig extends ApplyRulesConfig where
  /-- Enable backtracking search. -/
  backtracking : Bool := true
  maxDepth := 6
  /-- Trying calling `intro` if no lemmas apply. -/
  intro : Bool := true
  /-- Try calling `constructor` if no lemmas apply. -/
  constructor : Bool := true
goal: Bool

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.constructor
code: /--
Configuration structure to control the behaviour of `solve_by_elim`:
* transparency mode for calls to `apply`
* whether to use `symm` on hypotheses and `exfalso` on the goal as needed,
* see also `BacktrackConfig` for hooks allowing flow control.
-/
structure SolveByElimConfig extends ApplyRulesConfig where
  /-- Enable backtracking search. -/
  backtracking : Bool := true
  maxDepth := 6
  /-- Trying calling `intro` if no lemmas apply. -/
  intro : Bool := true
  /-- Try calling `constructor` if no lemmas apply. -/
  constructor : Bool := true
goal: Bool

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.instCoeBacktrackConfig
code: instance : Coe SolveByElimConfig BacktrackConfig 
goal: Coe Lean.Meta.SolveByElim.SolveByElimConfig Lean.Meta.Tactic.Backtrack.BacktrackConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.accept
code: /-- Create or modify a `Config` which allows a class of goals to be returned as subgoals. -/
def accept (cfg : SolveByElimConfig := {}) (test : MVarId → MetaM Bool) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.mainGoalProc
code: /--
Create or modify a `Config` which runs a tactic on the main goal.
If that tactic fails, fall back to the `proc` behaviour of `cfg`.
-/
def mainGoalProc (cfg : SolveByElimConfig := {}) (proc : MVarId → MetaM (List MVarId)) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.intros
code: /-- Create or modify a `Config` which calls `intro` on each goal before applying lemmas. -/
-- Because `SolveByElim` works on each goal in sequence, even though
-- `mainGoalProc` only applies this operation on the main goal,
-- it is applied to every goal before lemmas are applied.
def intros (cfg : SolveByElimConfig := {}) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.synthInstance
code: /-- Attempt typeclass inference on each goal, before applying lemmas. -/
-- Because `SolveByElim` works on each goal in sequence, even though
-- `mainGoalProc` only applies this operation on the main goal,
-- it is applied to every goal before lemmas are applied.
def synthInstance (cfg : SolveByElimConfig := {}) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.withDischarge
code: /-- Add a discharging tactic, falling back to the original discharging tactic if it fails.
Return `none` to return the goal as a new subgoal, or `some goals` to replace it. -/
def withDischarge (cfg : SolveByElimConfig := {}) (discharge : MVarId → MetaM (Option (List MVarId))) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.introsAfter
code: /-- Create or modify a `SolveByElimConfig` which calls `intro` on any goal for which no lemma applies. -/
def introsAfter (cfg : SolveByElimConfig := {}) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.constructorAfter
code: /-- Call `constructor` when no lemmas apply. -/
def constructorAfter (cfg : SolveByElimConfig := {}) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.synthInstanceAfter
code: /-- Create or modify a `Config` which
calls `synthInstance` on any goal for which no lemma applies. -/
def synthInstanceAfter (cfg : SolveByElimConfig := {}) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.testPartialSolutions
code: /--
Create or modify a `Config` which rejects branches for which `test`,
applied to the instantiations of the original goals, fails or returns `false`.
-/
def testPartialSolutions (cfg : SolveByElimConfig := {}) (test : List Expr → MetaM Bool) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.testSolutions
code: /--
Create or modify a `SolveByElimConfig` which rejects complete solutions for which `test`,
applied to the instantiations of the original goals, fails or returns `false`.
-/
def testSolutions (cfg : SolveByElimConfig := {}) (test : List Expr → MetaM Bool) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.requireUsingAll
code: /--
Create or modify a `Config` which only accept solutions
for which every expression in `use` appears as a subexpression.
-/
def requireUsingAll (cfg : SolveByElimConfig := {}) (use : List Expr) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.SolveByElimConfig.processOptions
code: /--
Process the `intro` and `constructor` options by implementing the `discharger` tactic.
-/
def processOptions (cfg : SolveByElimConfig) : SolveByElimConfig 
goal: Lean.Meta.SolveByElim.SolveByElimConfig

full_name: Lean.Meta.SolveByElim.elabContextLemmas
code: /--
Elaborate a list of lemmas and local context.
See `mkAssumptionSet` for an explanation of why this is needed.
-/
def elabContextLemmas (cfg : SolveByElimConfig) (g : MVarId)
    (lemmas : List (TermElabM Expr)) (ctx : SolveByElimConfig → TermElabM (List Expr)) :
    MetaM (List Expr) 
goal: Lean.MetaM (List Lean.Expr)

full_name: Lean.Meta.SolveByElim.applyLemmas
code: /-- Returns the list of tactics corresponding to applying the available lemmas to the goal. -/
def applyLemmas (cfg : SolveByElimConfig)
    (lemmas : List (TermElabM Expr)) (ctx : SolveByElimConfig → TermElabM (List Expr))
    (g : MVarId) : MetaM (Meta.Iterator (List MVarId)) 
goal: Lean.MetaM (Lean.Meta.Iterator (List Lean.MVarId))

full_name: Lean.Meta.SolveByElim.applyFirstLemma
code: /-- Applies the first possible lemma to the goal. -/
def applyFirstLemma (cfg : SolveByElimConfig)
    (lemmas : List (TermElabM Expr)) (ctx : SolveByElimConfig → TermElabM (List Expr))
    (g : MVarId) : MetaM (List MVarId) 
goal: Lean.MetaM (List Lean.MVarId)

full_name: Lean.Meta.SolveByElim.solveByElim.run
code: /--
Solve a collection of goals by repeatedly applying lemmas, backtracking as necessary.

Arguments:
* `cfg : SolveByElimConfig` additional configuration options
  (options for `apply`, maximum depth, and custom flow control)
* `lemmas : List (TermElabM Expr)` lemmas to apply.
  These are thunks in `TermElabM` to avoid stuck metavariables.
* `ctx : TermElabM (List Expr)` monadic function returning the local hypotheses to use.
* `goals : List MVarId` the initial list of goals for `solveByElim`

Returns a list of suspended goals, if it succeeded on all other subgoals.
By default `cfg.suspend` is `false,` `cfg.discharge` fails, and `cfg.failAtMaxDepth` is `true`,
and so the returned list is always empty.
Custom wrappers (e.g. `apply_assumption` and `apply_rules`) may modify this behaviour.
-/
def solveByElim (cfg : SolveByElimConfig)
    (lemmas : List (TermElabM Expr)) (ctx : SolveByElimConfig → TermElabM (List Expr))
    (goals : List MVarId) : MetaM (List MVarId) 
goal: List Lean.MVarId → Lean.MetaM (List Lean.MVarId)

full_name: Lean.Meta.SolveByElim.solveByElim
code: /--
Solve a collection of goals by repeatedly applying lemmas, backtracking as necessary.

Arguments:
* `cfg : SolveByElimConfig` additional configuration options
  (options for `apply`, maximum depth, and custom flow control)
* `lemmas : List (TermElabM Expr)` lemmas to apply.
  These are thunks in `TermElabM` to avoid stuck metavariables.
* `ctx : TermElabM (List Expr)` monadic function returning the local hypotheses to use.
* `goals : List MVarId` the initial list of goals for `solveByElim`

Returns a list of suspended goals, if it succeeded on all other subgoals.
By default `cfg.suspend` is `false,` `cfg.discharge` fails, and `cfg.failAtMaxDepth` is `true`,
and so the returned list is always empty.
Custom wrappers (e.g. `apply_assumption` and `apply_rules`) may modify this behaviour.
-/
def solveByElim (cfg : SolveByElimConfig)
    (lemmas : List (TermElabM Expr)) (ctx : SolveByElimConfig → TermElabM (List Expr))
    (goals : List MVarId) : MetaM (List MVarId) 
goal: Lean.MetaM (List Lean.MVarId)

full_name: Lean.Meta.SolveByElim.saturateSymm
code: /--
If `symm` is `true`, then adds in symmetric versions of each hypothesis.
-/
def saturateSymm (symm : Bool) (hyps : List Expr) : MetaM (List Expr) 
goal: Lean.MetaM (List Lean.Expr)

full_name: Lean.MVarId.applyRules
code: /--
A `MetaM` analogue of the `apply_rules` user tactic.

We pass the lemmas as `TermElabM Expr` rather than just `Expr`,
so they can be generated fresh for each application, to avoid stuck metavariables.

By default it uses all local hypotheses, but you can disable this with `only := true`.
If you need to remove particular local hypotheses, call `solveByElim` directly.
-/
def _root_.Lean.MVarId.applyRules (cfg : SolveByElimConfig) (lemmas : List (TermElabM Expr))
    (only : Bool := false) (g : MVarId) : MetaM (List MVarId) 
goal: Lean.MetaM (List Lean.MVarId)

full_name: Lean.Meta.SolveByElim.mkAssumptionSet
code: /--
`mkAssumptionSet` builds a collection of lemmas for use in
the backtracking search in `solve_by_elim`.

* By default, it includes all local hypotheses, along with `rfl`, `trivial`, `congrFun`
  and `congrArg`.
* The flag `noDefaults` removes these.
* The flag `star` includes all local hypotheses, but not `rfl`, `trivial`, `congrFun`,
  or `congrArg`. (It doesn't make sense to use `star` without `noDefaults`.)
* The argument `add` is the list of terms inside the square brackets that did not have `-`
  and can be used to add expressions or local hypotheses
* The argument `remove` is the list of terms inside the square brackets that had a `-`,
  and can be used to remove local hypotheses.
  (It doesn't make sense to remove expressions which are not local hypotheses,
  to remove local hypotheses unless `!noDefaults || star`,
  and it does not make sense to use `star` unless you remove at least one local hypothesis.)

`mkAssumptionSet` returns not a `List expr`, but a `List (TermElabM Expr) × TermElabM (List Expr)`.
There are two separate problems that need to be solved.

### Stuck metavariables

Lemmas with implicit arguments would be filled in with metavariables if we created the
`Expr` objects immediately, so instead we return thunks that generate the expressions
on demand. This is the first component, with type `List (TermElabM Expr)`.

As an example, we have `def rfl : ∀ {α : Sort u} {a : α}, a = a`, which on elaboration will become
`@rfl ?m_1 ?m_2`.

Because `solve_by_elim` works by repeated application of lemmas against subgoals,
the first time such a lemma is successfully applied,
those metavariables will be unified, and thereafter have fixed values.
This would make it impossible to apply the lemma
a second time with different values of the metavariables.

See https://github.com/leanprover-community/mathlib/issues/2269

### Relevant local hypotheses

`solve_by_elim*` works with multiple goals,
and we need to use separate sets of local hypotheses for each goal.
The second component of the returned value provides these local hypotheses.
(Essentially using `getLocalHyps`, along with some filtering to remove hypotheses
that have been explicitly removed via `only` or `[-h]`.)

-/
-- These `TermElabM`s must be run inside a suitable `g.withContext`,
-- usually using `elabContextLemmas`.
def mkAssumptionSet (noDefaults star : Bool) (add remove : List Term) (use : Array Ident) :
    MetaM (List (TermElabM Expr) × (SolveByElimConfig → TermElabM (List Expr))) 
goal: Lean.MetaM
  (List (Lean.Elab.TermElabM Lean.Expr) ×
    (Lean.Meta.SolveByElim.SolveByElimConfig → Lean.Elab.TermElabM (List Lean.Expr)))

full_name: Lean.Meta.SolveByElim.mkAssumptionSet.elab'
code: /--
`mkAssumptionSet` builds a collection of lemmas for use in
the backtracking search in `solve_by_elim`.

* By default, it includes all local hypotheses, along with `rfl`, `trivial`, `congrFun`
  and `congrArg`.
* The flag `noDefaults` removes these.
* The flag `star` includes all local hypotheses, but not `rfl`, `trivial`, `congrFun`,
  or `congrArg`. (It doesn't make sense to use `star` without `noDefaults`.)
* The argument `add` is the list of terms inside the square brackets that did not have `-`
  and can be used to add expressions or local hypotheses
* The argument `remove` is the list of terms inside the square brackets that had a `-`,
  and can be used to remove local hypotheses.
  (It doesn't make sense to remove expressions which are not local hypotheses,
  to remove local hypotheses unless `!noDefaults || star`,
  and it does not make sense to use `star` unless you remove at least one local hypothesis.)

`mkAssumptionSet` returns not a `List expr`, but a `List (TermElabM Expr) × TermElabM (List Expr)`.
There are two separate problems that need to be solved.

### Stuck metavariables

Lemmas with implicit arguments would be filled in with metavariables if we created the
`Expr` objects immediately, so instead we return thunks that generate the expressions
on demand. This is the first component, with type `List (TermElabM Expr)`.

As an example, we have `def rfl : ∀ {α : Sort u} {a : α}, a = a`, which on elaboration will become
`@rfl ?m_1 ?m_2`.

Because `solve_by_elim` works by repeated application of lemmas against subgoals,
the first time such a lemma is successfully applied,
those metavariables will be unified, and thereafter have fixed values.
This would make it impossible to apply the lemma
a second time with different values of the metavariables.

See https://github.com/leanprover-community/mathlib/issues/2269

### Relevant local hypotheses

`solve_by_elim*` works with multiple goals,
and we need to use separate sets of local hypotheses for each goal.
The second component of the returned value provides these local hypotheses.
(Essentially using `getLocalHyps`, along with some filtering to remove hypotheses
that have been explicitly removed via `only` or `[-h]`.)

-/
-- These `TermElabM`s must be run inside a suitable `g.withContext`,
-- usually using `elabContextLemmas`.
def mkAssumptionSet (noDefaults star : Bool) (add remove : List Term) (use : Array Ident) :
    MetaM (List (TermElabM Expr) × (SolveByElimConfig → TermElabM (List Expr))) 
goal: Lean.Elab.TermElabM Lean.Expr