fix: where finally should enter the private scope (#10151)

This PR ensures `where finally` tactics can access private data under
the module system even when the corresponding holes are in the public
scope as long as all of them are of proposition types.
This commit is contained in:
Sebastian Ullrich 2025-08-27 13:27:40 +02:00 committed by GitHub
parent 43dc9f45d1
commit 4d5fb31dfb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 3 deletions

View file

@ -656,20 +656,44 @@ private def ExprWithHoles.getHoles (e : ExprWithHoles) : TermElabM (Array MVarId
private def fillHolesFromWhereFinally (name : Name) (es : Array ExprWithHoles) (whereFinally : WhereFinallyView) : TermElabM PUnit := do
if whereFinally.isNone then return
let goals := (← es.mapM fun e => e.getHoles).flatten
-- Exit exporting context if entering proof(s), analogous to `Term.runTactic`.
-- NOTE: when entering a proof/data mix, we must conservatively default to not changing the
-- context.
let wasExporting := (← getEnv).isExporting
let isNoLongerExporting ← pure wasExporting <&&> goals.allM fun mvarId => do
mvarId.withContext do
isProp (← mvarId.getType)
let mut goals' := goals
if isNoLongerExporting then
goals' ← goals.mapM fun mvarId => do
let mvarDecl ← getMVarDecl mvarId
return (← mkFreshExprMVarAt mvarDecl.lctx mvarDecl.localInstances mvarDecl.type mvarDecl.kind mvarDecl.userName).mvarId!
withExporting (isExporting := wasExporting && !isNoLongerExporting) do
Lean.Elab.Term.TermElabM.run' do
Term.withDeclName name do
withRef whereFinally.ref do
unless goals.isEmpty do
-- make info from `runTactic` available
goals.forM fun goal => pushInfoTree (.hole goal)
goals'.forM fun goal => pushInfoTree (.hole goal)
-- assign goals
let remainingGoals ← Tactic.run goals[0]! do
Tactic.setGoals goals.toList
let remainingGoals ← Tactic.run goals'[0]! do
Tactic.setGoals goals'.toList
Tactic.withTacticInfoContext whereFinally.ref do
Tactic.evalTactic whereFinally.tactic
-- complain if any goals remain
unless remainingGoals.isEmpty do
Term.reportUnsolvedGoals remainingGoals
if isNoLongerExporting then
for mvarId in goals, mvarId' in goals' do
let mut e ← instantiateExprMVars (.mvar mvarId')
if !e.isFVar then
e ← mvarId'.withContext do
withExporting (isExporting := wasExporting) do
abstractProof e
mvarId.assign e
namespace MutualClosure

View file

@ -1,3 +1,7 @@
module
public section
example (i j : Nat) (xs : Array Nat) (hi : i < xs.size) (hj: j < xs.size) :=
match i with
| 0 => x
@ -113,3 +117,11 @@ def hole_decreasing_does_not_exist (i : Nat) (xs : Array Nat) (h : i < xs.size)
where finally
case hole => exact h
| decreasing => skip
/-! `where finally` should open a private scope. -/
private theorem priv : True := .intro
@[expose] def pub : True := ?_
where finally
exact priv