File: Mathlib/Tactic/Subsingleton.lean

full_name: Lean.Meta.mkSubsingleton
code: /-- Returns the expression `Subsingleton ty`. -/
def Lean.Meta.mkSubsingleton (ty : Expr) : MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.Meta.synthSubsingletonInst
code: /-- Synthesizes a `Subsingleton ty` instance with the additional local instances made available. -/
def Lean.Meta.synthSubsingletonInst (ty : Expr)
    (insts : Array (Term × AbstractMVarsResult) := #[]) :
    MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.MVarId.subsingleton
code: /--
Closes the goal `g` whose target is an `Eq` or `HEq` by appealing to the fact that the types
are subsingletons.
Fails if it cannot find a way to do this.

Has support for showing `BEq` instances are equal if they have `LawfulBEq` instances.
-/
def Lean.MVarId.subsingleton (g : MVarId) (insts : Array (Term × AbstractMVarsResult) := #[]) :
    MetaM Unit 
goal: Lean.MetaM Unit

full_name: Mathlib.Tactic.subsingletonStx
code: /--
The `subsingleton` tactic tries to prove a goal of the form `x = y` or `HEq x y`
using the fact that the types involved are *subsingletons*
(a type with exactly zero or one terms).
To a first approximation, it does `apply Subsingleton.elim`.
As a nicety, `subsingleton` first runs the `intros` tactic.

- If the goal is an equality, it either closes the goal or fails.
- `subsingleton [inst1, inst2, ...]` can be used to add additional `Subsingleton` instances
  to the local context. This can be more flexible than
  `have := inst1; have := inst2; ...; subsingleton` since the tactic does not require that
  all placeholders be solved for.

Techniques the `subsingleton` tactic can apply:
- proof irrelevance
- heterogenous proof irrelevance (via `proof_irrel_heq`)
- using `Subsingleton` (via `Subsingleton.elim`)
- proving `BEq` instances are equal if they are both lawful (via `lawful_beq_subsingleton`)

### Properties

The tactic is careful not to accidentally specialize `Sort _` to `Prop`,
avoiding the following surprising behavior of `apply Subsingleton.elim`:
```lean
example (α : Sort _) (x y : α) : x = y := by apply Subsingleton.elim
```
The reason this `example` goes through is that
it applies the `∀ (p : Prop), Subsingleton p` instance,
specializing the universe level metavariable in `Sort _` to `0`.
-/
syntax (name := subsingletonStx) "subsingleton" (ppSpace "[" term,* "]")? : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.elabSubsingletonInsts
code: /--
Elaborates the terms like how `Lean.Elab.Tactic.addSimpTheorem` does,
abstracting their metavariables.
-/
def elabSubsingletonInsts
    (instTerms? : Option (Array Term)) : TermElabM (Array (Term × AbstractMVarsResult)) 
goal: Lean.Elab.TermElabM (Array (Lean.Term × Lean.Meta.AbstractMVarsResult))

full_name: Mathlib.Tactic.elabSubsingletonInsts.go
code: /--
Elaborates the terms like how `Lean.Elab.Tactic.addSimpTheorem` does,
abstracting their metavariables.
-/
def elabSubsingletonInsts
    (instTerms? : Option (Array Term)) : TermElabM (Array (Term × AbstractMVarsResult)) 
goal: Lean.Elab.TermElabM (Array (Lean.Term × Lean.Meta.AbstractMVarsResult))

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_Subsingleton___elabRules_Mathlib_Tactic_subsingletonStx_1
code: elab_rules : tactic
  | `(tactic| subsingleton $[[$[$instTerms?],*]]?) => withMainContext do
    let recover := (← read).recover
    let insts ← elabSubsingletonInsts instTerms?
    Elab.Tactic.liftMetaTactic1 fun g => do
      let (fvars, g) ← g.intros
      -- note: `insts` are still valid after `intros`
      try
        g.subsingleton (insts := insts)
        return none
      catch e =>
        -- Try `refl` when all else fails, to give a hint to the user
        if recover then
          try
            g.refl <|> g.hrefl
            let tac ← if !fvars.isEmpty then `(tactic| (intros; rfl)) else `(tactic| rfl)
            Meta.Tactic.TryThis.addSuggestion (← getRef) tac (origSpan? := ← getRef)
            return none
          catch _ => pure ()
        throw e
goal: Lean.Elab.Tactic.Tactic