lean4-htt/src/Lean/Meta/Tactic/Clear.lean
Kim Morrison f85c66789d
feat: Array.insertIdx/eraseIdx take a tactic-provided proof (#6133)
This PR replaces `Array.feraseIdx` and `Array.insertAt` with
`Array.eraseIdx` and `Array.insertIdx`, both of which take a `Nat`
argument and a tactic-provided proof that it is in bounds. We also have
`eraseIdxIfInBounds` and `insertIdxIfInBounds` which are noops if the
index is out of bounds. We also provide a `Fin` valued version of
`Array.findIdx?`. Together, these quite ergonomically improve the array
indexing safety at a number of places in the compiler/elaborator.
2024-11-20 09:52:38 +00:00

73 lines
2.7 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.Tactic.Util
namespace Lean.Meta
/--
Erase the given free variable from the goal `mvarId`.
-/
def _root_.Lean.MVarId.clear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
mvarId.withContext do
mvarId.checkNotAssigned `clear
let lctx ← getLCtx
unless lctx.contains fvarId do
throwTacticEx `clear mvarId m!"unknown variable '{mkFVar fvarId}'"
let tag ← mvarId.getTag
lctx.forM fun localDecl => do
unless localDecl.fvarId == fvarId do
if (← localDeclDependsOn localDecl fvarId) then
throwTacticEx `clear mvarId m!"variable '{localDecl.toExpr}' depends on '{mkFVar fvarId}'"
let mvarDecl ← mvarId.getDecl
if (← exprDependsOn mvarDecl.type fvarId) then
throwTacticEx `clear mvarId m!"target depends on '{mkFVar fvarId}'"
let lctx := lctx.erase fvarId
let localInsts ← getLocalInstances
let localInsts := match localInsts.findFinIdx? fun localInst => localInst.fvar.fvarId! == fvarId with
| none => localInsts
| some idx => localInsts.eraseIdx idx
let newMVar ← mkFreshExprMVarAt lctx localInsts mvarDecl.type MetavarKind.syntheticOpaque tag
mvarId.assign newMVar
pure newMVar.mvarId!
/--
Try to erase the given free variable from the goal `mvarId`. It is no-op if the free variable
cannot be erased due to forward dependencies.
-/
def _root_.Lean.MVarId.tryClear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
mvarId.clear fvarId <|> pure mvarId
/--
Try to clear the given fvars from the local context.
The fvars must be given in the order they appear in the local context.
See also `tryClearMany'` which takes care of reordering internally,
and returns the cleared hypotheses along with the new goal.
-/
def _root_.Lean.MVarId.tryClearMany (mvarId : MVarId) (fvarIds : Array FVarId) : MetaM MVarId := do
fvarIds.foldrM (init := mvarId) fun fvarId mvarId => mvarId.tryClear fvarId
/--
Try to clear the given fvars from the local context. Returns the new goal and
the hypotheses that were cleared.
Does not require the `hyps` to be given in the order in which they
appear in the local context.
-/
def _root_.Lean.MVarId.tryClearMany' (goal : MVarId) (fvarIds : Array FVarId) :
MetaM (MVarId × Array FVarId) :=
goal.withContext do
let fvarIds := (← getLCtx).sortFVarsByContextOrder fvarIds
fvarIds.foldrM (init := (goal, Array.mkEmpty fvarIds.size))
fun h (goal, cleared) => do
let goal' ← goal.tryClear h
let cleared := if goal == goal' then cleared else cleared.push h
return (goal', cleared)
end Lean.Meta