mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-17 10:24:07 +00:00
feat: add declaration name to leanchecker error messages (#12525)
This PR adds declaration names to leanchecker error messages to make debugging easier when the kernel rejects a declaration. Previously, leanchecker would only show the kernel error without identifying which declaration failed: ``` uncaught exception: (kernel) type checker does not support loose bound variables ``` Now it includes the declaration name: ``` uncaught exception: while replaying declaration 'myDecl': (kernel) type checker does not support loose bound variables ``` Fixes: #11937 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nomeata <148037+nomeata@users.noreply.github.com>
This commit is contained in:
@@ -77,45 +77,48 @@ partial def replayConstant (name : Name) : M Unit := do
|
||||
replayConstants ci.getUsedConstantsAsSet
|
||||
-- Check that this name is still pending: a mutual block may have taken care of it.
|
||||
if (← get).pending.contains name then
|
||||
match ci with
|
||||
| .defnInfo info =>
|
||||
addDecl (Declaration.defnDecl info)
|
||||
| .thmInfo info =>
|
||||
addDecl (Declaration.thmDecl info)
|
||||
| .axiomInfo info =>
|
||||
addDecl (Declaration.axiomDecl info)
|
||||
| .opaqueInfo info =>
|
||||
addDecl (Declaration.opaqueDecl info)
|
||||
| .inductInfo info =>
|
||||
let lparams := info.levelParams
|
||||
let nparams := info.numParams
|
||||
let all ← info.all.mapM fun n => do pure <| ((← read).newConstants[n]!)
|
||||
for o in all do
|
||||
modify fun s =>
|
||||
{ s with remaining := s.remaining.erase o.name, pending := s.pending.erase o.name }
|
||||
let ctorInfo ← all.mapM fun ci => do
|
||||
pure (ci, ← ci.inductiveVal!.ctors.mapM fun n => do
|
||||
pure ((← read).newConstants[n]!))
|
||||
-- Make sure we are really finished with the constructors.
|
||||
for (_, ctors) in ctorInfo do
|
||||
for ctor in ctors do
|
||||
replayConstants ctor.getUsedConstantsAsSet
|
||||
let types : List InductiveType := ctorInfo.map fun ⟨ci, ctors⟩ =>
|
||||
{ name := ci.name
|
||||
type := ci.type
|
||||
ctors := ctors.map fun ci => { name := ci.name, type := ci.type } }
|
||||
addDecl (Declaration.inductDecl lparams nparams types false)
|
||||
-- We postpone checking constructors,
|
||||
-- and at the end make sure they are identical
|
||||
-- to the constructors generated when we replay the inductives.
|
||||
| .ctorInfo info =>
|
||||
modify fun s => { s with postponedConstructors := s.postponedConstructors.insert info.name }
|
||||
-- Similarly we postpone checking recursors.
|
||||
| .recInfo info =>
|
||||
modify fun s => { s with postponedRecursors := s.postponedRecursors.insert info.name }
|
||||
| .quotInfo _ =>
|
||||
addDecl (Declaration.quotDecl)
|
||||
modify fun s => { s with pending := s.pending.erase name }
|
||||
try
|
||||
match ci with
|
||||
| .defnInfo info =>
|
||||
addDecl (Declaration.defnDecl info)
|
||||
| .thmInfo info =>
|
||||
addDecl (Declaration.thmDecl info)
|
||||
| .axiomInfo info =>
|
||||
addDecl (Declaration.axiomDecl info)
|
||||
| .opaqueInfo info =>
|
||||
addDecl (Declaration.opaqueDecl info)
|
||||
| .inductInfo info =>
|
||||
let lparams := info.levelParams
|
||||
let nparams := info.numParams
|
||||
let all ← info.all.mapM fun n => do pure <| ((← read).newConstants[n]!)
|
||||
for o in all do
|
||||
modify fun s =>
|
||||
{ s with remaining := s.remaining.erase o.name, pending := s.pending.erase o.name }
|
||||
let ctorInfo ← all.mapM fun ci => do
|
||||
pure (ci, ← ci.inductiveVal!.ctors.mapM fun n => do
|
||||
pure ((← read).newConstants[n]!))
|
||||
-- Make sure we are really finished with the constructors.
|
||||
for (_, ctors) in ctorInfo do
|
||||
for ctor in ctors do
|
||||
replayConstants ctor.getUsedConstantsAsSet
|
||||
let types : List InductiveType := ctorInfo.map fun ⟨ci, ctors⟩ =>
|
||||
{ name := ci.name
|
||||
type := ci.type
|
||||
ctors := ctors.map fun ci => { name := ci.name, type := ci.type } }
|
||||
addDecl (Declaration.inductDecl lparams nparams types false)
|
||||
-- We postpone checking constructors,
|
||||
-- and at the end make sure they are identical
|
||||
-- to the constructors generated when we replay the inductives.
|
||||
| .ctorInfo info =>
|
||||
modify fun s => { s with postponedConstructors := s.postponedConstructors.insert info.name }
|
||||
-- Similarly we postpone checking recursors.
|
||||
| .recInfo info =>
|
||||
modify fun s => { s with postponedRecursors := s.postponedRecursors.insert info.name }
|
||||
| .quotInfo _ =>
|
||||
addDecl (Declaration.quotDecl)
|
||||
modify fun s => { s with pending := s.pending.erase name }
|
||||
catch ex =>
|
||||
throw <| .userError s!"while replaying declaration '{name}':\n{ex}"
|
||||
|
||||
/-- Replay a set of constants one at a time. -/
|
||||
partial def replayConstants (names : NameSet) : M Unit := do
|
||||
|
||||
@@ -82,60 +82,63 @@ partial def replayConstant (name : Name) : M Unit := do
|
||||
replayConstants ci.getUsedConstantsAsSet
|
||||
-- Check that this name is still pending: a mutual block may have taken care of it.
|
||||
if (← get).pending.contains name then
|
||||
match ci with
|
||||
| .defnInfo info =>
|
||||
addDecl (Declaration.defnDecl info)
|
||||
| .thmInfo info =>
|
||||
-- Ignore duplicate theorems. This code is identical to that in `finalizeImport` before it
|
||||
-- added extended duplicates support for the module system, which is not relevant for us
|
||||
-- here as we always load all .olean information. We need this case *because* of the module
|
||||
-- system -- as we have more data loaded than it, we might encounter duplicate private
|
||||
-- theorems where elaboration under the module system would have only one of them in scope.
|
||||
if let some (.thmInfo info') := (← get).env.find? ci.name then
|
||||
if info.name == info'.name &&
|
||||
info.type == info'.type &&
|
||||
info.levelParams == info'.levelParams &&
|
||||
info.all == info'.all
|
||||
then
|
||||
return
|
||||
addDecl (Declaration.thmDecl info)
|
||||
| .axiomInfo info =>
|
||||
addDecl (Declaration.axiomDecl info)
|
||||
| .opaqueInfo info =>
|
||||
addDecl (Declaration.opaqueDecl info)
|
||||
| .inductInfo info =>
|
||||
let lparams := info.levelParams
|
||||
let nparams := info.numParams
|
||||
let all ← info.all.mapM fun n => do pure <| ((← read).newConstants[n]!)
|
||||
for o in all do
|
||||
modify fun s =>
|
||||
{ s with remaining := s.remaining.erase o.name, pending := s.pending.erase o.name }
|
||||
let ctorInfo ← all.mapM fun ci => do
|
||||
pure (ci, ← ci.inductiveVal!.ctors.mapM fun n => do
|
||||
pure ((← read).newConstants[n]!))
|
||||
-- Make sure we are really finished with the constructors.
|
||||
for (_, ctors) in ctorInfo do
|
||||
for ctor in ctors do
|
||||
replayConstants ctor.getUsedConstantsAsSet
|
||||
let types : List InductiveType := ctorInfo.map fun ⟨ci, ctors⟩ =>
|
||||
{ name := ci.name
|
||||
type := ci.type
|
||||
ctors := ctors.map fun ci => { name := ci.name, type := ci.type } }
|
||||
addDecl (Declaration.inductDecl lparams nparams types false)
|
||||
-- We postpone checking constructors,
|
||||
-- and at the end make sure they are identical
|
||||
-- to the constructors generated when we replay the inductives.
|
||||
| .ctorInfo info =>
|
||||
modify fun s => { s with postponedConstructors := s.postponedConstructors.insert info.name }
|
||||
-- Similarly we postpone checking recursors.
|
||||
| .recInfo info =>
|
||||
modify fun s => { s with postponedRecursors := s.postponedRecursors.insert info.name }
|
||||
| .quotInfo _ =>
|
||||
-- `Quot.lift` and `Quot.ind` have types that reference `Eq`,
|
||||
-- so we need to ensure `Eq` is replayed before adding the quotient declaration.
|
||||
replayConstant `Eq
|
||||
addDecl (Declaration.quotDecl)
|
||||
modify fun s => { s with pending := s.pending.erase name }
|
||||
try
|
||||
match ci with
|
||||
| .defnInfo info =>
|
||||
addDecl (Declaration.defnDecl info)
|
||||
| .thmInfo info =>
|
||||
-- Ignore duplicate theorems. This code is identical to that in `finalizeImport` before it
|
||||
-- added extended duplicates support for the module system, which is not relevant for us
|
||||
-- here as we always load all .olean information. We need this case *because* of the module
|
||||
-- system -- as we have more data loaded than it, we might encounter duplicate private
|
||||
-- theorems where elaboration under the module system would have only one of them in scope.
|
||||
if let some (.thmInfo info') := (← get).env.find? ci.name then
|
||||
if info.name == info'.name &&
|
||||
info.type == info'.type &&
|
||||
info.levelParams == info'.levelParams &&
|
||||
info.all == info'.all
|
||||
then
|
||||
return
|
||||
addDecl (Declaration.thmDecl info)
|
||||
| .axiomInfo info =>
|
||||
addDecl (Declaration.axiomDecl info)
|
||||
| .opaqueInfo info =>
|
||||
addDecl (Declaration.opaqueDecl info)
|
||||
| .inductInfo info =>
|
||||
let lparams := info.levelParams
|
||||
let nparams := info.numParams
|
||||
let all ← info.all.mapM fun n => do pure <| ((← read).newConstants[n]!)
|
||||
for o in all do
|
||||
modify fun s =>
|
||||
{ s with remaining := s.remaining.erase o.name, pending := s.pending.erase o.name }
|
||||
let ctorInfo ← all.mapM fun ci => do
|
||||
pure (ci, ← ci.inductiveVal!.ctors.mapM fun n => do
|
||||
pure ((← read).newConstants[n]!))
|
||||
-- Make sure we are really finished with the constructors.
|
||||
for (_, ctors) in ctorInfo do
|
||||
for ctor in ctors do
|
||||
replayConstants ctor.getUsedConstantsAsSet
|
||||
let types : List InductiveType := ctorInfo.map fun ⟨ci, ctors⟩ =>
|
||||
{ name := ci.name
|
||||
type := ci.type
|
||||
ctors := ctors.map fun ci => { name := ci.name, type := ci.type } }
|
||||
addDecl (Declaration.inductDecl lparams nparams types false)
|
||||
-- We postpone checking constructors,
|
||||
-- and at the end make sure they are identical
|
||||
-- to the constructors generated when we replay the inductives.
|
||||
| .ctorInfo info =>
|
||||
modify fun s => { s with postponedConstructors := s.postponedConstructors.insert info.name }
|
||||
-- Similarly we postpone checking recursors.
|
||||
| .recInfo info =>
|
||||
modify fun s => { s with postponedRecursors := s.postponedRecursors.insert info.name }
|
||||
| .quotInfo _ =>
|
||||
-- `Quot.lift` and `Quot.ind` have types that reference `Eq`,
|
||||
-- so we need to ensure `Eq` is replayed before adding the quotient declaration.
|
||||
replayConstant `Eq
|
||||
addDecl (Declaration.quotDecl)
|
||||
modify fun s => { s with pending := s.pending.erase name }
|
||||
catch ex =>
|
||||
throw <| .userError s!"while replaying declaration '{name}':\n{ex}"
|
||||
|
||||
/-- Replay a set of constants one at a time. -/
|
||||
partial def replayConstants (names : NameSet) : M Unit := do
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
leanchecker found a problem in LeanCheckerTests.AddFalse
|
||||
uncaught exception: (kernel) declaration type mismatch, 'false' has type
|
||||
uncaught exception: while replaying declaration 'false':
|
||||
(kernel) declaration type mismatch, 'false' has type
|
||||
Prop
|
||||
but it is expected to have type
|
||||
False
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
leanchecker found a problem in LeanCheckerTests.ReplaceAxiom
|
||||
uncaught exception: (kernel) application type mismatch
|
||||
uncaught exception: while replaying declaration 'efsq':
|
||||
(kernel) application type mismatch
|
||||
False.elim @propext
|
||||
argument has type
|
||||
∀ {a b : Prop}, Iff a b → Eq a b
|
||||
|
||||
Reference in New Issue
Block a user