fix: unfold should not create an auxiliary declaration when result is definitionally equal

This commit fixes an issue reported on Zulip
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Unfolding.20the.20type.20of.20a.20variable.20creates.20a.20new.20variable
This commit is contained in:
Leonardo de Moura 2022-04-11 07:17:05 -07:00
parent 7cf4642d1b
commit fb64a4ccc0
4 changed files with 28 additions and 5 deletions

View file

@ -680,9 +680,9 @@ def applySimpResultToProp (mvarId : MVarId) (proof : Expr) (prop : Expr) (r : Si
else
return some (proof, r.expr)
def applySimpResultToFVarId (mvarId : MVarId) (fvarId : FVarId) (r : Simp.Result) : MetaM (Option (Expr × Expr)) := do
def applySimpResultToFVarId (mvarId : MVarId) (fvarId : FVarId) (r : Simp.Result) (mayCloseGoal : Bool) : MetaM (Option (Expr × Expr)) := do
let localDecl ← getLocalDecl fvarId
applySimpResultToProp mvarId (mkFVar fvarId) localDecl.type r
applySimpResultToProp mvarId (mkFVar fvarId) localDecl.type r mayCloseGoal
/--
Simplify `prop` (which is inhabited by `proof`). Return `none` if the goal was closed. Return `some (proof', prop')`
@ -709,8 +709,17 @@ def applySimpResultToLocalDeclCore (mvarId : MVarId) (fvarId : FVarId) (r : Opti
/--
Simplify `simp` result to the given local declaration. Return `none` if the goal was closed.
This method assumes `mvarId` is not assigned, and we are already using `mvarId`s local context. -/
def applySimpResultToLocalDecl (mvarId : MVarId) (fvarId : FVarId) (r : Simp.Result) : MetaM (Option (FVarId × MVarId)) := do
applySimpResultToLocalDeclCore mvarId fvarId (← applySimpResultToFVarId mvarId fvarId r)
def applySimpResultToLocalDecl (mvarId : MVarId) (fvarId : FVarId) (r : Simp.Result) (mayCloseGoal : Bool) : MetaM (Option (FVarId × MVarId)) := do
if r.proof?.isNone then
-- New result is definitionally equal to input. Thus, we can avoid creating a new variable if there are dependencies
let mvarId ← replaceLocalDeclDefEq mvarId fvarId r.expr
if mayCloseGoal && r.expr.isConstOf ``False then
assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) (mkFVar fvarId))
return none
else
return some (fvarId, mvarId)
else
applySimpResultToLocalDeclCore mvarId fvarId (← applySimpResultToFVarId mvarId fvarId r mayCloseGoal)
def simpLocalDecl (mvarId : MVarId) (fvarId : FVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) (mayCloseGoal := true) : MetaM (Option (FVarId × MVarId)) := do
withMVarContext mvarId do

View file

@ -36,7 +36,7 @@ def unfoldTarget (mvarId : MVarId) (declName : Name) : MetaM MVarId := withMVarC
def unfoldLocalDecl (mvarId : MVarId) (fvarId : FVarId) (declName : Name) : MetaM MVarId := withMVarContext mvarId do
let localDecl ← getLocalDecl fvarId
let r ← unfold (← instantiateMVars localDecl.type) declName
let some (_, mvarId) ← applySimpResultToLocalDecl mvarId fvarId r | unreachable!
let some (_, mvarId) ← applySimpResultToLocalDecl mvarId fvarId r (mayCloseGoal := false) | unreachable!
return mvarId
end Lean.Meta

View file

@ -0,0 +1,9 @@
def Wrapper (n : Nat) : Type × Type :=
(Fin n, Fin n)
def some_property {n} (x : Fin n) : Prop :=
True
example (x : (Wrapper n).1) (h : some_property x) : True := by
unfold Wrapper at x
done

View file

@ -0,0 +1,5 @@
unfoldDefEq.lean:9:2-9:6: error: unsolved goals
n : Nat
x : (Fin n, Fin n).fst
h : some_property x
⊢ True