-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
using JET
x = [(1,), ()] # 2-element Vector{Tuple{Vararg{Int64}}}
@report_call any(k -> k == (), x)yields:
═════ 1 possible error found ═════
┌ any(f::var"#19#20", a::Vector{Tuple{Vararg{Int64}}}) @ Base ./reducedim.jl:992
│┌ any(f::var"#19#20", a::Vector{Tuple{Vararg{Int64}}}; dims::Colon) @ Base ./reducedim.jl:992
││┌ _any(f::var"#19#20", itr::Vector{Tuple{Vararg{Int64}}}, ::Colon) @ Base ./reduce.jl:1237
│││┌ (::var"#19#20")(k::Tuple{Vararg{Int64}}) @ Main ./REPL[17]:1
││││┌ ==(t1::Tuple{Vararg{Int64}}, t2::Tuple{}) @ Base ./tuple.jl:547
│││││┌ _eq(t1::Tuple{Vararg{Int64}}, t2::Tuple{}) @ Base ./tuple.jl:551
││││││┌ getindex(t::Tuple{}, i::Int64) @ Base ./tuple.jl:31
│││││││ invalid builtin function call: Base.getfield(t::Tuple{}, i::Int64, $(Expr(:boundscheck)))
││││││└────────────────────The relevant code is here (line numbers are a bit different because I used 1.11, but the code hasn't changed since):
Lines 544 to 556 in 966d0af
| ==(t1::Tuple, t2::Tuple) = (length(t1) == length(t2)) && _eq(t1, t2) | |
| _eq(t1::Tuple{}, t2::Tuple{}) = true | |
| _eq_missing(t1::Tuple{}, t2::Tuple{}) = missing | |
| function _eq(t1::Tuple, t2::Tuple) | |
| eq = t1[1] == t2[1] | |
| if eq === false | |
| return false | |
| elseif ismissing(eq) | |
| return _eq_missing(tail(t1), tail(t2)) | |
| else | |
| return _eq(tail(t1), tail(t2)) | |
| end | |
| end |
One could argue that this is dynamic dispatch (and indeed JET.@report_opt already warns us about this); but this issue seems to be specific to tuple comparison, there aren't any errors if you do any(k -> k == 1.0, x). Of course the arguments to _eq can't be nonempty (if they're both empty the method on L545 would catch it, and if only one is empty the length check in == would catch it); but I suppose because the compiler can't figure that out?
This looks very similar to #58214 #58220 but just for the tuple case.
Because NamedTuple equality defers to Tuple equality, the same problem occurs with NamedTuples:
Line 241 in 966d0af
| ==(a::NamedTuple{n}, b::NamedTuple{n}) where {n} = Tuple(a) == Tuple(b) |
x = [(a = 1,), (b = 2, c = 3)] # 2-element Vector{NamedTuple}
@report_call any(k -> k == (a = 1,), x)
#=
┌ any(f::var"#13#14", a::Vector{NamedTuple}) @ Base ./reducedim.jl:992
│┌ any(f::var"#13#14", a::Vector{NamedTuple}; dims::Colon) @ Base ./reducedim.jl:992
││┌ _any(f::var"#13#14", itr::Vector{NamedTuple}, ::Colon) @ Base ./reduce.jl:1237
│││┌ (::var"#13#14")(k::NamedTuple) @ Main ./REPL[14]:1
││││┌ ==(a::NamedTuple{(:a,)}, b::@NamedTuple{a::Int64}) @ Base ./namedtuple.jl:244
│││││┌ ==(t1::Tuple, t2::Tuple{Int64}) @ Base ./tuple.jl:547
││││││┌ _eq(t1::Tuple, t2::Tuple{Int64}) @ Base ./tuple.jl:555
│││││││┌ _eq_missing(t1::Tuple, t2::Tuple{}) @ Base ./tuple.jl:561
││││││││┌ getindex(t::Tuple{}, i::Int64) @ Base ./tuple.jl:31
│││││││││ invalid builtin function call: Base.getfield(t::Tuple{}, i::Int64, $(Expr(:boundscheck)))
││││││││└────────────────────
=#