Zulip Chat Archive
Stream: lean4
Topic: Bug causing stack overflow
Junyan Xu (Jan 08 2024 at 02:36):
The following code crashes Lean:
import Mathlib.Algebra.Algebra.Subalgebra.Basic
example {F E} [CommSemiring F] [Semiring E] [Algebra F E] : Subalgebra F E where
carrier := _
add_mem' := _
mul_mem' := _
algebraMap_mem' := _
This is a more minimal example (thanks to @Kevin Buzzard) than the original crash:
import Mathlib.FieldTheory.IntermediateField
example {F E} [Field F] [Field E] [Algebra F E] : IntermediateField F E where
carrier := _
add_mem' := _
mul_mem' := _
inv_mem' := _
algebraMap_mem' := _
Lean 4 Web reports:
The Lean Server has stopped processing this file:
Server process for file:///LeanProject.lean crashed, likely due to a stack overflow or a bug.
Locally I usually get
Stack overflow detected. Aborting.
but sometimes it's more detailed:
Lean server printed an error: libc++abi: terminating due to uncaught exception of type lean::stack_space_exception: deep recursion was detected at 'expression equality test' (potential solution: increase stack space in your system)
One strange thing: the structure docs#IntermediateField actually has two more fields one_mem'
and zero_mem'
, and if you add both of them then Lean doesn't crash, but it still crashes if you only add one of them. If you remove one of the five fields, it no longer crashes. Strangely, if you don't write any of the field names, Lean's suggestion is missing the zero_mem'
and one_mem'
fields:
fields missing: 'carrier', 'mul_mem'', 'add_mem'', 'algebraMap_mem'', 'inv_mem''
Reproduced 100% of the time.
Yury G. Kudryashov (Jan 08 2024 at 07:01):
I reported another crash recently, and I was told that you need to make a Mathlib-free #mwe if you want it to be investigated.
Kim Morrison (Jan 08 2024 at 08:36):
It doesn't hurt to create an issue on the Lean4 repo to track issues, but realistically the first step of resolving problems like this is to create a Mathlib-free minimisation. We have a label missing mwe
on the Lean4 repo that we can tag report bug reports with that still need this.
Creating a Mathlib free minimisation take some effort, but usually isn't super difficult.
If I've got no idea what the cause is and just want to minimise I follow this algorithm:
- Delete anything from the file that isn't necessary to exhibit the problem. It is particularly helpful to remove proofs! Often it's a good idea to remove structure fields too.
- Delete any imports that aren't necessary, or can be replaced with further upstream imports.
- Take an
import X
, create a newsection X
at the top of the file, and copy and paste the contents ofX
into that section (moving imports to the head of the file). - Repeat these steps until there are no more imports!
In practice one saves lots of time by taking clever shortcuts that circumvent needing some imports completely...
Kim Morrison (Jan 08 2024 at 08:43):
@Anne Baanen bravely attempted to automate a version of this, but in practice it wasn't efficient enough for use.
Kevin Buzzard (Jan 08 2024 at 09:03):
I got this far but I need to do other things now:
import Mathlib.Algebra.Ring.Hom.Defs
import Mathlib.GroupTheory.Submonoid.Basic
class Algebra' (R : Type) (A : Type) [CommSemiring R] [Semiring A] extends R →+* A where
def algebraMap' (R : Type) (A : Type) [CommSemiring R] [Semiring A] [Algebra' R A] : R →+* A :=
Algebra'.toRingHom
structure Subalgebra' (R : Type) (A : Type) [CommSemiring R] [Semiring A] [Algebra' R A] extends
Submonoid A : Type where
algebraMap_mem' : ∀ r, algebraMap' R A r ∈ carrier
one_mem' := (algebraMap' R A).map_one ▸ algebraMap_mem' 1 -- this is the problem
example {F E} [CommSemiring F] [Semiring E] [Algebra' F E] : Subalgebra' F E where
carrier := _
mul_mem' := _
algebraMap_mem' := _
Kevin Buzzard (Jan 08 2024 at 09:03):
Now it's just a matter (hopefully) of dropping in definitions of ring etc
Kevin Buzzard (Jan 08 2024 at 09:30):
Actually I just remembered that I made https://github.com/kbuzzard/MweSkeletons -- maybe I'll spend a little more time on this and see if I can get it over the line.
Kevin Buzzard (Jan 08 2024 at 09:44):
OK so this highly non-minimal but mathlib-free example https://gist.github.com/kbuzzard/931c7ce55d86d9f40e882eb2af2be96c produces the error
Lean server printed an error: libc++abi: terminating due to uncaught exception of type lean::stack_space_exception: deep recursion was detected at 'expression equality test' (potential solution: increase stack space in your system)
for me on Lean (version 4.5.0-rc1, commit b614ff1d12bc, Release)
. Sorry it's a bit of a rush job, I just copied and pasted a few files from that repo I linked to, there will be a whole bunch more minimisation which one can do here (e.g. removing all mention of inv and units) but now I really do have to go.
Kevin Buzzard (Jan 08 2024 at 09:46):
The issue seems to be that in the definition of Subalgebra'
the one_mem'
field has a default entry which for some reason the example doesn't like.
Anne Baanen (Jan 08 2024 at 10:34):
I wanted to try the minimizer script anyway and I can't reproduce the stack overflow in either example:
% lake env lean stack-overflow.lean # Kevin's minimized version
deep recursion was detected at 'expression equality test' (potential solution: increase stack space in your system)
% lake env lean stack-overflow2.lean # Junyan's original version
deep recursion was detected at 'expression equality test' (potential solution: increase stack space in your system)
My system is:
% lean --version
Lean (version 4.5.0-rc1, commit b614ff1d12bc, Release)
% uname -a
Linux McChouffe 6.1.62-1-lts #1 SMP PREEMPT_DYNAMIC Thu, 09 Nov 2023 17:21:17 +0000 x86_64 GNU/Linux
% ulimit -a
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) unlimited
-m: resident set size (kbytes) unlimited
-u: processes 63551
-n: file descriptors 1024
-l: locked-in-memory size (kbytes) 8192
-v: address space (kbytes) unlimited
-x: file locks unlimited
-i: pending signals 63551
-q: bytes in POSIX msg queues 819200
-e: max nice 0
-r: max rt priority 0
-N 15: rt cpu time (microseconds) unlimited
Kevin Buzzard (Jan 08 2024 at 13:01):
I get the same error as you when running the same command as you. The thing I cut and pasted was the output I got from VS Code on the same file (which seems to be the same error wrapped in an explanation that it was an uncaught exception)
Anne Baanen (Jan 08 2024 at 17:14):
Here's a cleaned up version of the autominimizer output on @Kevin Buzzard's results:
class Zero (α : Type u) where
zero : α
instance Zero.toOfNat0 {α} [Zero α] : OfNat α (nat_lit 0) where
ofNat := sorry
class One (α : Type u) where
one : α
instance One.toOfNat1 {α} [One α] : OfNat α (nat_lit 1) where
ofNat := sorry
class MulZeroClass (M₀ : Type _) extends Mul M₀, Zero M₀ where
zero_mul : ∀ a : M₀, 0 * a = 0
mul_zero : ∀ a : M₀, a * 0 = 0
class AddSemigroup (G : Type u) extends Add G where
add_assoc : ∀ a b c : G, a + b + c = a + (b + c)
class Semigroup (G : Type u) extends Mul G where
mul_assoc : ∀ a b c : G, a * b * c = a * (b * c)
class CommSemigroup (G : Type u) extends Semigroup G where
mul_comm : ∀ a b : G, a * b = b * a
class AddCommSemigroup (G : Type u) extends AddSemigroup G where
add_comm : ∀ a b : G, a + b = b + a
class SemigroupWithZero (S₀ : Type _) extends Semigroup S₀, MulZeroClass S₀
class MulOneClass (M : Type u) extends One M, Mul M where
one_mul : ∀ a : M, 1 * a = a
mul_one : ∀ a : M, a * 1 = a
class AddZeroClass (M : Type u) extends Zero M, Add M where
zero_add : ∀ a : M, 0 + a = a
add_zero : ∀ a : M, a + 0 = a
class MulZeroOneClass (M₀ : Type u) extends MulOneClass M₀, MulZeroClass M₀
class AddMonoid (M : Type u) extends AddSemigroup M, AddZeroClass M where
class Monoid (M : Type u) extends Semigroup M, MulOneClass M where
class MonoidWithZero (M₀ : Type u) extends Monoid M₀, MulZeroOneClass M₀, SemigroupWithZero M₀
class AddCommMonoid (M : Type u) extends AddMonoid M, AddCommSemigroup M
class SubNegMonoid (G : Type u) extends AddMonoid G, Neg G, Sub G where
sub a b := sorry
class AddMonoidWithOne (R : Type u) extends AddMonoid R, One R where
class CommMonoid (M : Type u) extends Monoid M, CommSemigroup M
class Distrib (R : Type _) extends Mul R, Add R where
protected left_distrib : ∀ a b c : R, a * (b + c) = a * b + a * c
protected right_distrib : ∀ a b c : R, (a + b) * c = a * c + b * c
class NonUnitalNonAssocSemiring (α : Type u) extends AddCommMonoid α, Distrib α, MulZeroClass α
class AddCommMonoidWithOne (R : Type _) extends AddMonoidWithOne R, AddCommMonoid R
class NonAssocSemiring (α : Type u) extends NonUnitalNonAssocSemiring α, MulZeroOneClass α,
AddCommMonoidWithOne α
class NonUnitalSemiring (α : Type u) extends NonUnitalNonAssocSemiring α, SemigroupWithZero α
class Semiring (α : Type u) extends NonUnitalSemiring α, NonAssocSemiring α, MonoidWithZero α
class CommSemiring (R : Type u) extends Semiring R, CommMonoid R
variable {β : Sort v}
class FunLike (F : Sort _) (α : outParam (Sort _)) (β : outParam <| α → Sort _) where
coe : F → ∀ a : α, β a
variable (F α : Sort _) (β : α → Sort _)
variable {F} [i : FunLike F α β]
instance (priority := 100) hasCoeToFun : CoeFun F fun _ ↦ ∀ a : α, β a where coe := FunLike.coe
structure ZeroHom (M : Type _) (N : Type _) [Zero M] [Zero N] where
toFun : M → N
map_zero' : toFun 0 = 0
class ZeroHomClass (F : Type _) (M N : outParam (Type _)) [Zero M] [Zero N]
extends FunLike F M fun _ => N where
map_zero : ∀ f : F, f 0 = 0
structure OneHom (M : Type _) (N : Type _) [One M] [One N] where
toFun : M → N
map_one' : toFun 1 = 1
class OneHomClass (F : Type _) (M N : outParam (Type _)) [One M] [One N]
extends FunLike F M fun _ => N where
map_one : ∀ f : F, f 1 = 1
structure AddHom (M : Type _) (N : Type _) [Add M] [Add N] where
toFun : M → N
map_add' : ∀ x y, toFun (x + y) = toFun x + toFun y
class AddHomClass (F : Type _) (M N : outParam (Type _)) [Add M] [Add N]
extends FunLike F M fun _ => N where
map_add : ∀ (f : F) (x y : M), f (x + y) = f x + f y
structure MulHom (M : Type _) (N : Type _) [Mul M] [Mul N] where
toFun : M → N
map_mul' : ∀ x y, toFun (x * y) = toFun x * toFun y
infixr:25 " →ₙ* " => MulHom
class MulHomClass (F : Type _) (M N : outParam (Type _)) [Mul M] [Mul N]
extends FunLike F M fun _ => N where
map_mul : ∀ (f : F) (x y : M), f (x * y) = f x * f y
structure AddMonoidHom (M : Type _) (N : Type _) [AddZeroClass M] [AddZeroClass N] extends
ZeroHom M N, AddHom M N
infixr:25 " →+ " => AddMonoidHom
class AddMonoidHomClass (F : Type _) (M N : outParam (Type _)) [AddZeroClass M] [AddZeroClass N]
extends AddHomClass F M N, ZeroHomClass F M N
structure MonoidHom (M : Type _) (N : Type _) [MulOneClass M] [MulOneClass N] extends
OneHom M N, M →ₙ* N
infixr:25 " →* " => MonoidHom
class MonoidHomClass (F : Type _) (M N : outParam (Type _)) [MulOneClass M] [MulOneClass N]
extends MulHomClass F M N, OneHomClass F M N
structure MonoidWithZeroHom (M : Type _) (N : Type _)
[MulZeroOneClass M] [MulZeroOneClass N] extends ZeroHom M N, MonoidHom M N
infixr:25 " →*₀ " => MonoidWithZeroHom
structure NonUnitalRingHom (α β : Type _) [NonUnitalNonAssocSemiring α]
[NonUnitalNonAssocSemiring β] extends α →ₙ* β, α →+ β
class MonoidWithZeroHomClass (F : Type _) (M N : outParam (Type _)) [MulZeroOneClass M]
[MulZeroOneClass N] extends MonoidHomClass F M N, ZeroHomClass F M N
infixr:25 " →ₙ+* " => NonUnitalRingHom
structure RingHom (α : Type _) (β : Type _) [NonAssocSemiring α] [NonAssocSemiring β] extends
α →* β, α →+ β, α →ₙ+* β, α →*₀ β
infixr:25 " →+* " => RingHom
class RingHomClass (F : Type _) (α β : outParam (Type _)) [NonAssocSemiring α]
[NonAssocSemiring β] extends FunLike F α (fun _ => β)
instance instRingHomClass {β : Type _} {_ : NonAssocSemiring α} {_ : NonAssocSemiring β} : RingHomClass (α →+* β) α β where
coe f := sorry
def Set (α : Type u) := α → Prop
instance : Membership α (Set α) := sorry
structure Subsemigroup (M : Type _) [Mul M] where
carrier : Set M
mul_mem' {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier
structure Submonoid (M : Type _) [MulOneClass M] extends Subsemigroup M where
one_mem' : (1 : M) ∈ carrier
class Algebra' (R : Type) (A : Type) [CommSemiring R] [Semiring A] extends R →+* A where
def algebraMap' (R : Type) (A : Type) [CommSemiring R] [Semiring A] [Algebra' R A] : R →+* A := sorry
protected theorem RingHom.map_one {α β : Type _} [Semiring α] [Semiring β] (f : α →+* β) : f 1 = 1 := sorry
structure Subalgebra' (R : Type) (A : Type) [CommSemiring R] [Semiring A] [Algebra' R A] extends
Submonoid A : Type where
algebraMap_mem' : ∀ r, algebraMap' R A r ∈ carrier
one_mem' := (algebraMap' R A).map_one ▸ algebraMap_mem' 1
example {F E} [CommSemiring F] [Semiring E] [Algebra' F E] : Subalgebra' F E where
carrier := _
mul_mem' := _
algebraMap_mem' := _
Somehow it figured out you can delete some lines in the file and cause Lean to crash before it detects the resulting errors. I fixed that up so there should only be warnings and then the Lean crash.
Kevin Buzzard (Jan 08 2024 at 17:25):
Nice! I've removed all mentions of 0 and +, and it's now down to this:
class One (α : Type u) where
one : α
instance One.toOfNat1 {α} [One α] : OfNat α (nat_lit 1) where
ofNat := sorry
class Semigroup (G : Type u) extends Mul G where
mul_assoc : ∀ a b c : G, a * b * c = a * (b * c)
class CommSemigroup (G : Type u) extends Semigroup G where
mul_comm : ∀ a b : G, a * b = b * a
class MulOneClass (M : Type u) extends One M, Mul M where
one_mul : ∀ a : M, 1 * a = a
mul_one : ∀ a : M, a * 1 = a
class Monoid (M : Type u) extends Semigroup M, MulOneClass M where
class CommMonoid (M : Type u) extends Monoid M, CommSemigroup M
variable {β : Sort v}
class FunLike (F : Sort _) (α : outParam (Sort _)) (β : outParam <| α → Sort _) where
coe : F → ∀ a : α, β a
variable (F α : Sort _) (β : α → Sort _)
variable {F} [i : FunLike F α β]
instance (priority := 100) hasCoeToFun : CoeFun F fun _ ↦ ∀ a : α, β a where coe := FunLike.coe
structure OneHom (M : Type _) (N : Type _) [One M] [One N] where
toFun : M → N
map_one' : toFun 1 = 1
class OneHomClass (F : Type _) (M N : outParam (Type _)) [One M] [One N]
extends FunLike F M fun _ => N where
map_one : ∀ f : F, f 1 = 1
structure MulHom (M : Type _) (N : Type _) [Mul M] [Mul N] where
toFun : M → N
map_mul' : ∀ x y, toFun (x * y) = toFun x * toFun y
infixr:25 " →ₙ* " => MulHom
class MulHomClass (F : Type _) (M N : outParam (Type _)) [Mul M] [Mul N]
extends FunLike F M fun _ => N where
map_mul : ∀ (f : F) (x y : M), f (x * y) = f x * f y
structure MonoidHom (M : Type _) (N : Type _) [MulOneClass M] [MulOneClass N] extends
OneHom M N, M →ₙ* N
infixr:25 " →* " => MonoidHom
class MonoidHomClass (F : Type _) (M N : outParam (Type _)) [MulOneClass M] [MulOneClass N]
extends MulHomClass F M N, OneHomClass F M N
instance instMonoidHomClass {β : Type _} {_ : Monoid α} {_ : Monoid β} : MonoidHomClass (α →* β) α β where
coe f := sorry
map_one := sorry
map_mul := sorry
def Set (α : Type u) := α → Prop
instance : Membership α (Set α) := sorry
structure Subsemigroup (M : Type _) [Mul M] where
carrier : Set M
mul_mem' {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier
structure Submonoid (M : Type _) [MulOneClass M] extends Subsemigroup M where
one_mem' : (1 : M) ∈ carrier
class Algebra' (R : Type) (A : Type) [Monoid R] [Monoid A] extends R →* A where
def algebraMap' (R : Type) (A : Type) [Monoid R] [Monoid A] [Algebra' R A] : R →* A := Algebra'.toMonoidHom
protected theorem MonoidHom.map_one {α β : Type _} [Monoid α] [Monoid β] (f : α →* β) : f 1 = 1 := sorry
structure Subalgebra' (R : Type) (A : Type) [Monoid R] [Monoid A] [Algebra' R A] extends
Submonoid A : Type where
algebraMap_mem' : ∀ r, algebraMap' R A r ∈ carrier
one_mem' := (algebraMap' R A).map_one ▸ algebraMap_mem' 1
example {F E} [Monoid F] [Monoid E] [Algebra' F E] : Subalgebra' F E where
carrier := _
mul_mem' := _
algebraMap_mem' := _
Anne Baanen (Jan 08 2024 at 17:34):
Here's my final contribution of today: the output of your further minimalization on brutal mode. It reproduces the crash but also has tons of extra errors:
class One (α : Type u) where
instance One.toOfNat1 {α} [One α] : OfNat α (nat_lit 1) where
class Semigroup (G : Type u) extends Mul G where
class MulOneClass (M : Type u) extends One M, Mul M where
class Monoid (M : Type u) extends Semigroup M, MulOneClass M where
class FunLike (F : Sort _) (α : outParam (Sort _)) (β : outParam <| α → Sort _) where
coe : F → ∀ a : α, β a
variable {F} [i : FunLike F α β]
instance (priority := 100) hasCoeToFun : CoeFun F fun _ ↦ ∀ a : α, β a where coe := FunLike.coe
structure OneHom (M : Type _) (N : Type _) [One M] [One N] where
class OneHomClass (F : Type _) (M N : outParam (Type _)) [One M] [One N]
extends FunLike F M fun _ => N where
structure MulHom (M : Type _) (N : Type _) [Mul M] [Mul N] where
class MulHomClass (F : Type _) (M N : outParam (Type _)) [Mul M] [Mul N]
structure MonoidHom (M : Type _) (N : Type _) [MulOneClass M] [MulOneClass N] extends
OneHom M N, MulHom M N
class MonoidHomClass (F : Type _) (M N : outParam (Type _)) [MulOneClass M] [MulOneClass N]
extends MulHomClass F M N, OneHomClass F M N
instance instMonoidHomClass {β : Type _} {_ : Monoid α} {_ : Monoid β} : MonoidHomClass (MonoidHom α β) α β where
def Set (α : Type u) := α → Prop
instance : Membership α (Set α) := sorry
structure Subsemigroup (M : Type _) [Mul M] where
carrier : Set M
mul_mem' {a b} : a ∈ carrier → b ∈ carrier → a * b ∈ carrier
structure Submonoid (M : Type _) [MulOneClass M] extends Subsemigroup M where
one_mem' : (1 : M) ∈ carrier
class Algebra' (R : Type) (A : Type) [Monoid R] [Monoid A] extends MonoidHom R A where
def algebraMap' (R : Type) (A : Type) [Monoid R] [Monoid A] [Algebra' R A] : MonoidHom R A := sorry
protected theorem MonoidHom.map_one {α β : Type _} [Monoid α] [Monoid β] (f : MonoidHom α β) : f 1 = 1 := sorry
structure Subalgebra' (R : Type) (A : Type) [Monoid R] [Monoid A] [Algebra' R A] extends
Submonoid A : Type where
algebraMap_mem' : ∀ r, algebraMap' R A r ∈ carrier
one_mem' := (algebraMap' R A).map_one ▸ algebraMap_mem' 1
example {F E} [Monoid F] [Monoid E] [Algebra' F E] : Subalgebra' F E where
carrier := _
mul_mem' := _
algebraMap_mem' := _
Kevin Buzzard (Jan 08 2024 at 17:35):
I can even remove mul
:
class One (α : Type) where
one : α
instance One.toOfNat1 {α} [One α] : OfNat α (nat_lit 1) where
ofNat := sorry
class FunLike (F : Type) (α : outParam Type) (β : outParam <| α → Sort _) where
coe : F → ∀ a : α, β a
variable (F α : Type) (β : α → Type)
variable {F} [i : FunLike F α β]
instance (priority := 100) hasCoeToFun : CoeFun F fun _ ↦ ∀ a : α, β a where coe := FunLike.coe
structure OneHom (M : Type) (N : Type _) [One M] [One N] where
toFun : M → N
map_one' : toFun 1 = 1
class OneHomClass (F : Type) (M N : outParam Type) [One M] [One N]
extends FunLike F M fun _ => N where
map_one : ∀ f : F, f 1 = 1
infixr:25 " →1 " => OneHom
instance instOneHomClass {β : Type} {_ : One α} {_ : One β} : OneHomClass (α →1 β) α β where
coe f := sorry
map_one := sorry
def Set (α : Type) := α → Prop
instance : Membership α (Set α) := sorry
structure Subone (M : Type) [One M] where
carrier : Set M
one_mem' : (1 : M) ∈ carrier
class Algebra' (R : Type) (A : Type) [One R] [One A] extends R →1 A where
def algebraMap' (R : Type) (A : Type) [One R] [One A] [Algebra' R A] : R →1 A := Algebra'.toOneHom
protected theorem OneHom.map_one {α β : Type _} [One α] [One β] (f : α →1 β) : f 1 = 1 := sorry
structure Subalgebra' (R : Type) (A : Type) [One R] [One A] [Algebra' R A] extends
Subone A : Type where
algebraMap_mem' : ∀ r, algebraMap' R A r ∈ carrier
one_mem' := (algebraMap' R A).map_one ▸ algebraMap_mem' 1
example {F E} [One F] [One E] [Algebra' F E] : Subalgebra' F E where
carrier := _
algebraMap_mem' := _
Kevin Buzzard (Jan 08 2024 at 17:38):
I'm not intending on taking this further now; hopefully now this is reasonable enough to start thinking about debugging? Thanks Anne for your help! It inspired me to go further now my workday is over :-)
Junyan Xu (Jan 08 2024 at 18:10):
Thanks all for the suggestion, diagnosis, and inspirations. I'm now able to reduce it to 20 lines:
class One (α : Type) where
one : α
variable (R A : Type) [One R] [One A]
class OneHom where
toFun : R → A
map_one : toFun One.one = One.one
structure Subone where
mem : R → Prop
one_mem : mem One.one
structure Subalgebra [OneHom R A] extends Subone A : Type where
algebraMap_mem : ∀ r : R, mem (OneHom.toFun r)
one_mem := OneHom.map_one (R := R) (A := A) ▸ algebraMap_mem One.one
example [OneHom R A] : Subalgebra R A where
mem := _
algebraMap_mem := _
Junyan Xu (Jan 08 2024 at 18:23):
Junyan Xu (Jan 09 2024 at 07:33):
It might be helpful to bisect to find out which Lean 4 commit caused this ...
Mario Carneiro (Jan 09 2024 at 07:59):
Is this actually new?
Junyan Xu (Jan 09 2024 at 08:00):
It seems anyone who tries to construct a Subalgebra will discover this ...
Junyan Xu (Jan 09 2024 at 08:07):
Lean only crashes when you put placeholders there, it doesn't crash if you fill the placeholders with something that compiles. So the crash cannot be discovered by compiling mathlib. For example this doesn't crash:
variable {R A : Type} (r : R) (a : A)
structure Subone where
mem : R → Prop
one_mem : mem r
variable {f : R → A} (hf : f r = a)
structure Subalgebra extends Subone a : Type where
algebraMap_mem (r : R) : mem (f r)
one_mem := cast (congrArg mem hf) (algebraMap_mem r) -- changing ▸ to explicit `cast` has no effect
example : Subalgebra r a hf where
mem := fun _ ↦ True
algebraMap_mem := fun _ ↦ trivial
Yury G. Kudryashov (Jan 09 2024 at 08:19):
I guess, with placeholders it tries to find them by unification, then something breaks.
Junyan Xu (Jan 09 2024 at 17:27):
It turns out the crash already happens in 4.0.0-m2 (3 years ago)
Newell Jensen (Feb 16 2024 at 14:07):
I am running into this with linting on #7479
...
info: [68/68] Linking runLinter
libc++abi: terminating due to uncaught exception of type lean::stack_space_exception: deep recursion was detected at 'expression equality test' (potential solution: increase stack space in your system)
Anyone know how to fix this?
Jovan Gerbscheid (Nov 08 2024 at 00:50):
I found a much smaller example that crashes with a stack overflow:
def test (a : String) : String :=
let x : String → String := _
have : x = 10 := by rfl
(the String
types can be replaced with any other type)
From the stack trace we can see the source of the infinite recursion. It is a mutual block in MetavarContext.lean
, and has the following pattern of function calls appearing repeatedly:
mkAuxMVarType.abstractRangeAux
mkAuxMVarType
elimMVar
elimApp
visit
Array.mapMUnsafe.map._at._private.src.Lean.MetavarContext.0.Lean.MetavarContext.MkBinding.elimApp._spec_6
elimApp
visit
elimApp
visit
elim
(the top of the list corresponds to the top of the stack, so each function calls the one above it)
This infinite loop is reached via a call to mkLambdaFVars
, which calls mkBinding
. In particular this call in elabFunValues
in MutualDef.lean
. So the particular lambda that is trying to be created is
fun a : String =>
let x : String → String := _
have : x = 10 := by rfl
Using binary search I found that the stack overflow happens in version 4.9.0 and not in 4.8.0.
Kim Morrison (Nov 08 2024 at 09:34):
git bisect
... is tricky. :-) Still working on this.
Kim Morrison (Nov 08 2024 at 10:28):
@Sebastian Ullrich, unfortunately this is an incrementality bug, which appears at lean#3940, commit f97a7d4234bd76bc0f61e43b8c6a78117c1376df
Kim Morrison (Nov 08 2024 at 10:29):
@Jovan Gerbscheid, would you mind posting your example as new issue, including the fact that it breaks as of lean#3940?
Jovan Gerbscheid (Nov 08 2024 at 13:41):
Jovan Gerbscheid (Nov 14 2024 at 04:32):
I have figured out the cause of the stack overflow. It is a violation of the type occurs check. And the stack overflow in lean#3150 is caused by the same problem.
Jovan Gerbscheid (Nov 14 2024 at 04:38):
In lean#3150, the problem looks like this:
?m : { α := Nat, a := id ?m }.α
And in lean#6013, the problem looks like this:
?m1 := @OfNat.ofNat (String → String) 10 ?m2
?m2 : let x := ?m1;
OfNat (String → String) 10
As we can see, both of these type occurs check failures can be made to disappear after a sufficient amount of reducing the type, so they are not inherently bad. But mkLambdaFVars
has trouble dealing with them.
Junyan Xu (Nov 14 2024 at 08:48):
But lean4#3150 occured as early as 4.0.0-m2. So lean4#3940 just made it easier to trigger an old bug?
Sebastian Ullrich (Nov 14 2024 at 12:45):
yes
Jovan Gerbscheid (Nov 14 2024 at 16:07):
I can see two ways to fix this:
- change unification/elaboration such that a metavariable type occurrence can't happen. This is tricky, because when assigning metavariables in unification, it explicitly allows some type occurrence to happen, knowing that it will be reduced away later.
- change the free variable elimination procedure so that it can deal with metavariable type occurrences.
I have a fix here that does the latter: lean#6079
Last updated: May 02 2025 at 03:31 UTC