From 81ce73cc7223c892bd28c29340d207f2e0df5e71 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 11:11:41 +0000 Subject: [PATCH 1/8] Apply fix --- base/deepcopy.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index c4f9ae1a6cb10..45ae7701156f9 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -124,7 +124,8 @@ end if haskey(stackdict, x) return stackdict[x]::typeof(x) end - stackdict[x] = $(Expr(:new, :(Array{T, N}), :(deepcopy_internal(x.ref, stackdict)), :(x.size))) + copied = $(Expr(:new, :(Array{T, N}), :(deepcopy_internal(x.ref, stackdict)), :(x.size))) + get!(stackdict, x, copied)::typeof(x) end function deepcopy_internal(x::GenericMemoryRef, stackdict::IdDict) if haskey(stackdict, x) From a0e0385f155ed69bcc88d600f6410a23dc8f40e0 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 11:33:25 +0000 Subject: [PATCH 2/8] Update base/deepcopy.jl --- base/deepcopy.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index 45ae7701156f9..fe185db5d3bfc 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -125,6 +125,7 @@ end return stackdict[x]::typeof(x) end copied = $(Expr(:new, :(Array{T, N}), :(deepcopy_internal(x.ref, stackdict)), :(x.size))) + #we need to check again, in case we just recursed back to x get!(stackdict, x, copied)::typeof(x) end function deepcopy_internal(x::GenericMemoryRef, stackdict::IdDict) From 09c03b93ab5dffcc6a35ff95fdff9f217ec2e889 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 15:32:20 +0000 Subject: [PATCH 3/8] Add regression test --- test/copy.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/copy.jl b/test/copy.jl index 559bf5d3e757a..f05fc2abdf97f 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -253,8 +253,19 @@ end @test copyto!(s, String[]) == [1, 2] # No error end +function make_circular_reference_array_56775() + p = Any[nothing] + p[1] = p + return p +end + @testset "deepcopy_internal arrays" begin @test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros() + + # issue 56775 + p = make_circular_reference_array_56775() + p2 = deepcopy(p) + p2 === p2[1] end @testset "deepcopy_internal inference" begin From 4a5f5e864d9a8b8dd889221d4697864d1cd9ece4 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 15:53:12 +0000 Subject: [PATCH 4/8] Change fix implementation --- base/deepcopy.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index fe185db5d3bfc..111a9b448647a 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -124,9 +124,10 @@ end if haskey(stackdict, x) return stackdict[x]::typeof(x) end - copied = $(Expr(:new, :(Array{T, N}), :(deepcopy_internal(x.ref, stackdict)), :(x.size))) - #we need to check again, in case we just recursed back to x - get!(stackdict, x, copied)::typeof(x) + y = stackdict[x] = Array{T, N}(undef, ntuple(Returns(0), Val{N}())) + setfield!(y, :ref, deepcopy_internal(x.ref, stackdict)) + setfield!(y, :size, x.size) + y end function deepcopy_internal(x::GenericMemoryRef, stackdict::IdDict) if haskey(stackdict, x) From b1dcf08502199366f2d379a834457cebd80110f2 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 15:53:38 +0000 Subject: [PATCH 5/8] Make check into actual test --- test/copy.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/copy.jl b/test/copy.jl index f05fc2abdf97f..0bba1acbcf4e4 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -265,7 +265,7 @@ end # issue 56775 p = make_circular_reference_array_56775() p2 = deepcopy(p) - p2 === p2[1] + @test p2 === p2[1] end @testset "deepcopy_internal inference" begin From 47e13d1af3e129d90cd3b5f6363d95068360a705 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 19:14:40 +0000 Subject: [PATCH 6/8] Remove eval --- base/deepcopy.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index 111a9b448647a..f60ce2043dd5a 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -120,7 +120,7 @@ function _deepcopy_memory_t(@nospecialize(x::Memory), T, stackdict::IdDict) end return dest end -@eval function deepcopy_internal(x::Array{T, N}, stackdict::IdDict) where {T, N} +function deepcopy_internal(x::Array{T, N}, stackdict::IdDict) where {T, N} if haskey(stackdict, x) return stackdict[x]::typeof(x) end From 016b28258ca80b741d841df7dd5ec4e24a859f68 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Wed, 8 Jan 2025 22:09:18 +0000 Subject: [PATCH 7/8] Update test/copy.jl Co-authored-by: Lilith Orion Hafner --- test/copy.jl | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/copy.jl b/test/copy.jl index 0bba1acbcf4e4..da744e456a490 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -253,19 +253,16 @@ end @test copyto!(s, String[]) == [1, 2] # No error end -function make_circular_reference_array_56775() +@testset "circular reference arrays" begin + # issue 56775 p = Any[nothing] p[1] = p - return p + p2 = deepcopy(p) + @test p2 === p2[1] end @testset "deepcopy_internal arrays" begin @test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros() - - # issue 56775 - p = make_circular_reference_array_56775() - p2 = deepcopy(p) - @test p2 === p2[1] end @testset "deepcopy_internal inference" begin From ec653c7129b1376ba1b0198da642936ef53cd932 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Thu, 9 Jan 2025 09:21:29 +0000 Subject: [PATCH 8/8] Update test/copy.jl Co-authored-by: Neven Sajko <4944410+nsajko@users.noreply.github.com> --- test/copy.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/copy.jl b/test/copy.jl index da744e456a490..f5cc57c86feaa 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -259,6 +259,7 @@ end p[1] = p p2 = deepcopy(p) @test p2 === p2[1] + @test p2 !== p end @testset "deepcopy_internal arrays" begin