diff --git a/Project.toml b/Project.toml index 891d709f..fad5a912 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] diff --git a/src/dict_support.jl b/src/dict_support.jl index 6a95ff1f..3a7def95 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,9 +1,16 @@ # support functions -using InteractiveUtils: methodswith - -function not_iterator_of_pairs(kv) - return any(x->isempty(methodswith(typeof(kv), x, true)), - [iterate]) || - any(x->!isa(x, Union{Tuple,Pair}), kv) +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 + # 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 diff --git a/test/test_priority_queue.jl b/test/test_priority_queue.jl index 35dc8e61..5094f18a 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" begin + 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