fix: instantiate metavariables when collecting a goal's constants (#13748)
This PR fixes premise selection silently dropping relevant premises when
the goal was reached via `induction`.
`MVarId.getRelevantConstants` and `MVarId.getConstants` walked the raw
goal type returned by `getType`, which after `induction` is `?motive
arg` with `?motive` an assigned-but-unsubstituted metavariable. The
constant fold treats the metavariable as an opaque leaf, so every
constant in the goal predicate is lost. Instantiating metavariables
first recovers them.
Thanks to Xavier Généreux for the report.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5d22886aff
commit
6d5ec050f4
3 changed files with 42 additions and 4 deletions
|
|
@ -101,16 +101,26 @@ end Lean.Expr
|
|||
|
||||
open Lean Meta MVarId in
|
||||
public def Lean.MVarId.getConstants (g : MVarId) : MetaM NameSet := withContext g do
|
||||
let mut c := (← g.getType).getUsedConstantsAsSet
|
||||
-- `instantiateMVars` is needed so that constants are not lost behind assigned
|
||||
-- metavariables, e.g. the `?motive` left in a goal reached via `induction`.
|
||||
-- Note: this does not recover constants behind non-ground delayed-assigned
|
||||
-- metavariables. Without evidence this matters for premise selection,
|
||||
-- for now we avoid the extra complexity of walking the metavariable graph.
|
||||
let mut c := (← instantiateMVars (← g.getType)).getUsedConstantsAsSet
|
||||
for t in (← getLocalHyps) do
|
||||
c := c ∪ (← inferType t).getUsedConstantsAsSet
|
||||
c := c ∪ (← instantiateMVars (← inferType t)).getUsedConstantsAsSet
|
||||
return c
|
||||
|
||||
open Lean Meta MVarId in
|
||||
public def Lean.MVarId.getRelevantConstants (g : MVarId) : MetaM NameSet := withContext g do
|
||||
let mut c ← (← g.getType).relevantConstantsAsSet
|
||||
-- `instantiateMVars` is needed so that constants are not lost behind assigned
|
||||
-- metavariables, e.g. the `?motive` left in a goal reached via `induction`.
|
||||
-- Note: this does not recover constants behind non-ground delayed-assigned
|
||||
-- metavariables. Without evidence this matters for premise selection,
|
||||
-- for now we avoid the extra complexity of walking the metavariable graph.
|
||||
let mut c ← (← instantiateMVars (← g.getType)).relevantConstantsAsSet
|
||||
for t in (← getLocalHyps) do
|
||||
c := c ∪ (← (← inferType t).relevantConstantsAsSet)
|
||||
c := c ∪ (← (← instantiateMVars (← inferType t)).relevantConstantsAsSet)
|
||||
return c
|
||||
|
||||
@[expose] public section
|
||||
|
|
|
|||
27
tests/elab/library_suggestions_relevant_constants.lean
Normal file
27
tests/elab/library_suggestions_relevant_constants.lean
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import Lean.LibrarySuggestions.Basic
|
||||
|
||||
/-!
|
||||
Regression test: `MVarId.getRelevantConstants` must instantiate metavariables
|
||||
in the goal type before collecting constants.
|
||||
|
||||
A goal reached via `induction` has type `?motive arg`, where `?motive` is an
|
||||
assigned-but-unsubstituted metavariable. Without `instantiateMVars`, the
|
||||
constant fold treats `?motive` as an opaque leaf, so every constant occurring
|
||||
in the goal predicate is lost.
|
||||
-/
|
||||
|
||||
open Lean Lean.Elab.Tactic
|
||||
|
||||
axiom MyP : Nat → Prop
|
||||
|
||||
example : ∀ n : Nat, MyP n := by
|
||||
intro n
|
||||
induction n with
|
||||
| zero =>
|
||||
run_tac do
|
||||
let c ← (← getMainGoal).getRelevantConstants
|
||||
unless c.contains ``MyP do
|
||||
throwError "getRelevantConstants missed `MyP` hidden behind the \
|
||||
induction motive metavariable"
|
||||
sorry
|
||||
| succ k ih => sorry
|
||||
|
|
@ -0,0 +1 @@
|
|||
library_suggestions_relevant_constants.lean:17:0-17:7: warning: declaration uses `sorry`
|
||||
Loading…
Add table
Reference in a new issue