-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Julia 1.9: precompile prints fatal error in type inference (type bound)
when mixing pkgimages=yes and pkgimages=no
#48397
Comments
Thanks! I saw this error somewhere else but didn't know how to repro it! |
fatal error in type inference (type bound)
when mixing pkgimages=yes and pkgimages=no
fatal error in type inference (type bound)
when mixing pkgimages=yes and pkgimages=nofatal error in type inference (type bound)
when mixing pkgimages=yes and pkgimages=no
JuliaParallel/MPI.jl#707 (comment) looks to be the same. |
PkgEval is also running into this, e.g., https://s3.amazonaws.com/julialang-reports/nanosoldier/pkgeval/by_date/2023-01/26/LLVM.against.log. I'm not sure how, as we aren't mixing precompilation images as far as I know. We do manually precompile the test environment beforehand, so maybe something goes wrong there: https://github.com/JuliaCI/PkgEval.jl/blob/1c9fa82732f50af4c62aaaf0a555cdbc476851b9/src/evaluate.jl#L381-L415 |
According to PkgEval logs this started somewhere in 4e76346...1c5fa2b Script version of reproducer: using Pkg
julia = Base.julia_cmd().exec[1]
mktempdir() do depot
withenv("JULIA_DEPOT_PATH" => depot) do
run(`$julia --pkgimages=no -e 'using Pkg; Pkg.activate("temp"; shared=true); Pkg.add("HTTP")'`)
run(`$julia --pkgimages=yes -e 'using Pkg; Pkg.activate("temp"; shared=true); Pkg.precompile()'`)
run(`$julia --pkgimages=no -e 'using Pkg; Pkg.activate("temp"; shared=true); Pkg.precompile(); sleep(1)'`)
end
end Using that to bisect:
|
Just to be clear, the issue was "introduced" in JuliaLang/Pkg.jl#3308 but it isn't a bug with that code per say (at least I don't think so), it seems instead that it triggers an error in inference in cases like this. |
Does setting a cache as stale make inference not trust it? Or is it rejected all at once? |
By looking at the IRcode I reconstructed the following MWE: i = 3
wat() = i == 3 ? nothing : "nothing"
@noinline function default()
if i == 1
return true
else
return (Any[], wat())
end
end
function doit(i)
modpath = ""
modkey = Base.PkgId("")
modbuild_id = UInt128(1)
cache = Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}()
get!(cache, (Base.PkgId(""), UInt128(1), "", "")) do
@show modpath modkey modbuild_id
if i == 1
return true
else
return (Any[], wat())
end
end
end
doit(2)
This also fails on 1.9, but not on 1.8, so we could put this on the milestone as a regression if anybody wants. I'm going to reduce & bisect now. |
Reduced MWE: i = wat() = i
cache = Dict{Tuple, Union{Bool, Tuple{Vector, String}}}()
get!(cache, ()) do
if i == 1
true
else
[], wat()
end
end Bisected to #44421 (cc @Keno):
|
#44421 changed the union-splitting to skip generating unnecessary fallback dynamic dispatch call when there is any fully covered call. But it turned out that this is only valid when there is any fully covered call in matches for all signatures that inference split, and it is invalid if there is any union split signature against which any uncovered call is found. Consider the following example: # case 1 # def nosplit(::Any) = [...] nosplit(::Int) = [...] # call nosplit(a::Any) split1: a::Any ┬ nosplit(a::Int) └ nosplit(a::Any) # fully covers split1 # case 2 # def convert(::Type{T}, ::T) = T # call convert(::Type{Union{Bool,Tuple{Int,String}}}, a::Union{Bool,Tuple{Int,Any}}) split1: a::Bool ─ convert(::Type{Bool}, ::Bool) # fully covers split1 split2: a::Tuple{Int,Any} ─ convert(::Type{Tuple{Int,String}}, ::Tuple{Int,String}) # NOT fully covers split2 #44421 allows us to optimize the the first case, but handles the second case wrongly. This commit fixes it up while still optimizing the first case. fix #48397.
#44421 changed the union-splitting to skip generating unnecessary fallback dynamic dispatch call when there is any fully covered call. But it turned out that this is only valid when there is any fully covered call in matches for all signatures that inference split, and it is invalid if there is any union split signature against which any uncovered call is found. Consider the following example: # case 1 # def nosplit(::Any) = [...] nosplit(::Int) = [...] # call nosplit(a::Any) split1: a::Any ┬ nosplit(a::Int) └ nosplit(a::Any) # fully covers split1 # case 2 # def convert(::Type{T}, ::T) = T # call convert(::Type{Union{Bool,Tuple{Int,String}}}, a::Union{Bool,Tuple{Int,Any}}) split1: a::Bool ─ convert(::Type{Bool}, ::Bool) # fully covers split1 split2: a::Tuple{Int,Any} ─ convert(::Type{Tuple{Int,String}}, ::Tuple{Int,String}) # NOT fully covers split2 #44421 allows us to optimize the the first case, but handles the second case wrongly. This commit fixes it up while still optimizing the first case. fix #48397.
#44421 changed the union-splitting to skip generating unnecessary fallback dynamic dispatch call when there is any fully covered call. But it turned out that this is only valid when there is any fully covered call in matches for all signatures that inference split, and it is invalid if there is any union split signature against which any uncovered call is found. Consider the following example: # case 1 # def nosplit(::Any) = [...] nosplit(::Int) = [...] # call nosplit(a::Any) split1: a::Any ┬ nosplit(a::Int) └ nosplit(a::Any) # fully covers split1 # case 2 # def convert(::Type{T}, ::T) = T # call convert(::Type{Union{Bool,Tuple{Int,String}}}, a::Union{Bool,Tuple{Int,Any}}) split1: a::Bool ─ convert(::Type{Bool}, ::Bool) # fully covers split1 split2: a::Tuple{Int,Any} ─ convert(::Type{Tuple{Int,String}}, ::Tuple{Int,String}) # NOT fully covers split2 #44421 allows us to optimize the the first case, but handles the second case wrongly. This commit fixes it up while still optimizing the first case. fix #48397.
#44421 changed the union-splitting to skip generating unnecessary fallback dynamic dispatch call when there is any fully covered call. But it turned out that this is only valid when there is any fully covered call in matches for all signatures that inference split, and it is invalid if there is any union split signature against which any uncovered call is found. Consider the following example: # case 1 # def nosplit(::Any) = [...] nosplit(::Int) = [...] # call nosplit(a::Any) split1: a::Any ┬ nosplit(a::Int) └ nosplit(a::Any) # fully covers split1 # case 2 # def convert(::Type{T}, ::T) = T # call convert(::Type{Union{Bool,Tuple{Int,String}}}, a::Union{Bool,Tuple{Int,Any}}) split1: a::Bool ─ convert(::Type{Bool}, ::Bool) # fully covers split1 split2: a::Tuple{Int,Any} ─ convert(::Type{Tuple{Int,String}}, ::Tuple{Int,String}) # NOT fully covers split2 #44421 allows us to optimize the the first case, but handles the second case wrongly. This commit fixes it up while still optimizing the first case. fix #48397.
FWIW, the fatal error in compiler is fixed, and now it's raised as an error within Pkg.jl: Precompiling environment...
16 dependencies successfully precompiled in 8 seconds
Activating project at `/var/folders/28/jpsyzp6971s99n6bd4_k6fgm0000gn/T/jl_wE65OO/environments/temp`
Precompiling environment...
16 dependencies successfully precompiled in 18 seconds
Activating project at `/var/folders/28/jpsyzp6971s99n6bd4_k6fgm0000gn/T/jl_wE65OO/environments/temp`
┌ Error: Pkg.precompile error
│ exception =
│ MethodError: Cannot `convert` an object of type
│ Tuple{Vector{Any}, Nothing} to an object of type
│ Union{Bool, Tuple{Vector{Any}, String}}
│
│ Closest candidates are:
│ convert(::Type{T}, ::T) where T
│ @ Base Base.jl:64
│
│ Stacktrace:
│ [1] get!(default::Pkg.API.var"#224#225"{UInt128, Base.PkgId, String, String}, h::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, key::Tuple{Base.PkgId, UInt128, String, String})
│ @ Base ./dict.jl:469
│ [2] _is_stale!(stale_cache::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, paths::Vector{String}, sourcepath::String)
│ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1068
│ [3] macro expansion
│ @ [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1388 [inlined]
│ [4] (::Pkg.API.var"#244#274"{Bool, Bool, Pkg.Types.Context, Vector{Task}, Dict{Base.PkgId, String}, Pkg.API.var"#handle_interrupt#266"{Base.Event, ReentrantLock, Base.TTY}, Pkg.API.var"#color_string#264", Base.Event, Base.Event, ReentrantLock, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, String}, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, Bool}, Dict{Base.PkgId, Base.Event}, Dict{Base.PkgId, Bool}, Vector{Pkg.Types.PackageSpec}, Dict{Base.PkgId, String}, Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, Vector{Base.PkgId}, Bool, Base.TTY, Base.Semaphore, String, Vector{String}, Vector{Base.PkgId}, Base.PkgId})()
│ @ Pkg.API ./task.jl:514
└ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1276
┌ Error: Pkg.precompile error
│ exception =
│ MethodError: Cannot `convert` an object of type
│ Tuple{Vector{Any}, Nothing} to an object of type
│ Union{Bool, Tuple{Vector{Any}, String}}
│
│ Closest candidates are:
│ convert(::Type{T}, ::T) where T
│ @ Base Base.jl:64
│
│ Stacktrace:
│ [1] get!(default::Pkg.API.var"#224#225"{UInt128, Base.PkgId, String, String}, h::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, key::Tuple{Base.PkgId, UInt128, String, String})
│ @ Base ./dict.jl:469
│ [2] _is_stale!(stale_cache::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, paths::Vector{String}, sourcepath::String)
│ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1068
│ [3] macro expansion
│ @ [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1388 [inlined]
│ [4] (::Pkg.API.var"#244#274"{Bool, Bool, Pkg.Types.Context, Vector{Task}, Dict{Base.PkgId, String}, Pkg.API.var"#handle_interrupt#266"{Base.Event, ReentrantLock, Base.TTY}, Pkg.API.var"#color_string#264", Base.Event, Base.Event, ReentrantLock, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, String}, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, Bool}, Dict{Base.PkgId, Base.Event}, Dict{Base.PkgId, Bool}, Vector{Pkg.Types.PackageSpec}, Dict{Base.PkgId, String}, Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, Vector{Base.PkgId}, Bool, Base.TTY, Base.Semaphore, String, Vector{String}, Vector{Base.PkgId}, Base.PkgId})()
│ @ Pkg.API ./task.jl:514
└ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1276
┌ Error: Pkg.precompile error
│ exception =
│ MethodError: Cannot `convert` an object of type
│ Tuple{Vector{Any}, Nothing} to an object of type
│ Union{Bool, Tuple{Vector{Any}, String}}
│
│ Closest candidates are:
│ convert(::Type{T}, ::T) where T
│ @ Base Base.jl:64
│
│ Stacktrace:
│ [1] get!(default::Pkg.API.var"#224#225"{UInt128, Base.PkgId, String, String}, h::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, key::Tuple{Base.PkgId, UInt128, String, String})
│ @ Base ./dict.jl:469
│ [2] _is_stale!(stale_cache::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, paths::Vector{String}, sourcepath::String)
│ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1068
│ [3] macro expansion
│ @ [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1388 [inlined]
│ [4] (::Pkg.API.var"#244#274"{Bool, Bool, Pkg.Types.Context, Vector{Task}, Dict{Base.PkgId, String}, Pkg.API.var"#handle_interrupt#266"{Base.Event, ReentrantLock, Base.TTY}, Pkg.API.var"#color_string#264", Base.Event, Base.Event, ReentrantLock, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, String}, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, Bool}, Dict{Base.PkgId, Base.Event}, Dict{Base.PkgId, Bool}, Vector{Pkg.Types.PackageSpec}, Dict{Base.PkgId, String}, Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, Vector{Base.PkgId}, Bool, Base.TTY, Base.Semaphore, String, Vector{String}, Vector{Base.PkgId}, Base.PkgId})()
│ @ Pkg.API ./task.jl:514
└ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1276
┌ Error: Pkg.precompile error
│ exception =
│ MethodError: Cannot `convert` an object of type
│ Tuple{Vector{Any}, Nothing} to an object of type
│ Union{Bool, Tuple{Vector{Any}, String}}
│
│ Closest candidates are:
│ convert(::Type{T}, ::T) where T
│ @ Base Base.jl:64
│
│ Stacktrace:
│ [1] get!(default::Pkg.API.var"#224#225"{UInt128, Base.PkgId, String, String}, h::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, key::Tuple{Base.PkgId, UInt128, String, String})
│ @ Base ./dict.jl:469
│ [2] _is_stale!(stale_cache::Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, paths::Vector{String}, sourcepath::String)
│ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1068
│ [3] macro expansion
│ @ [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1388 [inlined]
│ [4] (::Pkg.API.var"#244#274"{Bool, Bool, Pkg.Types.Context, Vector{Task}, Dict{Base.PkgId, String}, Pkg.API.var"#handle_interrupt#266"{Base.Event, ReentrantLock, Base.TTY}, Pkg.API.var"#color_string#264", Base.Event, Base.Event, ReentrantLock, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, String}, Vector{Base.PkgId}, Vector{Base.PkgId}, Dict{Base.PkgId, Bool}, Dict{Base.PkgId, Base.Event}, Dict{Base.PkgId, Bool}, Vector{Pkg.Types.PackageSpec}, Dict{Base.PkgId, String}, Dict{Tuple{Base.PkgId, UInt128, String, String}, Union{Bool, Tuple{Vector{Any}, String}}}, Vector{Base.PkgId}, Bool, Base.TTY, Base.Semaphore, String, Vector{String}, Vector{Base.PkgId}, Base.PkgId})()
│ @ Pkg.API ./task.jl:514
└ @ Pkg.API [...]/julia/usr/share/julia/stdlib/v1.10/Pkg/src/API.jl:1276
Process(`[...]/julia/usr/bin/julia --pkgimages=no -e 'using Pkg; Pkg.activate("temp"; shared=true); Pkg.precompile(); sleep(1)'`, ProcessExited(0)) |
@KristofferC Should we track the remaining issue here (on the milestone), or on the Pkg.jl repository? |
If you precompile the same package environment twice, once with
julia --pkgimages=yes
, and once withjulia --pkgimages=no
, then callingPkg.precompile()
a third time will print lots of errors:The text was updated successfully, but these errors were encountered: