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
RFC: allow Tuple{Union{}}, returning Union{} #53452
base: master
Are you sure you want to change the base?
Conversation
I'd argue that this a bugfix and have marked it for backport to the active release branches accordingly. |
My main question is: is this enough of a bug fix? It doesn't completely fix all of the regressed use-cases identified in #52385. At a minimum, I think we also need to have Then the fixes required for StructArrays are two ambiguous methods: staticschema(::Type{Union{}}) = Union{}
strip_params(::Type{Union{}}) = identity And the fixes required for TypedTables tests is just an ambiguity/unbound typevar around printing: columnnames(::AbstractArray{Union{}}) = ()
columnnames(::Table{<:Any,<:Any,<:NamedTuple{names}}) where {names} = names |
Those seem like unambiguously bugfixes regardless of what we do with Tuple{Union{}}? |
How are these "unambiguously bugfixes" if these methods could not even be triggered before this change in Julia? (that's for StructArrays, not too familiar with TypedTables) |
Whoops, Oscar and I thought no changes would be necessary in inference with this change, but I found a counter-example today demonstrating that apply_type_tfunc would not be sound after this change: julia> const VT = Val{Tuple{T}} where T; code_typed((Type,)) do T; VT{T}; end
1-element Vector{Any}:
CodeInfo(
@ REPL[1]:1 within `#3`
1 ─ %1 = Core.apply_type(Main.VT, T)::Type{Val{Tuple{T}}} where T
└── return %1
) => Type{Val{Tuple{T}}} where T
julia> Val{Union{}} isa Type{Val{Tuple{T}}} where T
false |
The list of fixes from @mbauman above are equivalent to fixing the output of the ambiguity test checker. I suppose calling them a bugfix is a bit strong though, since it is not actually a bug to have ambiguities, even though their presence causes this test to fail.
I believe many packages use |
@test_throws ErrorException("Tuple field type cannot be Union{}") Tuple{Int, Vararg{Union{},1}} | ||
@test_throws ErrorException("Tuple field type cannot be Union{}") Tuple{Vararg{Union{},1}} | ||
@test Tuple{Int, Vararg{Union{},1}} === Union{} | ||
@test Tuple{Vararg{Union{},1}} === Union{} | ||
@test Tuple{} <: Tuple{Vararg{Union{},N}} where N | ||
@test !(Tuple{} >: Tuple{Vararg{Union{},N}} where N) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@testset "#52385" begin | |
eagerzip() = error() | |
function eagerzip(args::AbstractArray...) | |
allequal(axes.(args)) || throw(DimensionMismatch()) | |
Base.require_one_based_indexing(args...) | |
res = similar(first(args), Tuple{eltype.(args)...}) | |
for i in eachindex(args...) | |
res[i] = getindex.(args, i) | |
end | |
res | |
end | |
@test isempty(eagerzip(Int[], [])) | |
@test eltype(eagerzip(Int[], [])) === Tuple{Int64, Any} | |
@test isempty(eagerzip(Union{}[], [])) | |
@test eltype(eagerzip(Union{}[], [])) === Union{} | |
end |
Seems worthwhile to grab @LilithHafner's test case from #52385 (comment)
How so? There is an issue on Aqua-detected ambiguities in StructArrays, and I don't see any overlap with @mbauman's methods: JuliaArrays/StructArrays.jl#293.
Sure, it's better if there are no ambiguities in methods at all. But achieving this in practice is both nontrivial, and not even clearly useful. For example, take StructArrays and the aforementioned issue on ambiguities. Those ambiguities don't even seem realizable in practice, and potential new methods added to resolve them would be dead weight (or even unreachable and untestable). This appears to be a very common position among devs: there are many issues with the same title by the same author over Julia packages, and almost all of them remain open. Even worse, these ambiguity detectors don't catch some real problems. See JuliaArrays/StructArrays.jl#279 with a short example exhibiting the ambiguity. This issue is clearly relevant, and remains open just because it's not clear how to best resolve it. This is somewhat off-topic wrt this issue, but yet, ambiguities are also a pain point (related to multiple dispatch) – but that's for real ambiguities that can actually be realized. Relationship with "detected" ones is unclear imo. |
This is quite tangential now, but there is actually a performance benefit now to solving those, even though they may seem completely pointless, their presence documents to the compiler that they are pointless, which allows it to skip a lot of work when inferring or loading the package. The added method does need to a slightly peculiar exact form though, with a Secondly, the default ambiguity checker is quite conservative, even though that means it may miss many relevant cases. You can make it less conservative by passing |
Backported PRs: - [x] #39071 <!-- Add a lazy `logrange` function and `LogRange` type --> - [x] #51802 <!-- Allow AnnotatedStrings in log messages --> - [x] #53369 <!-- Orthogonalize re-indexing for FastSubArrays --> - [x] #48050 <!-- improve `--heap-size-hint` arg handling --> - [x] #53482 <!-- add IR encoding for EnterNode --> - [x] #53499 <!-- Avoid compiler warning about redefining jl_globalref_t --> - [x] #53507 <!-- update staled `Core.Compiler.Effects` documentation --> - [x] #53408 <!-- task splitting: change additive accumulation to multiplicative --> - [x] #53523 <!-- add back an alias for `check_top_bit` --> - [x] #53377 <!-- add _readdirx for returning more object info gathered during dir scan --> - [x] #53525 <!-- fix InteractiveUtils call in Base.runtests on failure --> - [x] #53540 <!-- use more efficient `_readdirx` for tab completion --> - [x] #53545 <!-- use `_readdirx` for `walkdir` --> - [x] #53551 <!-- revert "Add @create_log_macro for making custom styled logging macros (#52196)" --> - [x] #53554 <!-- Always return a value in 1-d circshift! of abstractarray.jl --> - [x] #53424 <!-- yet more atomics & cache-line fixes on work-stealing queue --> - [x] #53571 <!-- Update Documenter to v1.3 for inventory writing --> - [x] #53403 <!-- Move parallel precompilation to Base --> - [x] #53589 <!-- add back `unsafe_convert` to pointer for arrays --> - [x] #53596 <!-- build: remove extra .a file --> - [x] #53606 <!-- fix error path in `precompilepkgs` --> - [x] #53004 <!-- Unexport with, at_with, and ScopedValue from Base --> - [x] #53629 <!-- typo fix in scoped values docs --> - [x] #53630 <!-- sroa: Fix incorrect scope counting --> - [x] #53598 <!-- Use Base parallel precompilation to build stdlibs --> - [x] #53649 <!-- precompilepkgs: package in boths deps and weakdeps are in fact only weak --> - [x] #53671 <!-- Fix bootstrap Base precompile in cross compile configuration --> - [x] #52125 <!-- Load Pkg if not already to reinstate missing package add prompt --> - [x] #53602 <!-- Handle zero on arrays of unions of number types and missings --> - [x] #53516 <!-- permit NamedTuple{<:Any, Union{}} to be created --> - [x] #53643 <!-- Bump CSL to 1.1.1 to fix libgomp bug --> - [x] #53679 <!-- move precompile workload back from Base --> - [x] #53663 <!-- add isassigned methods for reinterpretarray --> - [x] #53662 <!-- [REPL] fix incorrectly cleared line after completions accepted --> - [x] #53611 <!-- Linalg: matprod_dest for Diagonal and adjvec --> - [x] #53659 <!-- fix #52025, re-allow all implicit pointer casts in cconvert for Array --> - [x] #53631 <!-- LAPACK: validate input parameters to throw informative errors --> - [x] #53628 <!-- Make some improvements to the Scoped Values documentation. --> - [x] #53655 <!-- Change tbaa of ptr_phi to tbaa_value --> - [x] #53391 <!-- Default to the medium code model in x86 linux --> - [x] #53699 <!-- Move `isexecutable, isreadable, iswritable` to `filesystem.jl` --> - [x] #41232 <!-- Fix linear indexing for ReshapedArray if the parent has offset axes --> - [x] #53527 <!-- Enable analyzegc checks for try catch and fix found issues --> - [x] #52092 - [x] #53682 <!-- Increase build precompilation --> - [x] #53720 - [x] #53553 <!-- typeintersect: fix `UnionAll` unaliasing bug caused by innervars. --> Contains multiple commits, manual intervention needed: - [ ] #53305 <!-- Propagate inbounds in isassigned with CartesianIndex indices --> Non-merged PRs with backport label: - [ ] #53736 <!-- fix literal-pow to return the right type when the base is -1 --> - [ ] #53707 <!-- Make ScopedValue public --> - [ ] #53696 <!-- add invokelatest to on_done callback in bracketed paste --> - [ ] #53660 <!-- put Logging back in default sysimage --> - [ ] #53509 <!-- revert moving "creating packages" from Pkg.jl --> - [ ] #53452 <!-- RFC: allow Tuple{Union{}}, returning Union{} --> - [ ] #53402 <!-- Add `jl_getaffinity` and `jl_setaffinity` --> - [ ] #52694 <!-- Reinstate similar for AbstractQ for backward compatibility --> - [ ] #51928 <!-- Styled markdown, with a few tweaks --> - [ ] #51816 <!-- User-themable stacktraces --> - [ ] #51811 <!-- Make banner size depend on terminal size --> - [ ] #51479 <!-- prevent code loading from lookin in the versioned environment when building Julia -->
@oscardssmith requested that I put this up as a PR, where instead of throwing an exception, the call instead returns
Union{}
. It appears this is actually already consistent with the way we had been choosing to represent this particular operation in inference (specific to Tuple, since other types do not use exactly the same code path there), so no changes appear to be necessary there.Fixes #52385