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.
64 lines
3 KiB
Text
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
|
|
-/
|