From d3ace4be5663548799db9ef723861bf8a2ef487d Mon Sep 17 00:00:00 2001 From: Andy Dienes Date: Tue, 1 Jul 2025 10:33:44 -0400 Subject: [PATCH 1/3] fix == and show on self-referential arrays --- base/abstractarray.jl | 3 +++ base/arrayshow.jl | 12 ++++++++---- test/abstractarray.jl | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 94bf3170feb38..f1668d6f467a1 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -3029,6 +3029,9 @@ Return `true` when `A` is less than `B` in lexicographic order. isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0 function (==)(A::AbstractArray, B::AbstractArray) + if A === B + return true + end if axes(A) != axes(B) return false end diff --git a/base/arrayshow.jl b/base/arrayshow.jl index f792d26d8e9b5..554832bdc47de 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -442,7 +442,9 @@ function _show_nonempty(io::IO, @nospecialize(X::AbstractMatrix), prefix::String print(io, undef_ref_str) else el = X[i,j] - show(io, el) + if !show_circular(io, el) + show(io, el) + end end end if last(cr) == last(indc) @@ -488,9 +490,11 @@ function show(io::IO, X::AbstractArray) if !implicit io = IOContext(io, :typeinfo => eltype(X)) end - isempty(X) ? - _show_empty(io, X) : - _show_nonempty(io, X, prefix) + if isempty(X) + return _show_empty(io, X) + end + recur_io = IOContext(io, :SHOWN_SET => X) + _show_nonempty(recur_io, X, prefix) end ### 0-dimensional arrays (#31481) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index ad821855e573a..68390057643f9 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -2310,3 +2310,20 @@ end v2 = view(A, Base.IdentityUnitRange(1:length(A))) @test sum(x for x in v2) == sum(A) end + +@testset "self referential" begin + v = Any[1,2,3] + m = Any[1 2 3] + + v[1] = v + m[1] = m + + @test v == v == v[1] + @test m == m == m[1] + + io = IOBuffer() + show(io, v) + @test String(take!(io)) == "Any[Any[#= circular reference @-1 =#], 2, 3]" + show(io, m) + @test String(take!(io)) == "Any[#= circular reference @-1 =# 2 3]" +end From a857150236d5923ae654f3dcba226889334ba81c Mon Sep 17 00:00:00 2001 From: Andy Dienes Date: Tue, 1 Jul 2025 13:16:54 -0400 Subject: [PATCH 2/3] punt on equality changes --- base/abstractarray.jl | 3 --- test/abstractarray.jl | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index f1668d6f467a1..94bf3170feb38 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -3029,9 +3029,6 @@ Return `true` when `A` is less than `B` in lexicographic order. isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0 function (==)(A::AbstractArray, B::AbstractArray) - if A === B - return true - end if axes(A) != axes(B) return false end diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 68390057643f9..3af8df45de28b 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -2318,8 +2318,9 @@ end v[1] = v m[1] = m - @test v == v == v[1] - @test m == m == m[1] + # TODO: unclear how this (and `hash`) can work without tracking the objectid of each element + @test_broken (v == v == v[1]) + @test_broken (m == m == m[1]) io = IOBuffer() show(io, v) From 7f92f5f34138222b6c4147b0830f37fed434fb19 Mon Sep 17 00:00:00 2001 From: Andy Dienes Date: Tue, 8 Jul 2025 09:21:42 -0400 Subject: [PATCH 3/3] remove test_brokens --- test/abstractarray.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 3af8df45de28b..f4528ad12d4b6 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -2318,10 +2318,6 @@ end v[1] = v m[1] = m - # TODO: unclear how this (and `hash`) can work without tracking the objectid of each element - @test_broken (v == v == v[1]) - @test_broken (m == m == m[1]) - io = IOBuffer() show(io, v) @test String(take!(io)) == "Any[Any[#= circular reference @-1 =#], 2, 3]"