lean4-htt/src/Lean/Meta/Tactic/ExposeNames.lean
jrr6 b4b878b2d0
fix: prevent exact? and apply? from suggesting invalid tactics (#7192)
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).
2025-02-25 15:24:09 +00:00

66 lines
2.5 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) 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