lean4-htt/tests/elab/specialize_cache_miscompile.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

135 lines
5.1 KiB
Text

import Lean
open Lean Parser
/-!
This test accounts for a specialisation cache bug that was discovered in the Zulip thread
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Miscompilation.20.28incorrect.20code.29.20in.20new.20compiler/near/540037917
if the bug is around the eval at the end of the file evaluates to true instead of false.
-/
namespace Veil
inductive Mutability where
| mutable
| immutable
| inherit
deriving Inhabited, BEq, Hashable, Repr
inductive StateComponentType where
| simple (t : TSyntax ``Command.structSimpleBinder)
| complex (binders : TSyntaxArray ``Term.bracketedBinder) (dom : Term)
deriving Inhabited, BEq
structure StateComponent where
mutability : Mutability
name : Name
type : StateComponentType
deriving Inhabited, BEq
structure Module where
name : Name
signature : Array StateComponent
deriving Inhabited
end Veil
section Util
set_option autoImplicit true
def getSimpleBinderType [Monad m] [MonadError m] (sig : TSyntax `Lean.Parser.Command.structSimpleBinder) : m (TSyntax `term) := do
match sig with
| `(Lean.Parser.Command.structSimpleBinder| $_:ident : $tp:term) => pure tp
| _ => throwError s!"getSimpleBinderType: don't know how to handle {sig}"
def mkArrowStx [Monad m] [MonadQuotation m] [MonadError m] (tps : List Term) (terminator : Option $ TSyntax `term := none) : m (TSyntax `term) := do
match tps with
| [] => if let some t := terminator then return t else throwError "empty list of types and no terminator"
| [a] => match terminator with
| none => `(term| $a)
| some t => `(term| $a -> $t)
| a :: as =>
let cont ← mkArrowStx as terminator
`(term| $a -> $cont)
def complexBinderToSimpleBinder [Monad m] [MonadQuotation m] [MonadError m] (nm : TSyntax `ident) (br : TSyntaxArray `Lean.Parser.Term.bracketedBinder) (domT : TSyntax `term) : m (TSyntax `Lean.Parser.Command.structSimpleBinder) := do
let types ← br.mapM fun m => match m with
| `(bracketedBinder| ($_arg:ident : $tp:term)) => return tp
| _ => throwError "Invalid binder syntax {br}"
let typeStx ← mkArrowStx types.toList domT
let simple ← `(Lean.Parser.Command.structSimpleBinder| $nm:ident : $typeStx)
return simple
end Util
open Lean Parser Elab Command Term
namespace Veil
instance : ToString Mutability where
toString
| Mutability.mutable => "mutable"
| Mutability.immutable => "immutable"
| Mutability.inherit => "inherit"
instance : ToString StateComponentType where
toString
| StateComponentType.simple t => toString t
| StateComponentType.complex b d => s!"{b} : {d}"
instance : ToString StateComponent where
toString sc := s!"{sc.mutability} {sc.name} {sc.type}"
def StateComponentType.stx [Monad m] [MonadQuotation m] [MonadError m] (sct : StateComponentType) : m (TSyntax `term) := do
match sct with
| .simple t => getSimpleBinderType t
| .complex b d => getSimpleBinderType $ ← complexBinderToSimpleBinder (mkIdent Name.anonymous) b d
/-- Returns, e.g., `initial_msg : address → address → round → value → Prop` -/
def StateComponent.getSimpleBinder [Monad m] [MonadQuotation m] [MonadError m] (sc : StateComponent) : m (TSyntax ``Command.structSimpleBinder) := do
match sc.type with
| .simple t => return t
| .complex b d => return ← complexBinderToSimpleBinder (mkIdent sc.name) b d
def StateComponent.stx {m} [Monad m] [MonadQuotation m] [MonadError m] (sc : StateComponent) : m Syntax := sc.getSimpleBinder
def StateComponent.typeStx [Monad m] [MonadQuotation m] [MonadError m] (sc : StateComponent) : m Term := sc.type.stx
def Module.getTheoryBinders [Monad m] [MonadQuotation m] [MonadError m] (mod : Module) : m (Array (TSyntax `Lean.Parser.Term.bracketedBinder)) := do
mod.signature.filterMapM fun sc => do
match sc.mutability with
| .immutable => return .some $ ← `(bracketedBinder| ($(mkIdent sc.name) : $(← sc.typeStx)))
| _ => pure .none
def Module.getStateBinders [Monad m] [MonadQuotation m] [MonadError m] (mod : Module) : m (Array (TSyntax `Lean.Parser.Term.bracketedBinder)) := do
let res ← mod.signature.filterMapM fun sc => do
match sc.mutability with
| .mutable =>
return .some $ ← `(bracketedBinder| ($(mkIdent sc.name) : $(← sc.typeStx)))
| _ =>
-- NOTE 1: uncommenting this line makes `trigger` work correctly
pure .none
return res
-- NOTE 2: commenting out this function (or the `trace` statement) makes `trigger` work correctly
def interference (mod : Module) : CommandElabM Unit := do
trace[veil.debug] "theory binders: {← mod.getTheoryBinders}"
return
end Veil
namespace Veil
open Lean Parser Elab Command
def trigger : CommandElabM Bool := do
let sig : Array StateComponent := #[
{ mutability := .mutable, name := `leader, «type» := .simple $ ← `(Command.structSimpleBinder| x : Nat → Bool)},
{ mutability := .mutable, name := `pending, «type» := .simple $ ← `(Command.structSimpleBinder| pending : Nat → Nat → Bool)}
]
let emptyMod : Module := default
let mod := { emptyMod with signature := sig}
let binders ← mod.getStateBinders
return binders.isEmpty
/-- info: false -/
#guard_msgs in
#eval trigger
end Veil