Package precompilation error on Julia 1.8

Hi there,

I have an internal company package that is working fine on previous Julia versions, but suddenly throws an error upon precompilation in julia 1.8. See error below. Any help or tips are much appreciated.

It looks like unique is failing, so I removed all explicit usage of unique as a test, but precompilation still fails.

The error is complaining about a missing method of ==. Source code on float.jl line 448 seems to be comparing an Int and a Float. But I can trigger that code just fine on a REPL.

julia> @which Int(1.66679e+09) == 1.66679e+09
==(y::Int64, x::Float64) in Base at float.jl:450

This is the offending precompilation error:

julia> using MyPackage
[ Info: Precompiling MyPackage
fatal: error thrown and no exception handler available.
MethodError(f=Base.:(==), args=(1.66679e+09, 1.66679e+09), world=0x00000000000084b5)
jl_method_error_bare at /cygdrive/c/buildbot/worker/package_win64/build/src\gf.c:1879
jl_method_error at /cygdrive/c/buildbot/worker/package_win64/build/src\gf.c:1897
jl_lookup_generic_ at /cygdrive/c/buildbot/worker/package_win64/build/src\gf.c:2530
ijl_apply_generic at /cygdrive/c/buildbot/worker/package_win64/build/src\gf.c:2545
== at .\float.jl:448
== at .\float.jl:450
isequal at .\operators.jl:146
hash at .\float.jl:518 [inlined]
hash at .\tuple.jl:434 [inlined]
hash at .\tuple.jl:434
hash at .\tuple.jl:434 [inlined]
hash at .\hashing.jl:20 [inlined]
hashindex at .\dict.jl:169 [inlined]
ht_keyindex at .\dict.jl:284
haskey at .\dict.jl:569 [inlined]
in at .\set.jl:66
unknown function (ip: 000000001ee6b3ba)
unique at .\set.jl:140
_unique_dims at .\multidimensional.jl:1653 [inlined]
#unique#563 at .\multidimensional.jl:1651 [inlined]
unique at .\multidimensional.jl:1651
jfptr_unique_34512.clone_1 at C:\Users\matcox\AppData\Local\Programs\Julia-1.8.2\lib\julia\sys.dll (unknown line)
jl_apply at /cygdrive/c/buildbot/worker/package_win64/build/src\julia.h:1839 [inlined]
write_dependency_list at /cygdrive/c/buildbot/worker/package_win64/build/src\dump.c:1388 [inlined]
ijl_save_incremental at /cygdrive/c/buildbot/worker/package_win64/build/src\dump.c:2645
jl_write_compiler_output at /cygdrive/c/buildbot/worker/package_win64/build/src\precompile.c:65
ijl_atexit_hook at /cygdrive/c/buildbot/worker/package_win64/build/src\init.c:207
jl_repl_entrypoint at /cygdrive/c/buildbot/worker/package_win64/build/src\jlapi.c:720
mainCRTStartup at /cygdrive/c/buildbot/worker/package_win64/build/cli\loader_exe.c:59
BaseThreadInitThunk at C:\WINDOWS\System32\KERNEL32.DLL (unknown line)
RtlUserThreadStart at C:\WINDOWS\SYSTEM32\ntdll.dll (unknown line)

My version info:

julia> versioninfo()
Julia Version 1.8.2
Commit 36034abf26 (2022-09-29 15:21 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 8 × Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, skylake)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_PKG_PRECOMPILE_AUTO = 0

I personally have not seen this before and it looks strange. Is the company package huge or is it possible to reduce the code in it until it is something that could be publicly posted?

I’m trying to isolate the problem. A previous version of the package does run on Julia 1.8, so I hope to narrow down the issue with a git diff.

Ok, I found the offending function. It was a horrible coding pattern that slipped through our reviews, I feel ashamed to post it here. Though I wonder why it works on 1.7 but not on 1.8.

function Base.:(==)(s1::Union{Float64, MyType, Nothing}, s2::Union{Float64, MyType, Nothing})
    if typeof(s1) != typeof(s2)
        return false
    end
    if s1 isa Nothing
        return true
    end
    if s1 isa Float64
        return isapprox(s1, s2; atol = 1e-16)
    else
        return s1 == s2
    end
end

This was written by someone trying to compare a parametric union type, for example AnotherType{Union{Float64, MyType, Nothing}}. I now handle the comparison on that level. I really should clean up that code further…

1 Like

Running this code in the REPL (rather than precompile in a package) in 1.8 throws a slightly different error that might hint at a cause. It does not cause this on 1.7

module M
        struct MyType; end
        function Base.:(==)(s1::Union{Float64, MyType, Nothing}, s2::Union{Float64, MyType, Nothing})
         ......
        end
end
│   exception =
│    MethodError: ==(::Float64, ::Float64) is ambiguous. Candidates:
│      ==(x::T, y::T) where T<:Union{Float16, Float32, Float64} in Base at float.jl:410
│      ==(s1::Union{Nothing, Main.M.MyType, Float64}, s2::Union{Nothing, Main.M.MyType, Float64}) in Main.M at REPL[1]:3
│    Possible fix, define
│      ==(::Float64, ::Float64)
│    Stacktrace:
│      [1] ==(x::Float64, y::Int64)
│        @ Base .\float.jl:448
│      [2] edit_insert(s::REPL.LineEdit.PromptState, c::Union{Char, SubString{String}, String})
│        @ REPL.LineEdit C:\Users\avik\.julia\juliaup\julia-1.8.2+0.x64\share\julia\stdlib\v1.8\REPL\src\LineEdit.jl:0
│      [3] edit_insert(s::REPL.LineEdit.MIState, args::Any)
│        @ REPL.LineEdit C:\Users\avik\.julia\juliaup\julia-1.8.2+0.x64\share\julia\stdlib\v1.8\REPL\src\LineEdit.jl:239
│      [4] (::REPL.LineEdit.var"#137#191")(s::REPL.LineEdit.MIState, data::Any, c::Union{Char, SubString{String}, String})

Yeah, that would do it, heh. The reason it “works” on earlier Julia versions is probably that those don’t include use IEEEFloat to clean up floats.jl by Pramodh-G · Pull Request #43433 · JuliaLang/julia · GitHub which causes the new definition here to be ambiguous.