lean4-htt/tests/elab_fail/replaceLocalDeclInstantiateMVars.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

64 lines
3 KiB
Text

import Lean
/-!
# Ensure `replaceLocalDecl` instantiates metavariables
These tests ensure that `replaceLocalDecl` is aware of `FVarId`s present in the assignments of
metavariables present in the inserted declaration, and thus does not introduce unknown `FVarId`s by
inserting a local declaration before it's well-formed.
## Context
`replaceLocalDecl mvarId fvarId typeNew eqProof` replaces `fvarId` with a new FVarId that has the
same name but type `typeNew`. It does this by inserting a new local declaration with type `typeNew`
and clearing the old one if possible.
It makes sure that the new local declaration is inserted at the soonest point after `fvarId` at
which `typeNew` is well-formed. It does this by traversing `typeNew` and finding the `FVarId` with
the maximum index among all `FVarId`s occurring in `typeNew`.
If `replaceLocalDecl` encounters a metavariable during this traversal, it simply continues
traversing. Previously, it might have been the case that this metavariable we encountered was
assigned to an expression which contains an `FVarId` occurring after `fvarId`. This can lead to
`replaceLocalDecl` inserting a local declaration with a type which depends on `FVarId`s which come
after it in the local context, thus creating unknown `FVarId`s. (Note that the `FVarId`s of the
local declarations occurring after the insertion are modified, so the `FVarId` involved in the
assignment may not even exist in the local context anymore.)
We now attempt to prevent `replaceLocalDecl` from encountering assigned metavariables by
calling `instantiateMVars` in `replaceLocalDecl` before traversal.
Note that this is not a perfect solution to the overall problem; `Term.synthesizeSyntheticMVars`
may introduce assignments to inaccessible `FVarId`s after `replaceLocalDecl` has run, in which case
`instantiateMVars` is ineffective (as the metavariable has not even been assigned yet). See issue
#2727.
-/
/-! ## Direct test of instantiated mvars -/
open Lean Meta Elab Tactic in
/-- Replace the type of `fvar₁` with `fvar₂ = fvar₂` where the expression `fvar₂ = fvar₂` is hidden
under a metavariable assignment. Note that initially `fvar₁` must come before `fvar₂` in order to
make sure `replaceLocalDecl` is behaving correctly. -/
elab "replace " fvar₁:ident " with " fvar₂:ident " via " proof:term : tactic => withMainContext do
let fvar₁ ← getFVarId fvar₁
let fvar₂ ← getFVarId fvar₂
let underlyingTypeNew ← inferType <|← mkEqRefl (Expr.fvar fvar₂)
-- make a metavariable to use as the type in `replaceLocalDecl`; assign it to `underlyingTypeNew`
let typeNewMVar ← mkFreshExprMVar none
typeNewMVar.mvarId!.assign underlyingTypeNew
let proof ← elabTerm proof underlyingTypeNew
let { mvarId .. } ← (← getMainGoal).replaceLocalDecl fvar₁ typeNewMVar proof
replaceMainGoal [mvarId]
example : True := by
have h₁ : True := trivial
have h₂ : Nat := 0
replace h₁ with h₂ via eq_true rfl |>.symm
/-
Previously, goal state was:
h₁: _uniq.NNNN = _uniq.NNNN
h₂: Nat
⊢ True
-/