This PR prevents `exact?` and `apply?` from suggesting tactics that correspond to correct proofs but do not elaborate, and it allows these tactics to suggest `expose_names` when needed. These tactics now indicate that a non-compiling term was generated but do not suggest that that term be inserted. `exact?` also no longer suggests that the user try `apply?` if no partial suggestions were found. This addresses part of #5407 but does not achieve the exact expected behavior therein (due to #6122).
66 lines
2.5 KiB
Text
66 lines
2.5 KiB
Text
/-
|
||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. 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
|
||
|
||
/-- Returns a copy of the local context in which all declarations have clear, accessible names. -/
|
||
private def getLCtxWithExposedNames : MetaM LocalContext := do
|
||
let mut map : Std.HashMap Name FVarId := {}
|
||
let mut toRename := #[]
|
||
let mut lctx ← getLCtx
|
||
for localDecl in lctx do
|
||
let userName := localDecl.userName
|
||
if userName.hasMacroScopes then
|
||
toRename := toRename.push localDecl.fvarId
|
||
else
|
||
if let some fvarId := map[userName]? then
|
||
-- Variable has been shadowed
|
||
toRename := toRename.push fvarId
|
||
map := map.insert userName localDecl.fvarId
|
||
if toRename.isEmpty then
|
||
return lctx
|
||
let mut next : Std.HashMap Name Nat := {}
|
||
-- Remark: Shadowed variables may be inserted later.
|
||
toRename := toRename.qsort fun fvarId₁ fvarId₂ =>
|
||
(lctx.get! fvarId₁).index < (lctx.get! fvarId₂).index
|
||
for fvarId in toRename do
|
||
let localDecl := lctx.get! fvarId
|
||
let mut baseName := localDecl.userName
|
||
if baseName.hasMacroScopes then
|
||
baseName := baseName.eraseMacroScopes
|
||
if baseName == `x || baseName == `a then
|
||
if (← isProp localDecl.type) then
|
||
baseName := `h
|
||
let mut userName := baseName
|
||
let mut i := next[baseName]?.getD 0
|
||
repeat
|
||
if !map.contains userName then
|
||
break
|
||
i := i + 1
|
||
userName := baseName.appendIndexAfter i
|
||
next := next.insert baseName i
|
||
map := map.insert userName fvarId
|
||
lctx := lctx.modifyLocalDecl fvarId (·.setUserName userName)
|
||
return lctx
|
||
|
||
/--
|
||
Creates a new goal whose local context has been "exposed" so that every local declaration has a clear, accessible name.
|
||
If no local declarations require renaming, the original goal is returned unchanged.
|
||
-/
|
||
def _root_.Lean.MVarId.exposeNames (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||
mvarId.checkNotAssigned `expose_names
|
||
let lctx ← getLCtxWithExposedNames
|
||
let mvarNew ← mkFreshExprMVarAt lctx (← getLocalInstances) (← mvarId.getType) .syntheticOpaque (← mvarId.getTag)
|
||
mvarId.assign mvarNew
|
||
return mvarNew.mvarId!
|
||
|
||
/-- Creates a temporary local context where all names are exposed, and executes `k` -/
|
||
def withExposedNames (k : MetaM α) : MetaM α := do
|
||
withNewMCtxDepth <| withLCtx (← getLCtxWithExposedNames) (← getLocalInstances) k
|
||
|
||
end Lean.Meta
|