From 7582ea22216933bd6021b9c9703a7014cbbf2051 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 17:08:42 -0400 Subject: [PATCH 1/9] do not use InteractiveUtils Jeff and Oscar agree this should be equivalent (and precompilable!) --- src/dict_support.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/dict_support.jl b/src/dict_support.jl index 6a95ff1fd..9ea9c8346 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,9 +1,6 @@ # support functions -using InteractiveUtils: methodswith - -function not_iterator_of_pairs(kv) - return any(x->isempty(methodswith(typeof(kv), x, true)), - [iterate]) || +function not_iterator_of_pairs(kv::T) where T + return Base.hasmethod(Base.iterate, Tuple{T}) && any(x->!isa(x, Union{Tuple,Pair}), kv) end From 60feec6d5f3ddeb5198bcc005e66c9420ec69573 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 17:13:54 -0400 Subject: [PATCH 2/9] Update src/dict_support.jl --- src/dict_support.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dict_support.jl b/src/dict_support.jl index 9ea9c8346..83104cb0f 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,6 +1,6 @@ # support functions function not_iterator_of_pairs(kv::T) where T - return Base.hasmethod(Base.iterate, Tuple{T}) && + return Base.isiterable(kv) && any(x->!isa(x, Union{Tuple,Pair}), kv) end From 6625cdf3dc72ffe2058be3c23061f444a056406c Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 17:17:50 -0400 Subject: [PATCH 3/9] Update Project.toml --- Project.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Project.toml b/Project.toml index 891d709f7..fad5a912a 100644 --- a/Project.toml +++ b/Project.toml @@ -3,7 +3,6 @@ uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" version = "0.19.0-DEV" [deps] -InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" [compat] From dd506395af641ddd02ad3c07fea5c6bb6ab31417 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 21:37:18 -0400 Subject: [PATCH 4/9] Update src/dict_support.jl --- src/dict_support.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dict_support.jl b/src/dict_support.jl index 83104cb0f..c67ae8e29 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,6 +1,6 @@ # support functions function not_iterator_of_pairs(kv::T) where T - return Base.isiterable(kv) && + return Base.isiterable(T) && any(x->!isa(x, Union{Tuple,Pair}), kv) end From 06aea47d465fbb3a96444b6de658b54bb78c757c Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 21:38:38 -0400 Subject: [PATCH 5/9] Update src/dict_support.jl --- src/dict_support.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dict_support.jl b/src/dict_support.jl index c67ae8e29..1ea45553e 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,6 +1,6 @@ # support functions function not_iterator_of_pairs(kv::T) where T - return Base.isiterable(T) && + return !(Base.isiterable(T)) || # if the object is not iterable, return true, else check the eltype of the iteration any(x->!isa(x, Union{Tuple,Pair}), kv) end From f1db618f30d88ef9459516845e603db47ba6e917 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 21:42:48 -0400 Subject: [PATCH 6/9] Simpler logic and fast path for known concrete-ish eltypes --- src/dict_support.jl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/dict_support.jl b/src/dict_support.jl index 1ea45553e..d9654fbcd 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,6 +1,16 @@ # support functions function not_iterator_of_pairs(kv::T) where T - return !(Base.isiterable(T)) || # if the object is not iterable, return true, else check the eltype of the iteration - any(x->!isa(x, Union{Tuple,Pair}), kv) + # if the object is not iterable, return true, else check the eltype of the iteration + Base.isiterable(T) && return true + # else, check if we can check `eltype`: + if Base.IteratorEltype(kv) isa Base.HasEltype + typ = eltype(kv) + if !(typ == Any) + return !(typ <: Union{<: Tuple, <: Pair}) + end + end + # we can't check eltype, or eltype is not useful, + # so brute force it. + return any(x->!isa(x, Union{Tuple,Pair}), kv) end From 96ce804b6ab20a18e572621f5090743614556de1 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Wed, 30 Apr 2025 21:58:18 -0400 Subject: [PATCH 7/9] add tests for full coverage --- test/test_priority_queue.jl | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/test_priority_queue.jl b/test/test_priority_queue.jl index 35dc8e611..8861290e1 100644 --- a/test/test_priority_queue.jl +++ b/test/test_priority_queue.jl @@ -105,6 +105,40 @@ import Base.Order.Reverse @test_throws ArgumentError PriorityQueue(Reverse, Reverse) end + @testset "Strange eltype situations" begin + @testset "Eltype unknown" begin + struct EltypeUnknownIterator{T} + x::T + end + Base.IteratorEltype(::EltypeUnknownIterator) = Base.EltypeUnknown() + Base.iterate(i::EltypeUnknownIterator) = Base.iterate(i.x) + Base.iterate(i::EltypeUnknownIterator, state) = Base.iterate(i.x, state) + Base.IteratorSize(i::EltypeUnknownIterator) = Base.IteratorSize(i.x) + Base.length(i::EltypeUnknownIterator) = Base.length(i.x) + Base.size(i::EltypeUnknownIterator) = Base.size(i.x) + + @test_nowarn PriorityQueue(Dict(zip(1:5, 2:6))) + @test_nowarn PriorityQueue(EltypeUnknownIterator(Dict(zip(1:5, 2:6)))) + @test_throws ArgumentError PriorityQueue(EltypeUnknownIterator(['a'])) + end + + @testset "Eltype any" + struct EltypeAnyIterator{T} + x::T + end + Base.IteratorEltype(::EltypeAnyIterator) = Base.HasEltype() + Base.eltype(::EltypeAnyIterator) = Any + Base.iterate(i::EltypeAnyIterator) = Base.iterate(i.x) + Base.iterate(i::EltypeAnyIterator, state) = Base.iterate(i.x, state) + Base.IteratorSize(i::EltypeAnyIterator) = Base.IteratorSize(i.x) + Base.length(i::EltypeAnyIterator) = Base.length(i.x) + Base.size(i::EltypeAnyIterator) = Base.size(i.x) + + @test_nowarn PriorityQueue(EltypeAnyIterator(Dict(zip(1:5, 2:6)))) + @test_throws ArgumentError PriorityQueue(EltypeAnyIterator(['a'])) + end + end + end @testset "PriorityQueueMethods" begin From 1be4fefbed5e82bfd3997a07f85b8e7cfa5554d2 Mon Sep 17 00:00:00 2001 From: Frames White Date: Thu, 1 May 2025 11:56:57 +0800 Subject: [PATCH 8/9] add missing begin --- test/test_priority_queue.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_priority_queue.jl b/test/test_priority_queue.jl index 8861290e1..5094f18a3 100644 --- a/test/test_priority_queue.jl +++ b/test/test_priority_queue.jl @@ -122,7 +122,7 @@ import Base.Order.Reverse @test_throws ArgumentError PriorityQueue(EltypeUnknownIterator(['a'])) end - @testset "Eltype any" + @testset "Eltype any" begin struct EltypeAnyIterator{T} x::T end From 81eef601503a5a0a59535c2e3b890ac12bea25b3 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Thu, 1 May 2025 07:06:20 -0400 Subject: [PATCH 9/9] Update src/dict_support.jl --- src/dict_support.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dict_support.jl b/src/dict_support.jl index d9654fbcd..3a7def955 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -2,7 +2,7 @@ function not_iterator_of_pairs(kv::T) where T # if the object is not iterable, return true, else check the eltype of the iteration - Base.isiterable(T) && return true + Base.isiterable(T) || return true # else, check if we can check `eltype`: if Base.IteratorEltype(kv) isa Base.HasEltype typ = eltype(kv)