File: Mathlib/Tactic/ExtractGoal.lean

full_name: Mathlib.Tactic.ExtractGoal.star
code: /-- Have `extract_goal` extract the full local context. -/
syntax star := "*"
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.ExtractGoal.config
code: /-- Configuration for `extract_goal` for which variables from the context to include. -/
syntax config := star <|> (colGt ppSpace ident)*
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.ExtractGoal.extractGoal
code: /--
- `extract_goal` formats the current goal as a stand-alone theorem or definition after
  cleaning up the local context of irrelevant variables.
  A variable is *relevant* if (1) it occurs in the target type, (2) there is a relevant variable
  that depends on it, or (3) the type of the variable is a proposition that depends on a
  relevant variable.

  If the target is `False`, then for convenience `extract_goal` includes all variables.
- `extract_goal *` formats the current goal without cleaning up the local context.
- `extract_goal a b c ...` formats the current goal after removing everything that the given
  variables `a`, `b`, `c`, ... do not depend on.
- `extract_goal ... using name` uses the name `name` for the theorem or definition rather than
  the autogenerated name.

The tactic tries to produce an output that can be copy-pasted and just work,
but its success depends on whether the expressions are amenable
to being unambiguously pretty printed.

The tactic responds to pretty printing options.
For example, `set_option pp.all true in extract_goal` gives the `pp.all` form.
-/
syntax (name := extractGoal) "extract_goal" config (" using " ident)? : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.ExtractGoal._aux_Mathlib_Tactic_ExtractGoal___elabRules_Mathlib_Tactic_ExtractGoal_extractGoal_1
code: elab_rules : tactic
  | `(tactic| extract_goal $cfg:config $[using $name?]?) => do
    let name ← if let some name := name?
                then pure name.getId
                else mkAuxName ((← getCurrNamespace) ++ `extracted) 1
    let msg ← withoutModifyingEnv <| withoutModifyingState do
      let g ← getMainGoal
      let g ← do match cfg with
        | `(config| *) => pure g
        | `(config| ) =>
          if (← g.getType >>= instantiateMVars).consumeMData.isConstOf ``False then
            -- In a contradiction proof, it is not very helpful to clear all hypotheses!
            pure g
          else
            g.cleanup
        | `(config| $fvars:ident*) =>
          -- Note: `getFVarIds` does `withMainContext`
          g.cleanup (toPreserve := (← getFVarIds fvars)) (indirectProps := false)
        | _ => throwUnsupportedSyntax
      let (g, _) ← g.renameInaccessibleFVars
      let (_, g) ← g.revert (clearAuxDeclsInsteadOfRevert := true) (← g.getDecl).lctx.getFVarIds
      let ty ← instantiateMVars (← g.getType)
      if ty.hasExprMVar then
        -- TODO: turn metavariables into new hypotheses?
        throwError "Extracted goal has metavariables: {ty}"
      let ty ← Term.levelMVarToParam ty
      let seenLevels := collectLevelParams {} ty
      let levels := (← Term.getLevelNames).filter
                      fun u => seenLevels.visitedLevel.contains (.param u)
      addAndCompile <| Declaration.axiomDecl
        { name := name
          levelParams := levels
          isUnsafe := false
          type := ty }
      let sig ← addMessageContext <| MessageData.signature name
      let cmd := if ← Meta.isProp ty then "theorem" else "def"
      pure m!"{cmd} {sig} := sorry"
    logInfo msg
goal: Lean.Elab.Tactic.Tactic