Add promote_typejoin() and use it instead of typejoin() to preserve Union{T, Nothing/Missing}#25553
Add promote_typejoin() and use it instead of typejoin() to preserve Union{T, Nothing/Missing}#25553JeffBezanson merged 7 commits intomasterfrom
Conversation
6d9edf6 to
bfcd16d
Compare
test/tuple.jl
Outdated
| @test x isa Vector{Tuple{Int,Union{Int,T}}} | ||
|
|
||
| y = map(v -> (v[1], v[2]), [(1, T()), (1, 2)]) | ||
| @test y isa Vector{Tuple{Int64,Union{T,Int64}}} |
There was a problem hiding this comment.
These Int64 explain the 32-bit CI failures. Will fix in the next push.
bfcd16d to
8d90c23
Compare
|
Very nearly a CI straight flush. Win32 failure was a timeout. |
|
😎 |
base/inference.jl
Outdated
| n = length(p) | ||
| if n > lim | ||
| tail = reduce(typejoin, Bottom, Any[p[lim:(n-1)]..., unwrapva(p[n])]) | ||
| tail = reduce(promote_join, Bottom, Any[p[lim:(n-1)]..., unwrapva(p[n])]) |
There was a problem hiding this comment.
This should not be changed in inference.
There was a problem hiding this comment.
Right. I thought this was needed to change the promotion of tuples, but clearly I've been overzealous. I've reverted it.
|
Seems basically right. |
…, Void/Missing} This allows for a more efficient code and array layout than using Any.
…priate typejoin() is now used only for inference, and promote_join() everywhere else to choose the appropriate element type for a collection.
…or Nothing Reuse the typejoin() logic.
8d90c23 to
39ceccb
Compare
base/tuple.jl
Outdated
|
|
||
| # promotion | ||
|
|
||
| promote_rule(::Type{S}, ::Type{T}) where {S<:Tuple, T<:Tuple} = |
There was a problem hiding this comment.
I think this should be removed. Changing the type of [(1,), (1.0,)] seems to be outside of the goal here.
There was a problem hiding this comment.
The goal is to have [(1,), (missing,)] isa Vector{Tuple{Union{Int,Missing}} rather than Tuple{Any}. I agree that's not totally required in this PR, but it makes a lot of sense to avoid an inconsistency with map(identity, [(1,), (missing,)]). That's also consistent with [[1], [missing]]. In general I don't see why tuples shoudn't implement promotion, like other containers.
Another solution is to use promote_join rather than promote_type. This could be done either here (i.e. special-case tuples promotion to just use promote_join), or more generally when concatenating arrays. I would prefer a solution which applies consistently to all types.
Anyway I've added a commit to revert this for now, so that we can address these issues separately.
base/namedtuple.jl
Outdated
| isempty(::NamedTuple{()}) = true | ||
| isempty(::NamedTuple) = false | ||
|
|
||
| promote_rule(::Type{NamedTuple{n, S}}, ::Type{NamedTuple{n, T}}) where {n, S, T} = |
There was a problem hiding this comment.
I would also remove this for now. Can be raised as a separate issue if necessary.
Remove promotion tests, revert unneeded Any[ specifications.
Also add @_pure_meta to two methods to preserve current behavior
(without it, vcat((1,), (1.0,)) is not inferred as Vector{Tuple{Real}},
which is caught by a test which previously would not detect this problem).
|
Thanks for the review. I must say I'm not very happy with the name |
|
promote_jointype? |
base/promotion.jl
Outdated
| typejoin(@nospecialize(a), @nospecialize(b)) = (@_pure_meta; join_types(a, b, typejoin)) | ||
|
|
||
| function join_types(@nospecialize(a), @nospecialize(b), f::Function) | ||
| @_pure_meta |
There was a problem hiding this comment.
not pure anymore (due to the abstractly typed f::Function parameter)
There was a problem hiding this comment.
Ah, I always get this wrong... Fixed.
There was a problem hiding this comment.
Don't we need this function to be pure though?
There was a problem hiding this comment.
I have no idea. We could use a loop inside @eval to define two separate functions which would be pure, without duplicating the code.
|
I've renamed |
|
🆗 |
| promote_rule(::Type{TwicePrecision{R}}, ::Type{TwicePrecision{S}}) where {R,S} = | ||
| TwicePrecision{promote_type(R,S)} | ||
| promote_rule(::Type{TwicePrecision{R}}, ::Type{S}) where {R,S} = | ||
| promote_rule(::Type{TwicePrecision{R}}, ::Type{S}) where {R,S<:Number} = |
There was a problem hiding this comment.
I'm not sure this is right. For some reason TwicePrecision{T}'s parameter does not need to be a Number. @timholy Why is that?
|
|
||
| Compute a type that contains both `T` and `S`. | ||
|
|
||
| Return the closest common ancestor of `T` and `S`, i.e. the narrowest type from which |
There was a problem hiding this comment.
I think this docstring could be made clearer. I'm trying to figure out exactly what typejoin and promote_typejoin are doing and I don't think the current descriptions are complete. The current docstring for typejoin states that it returns
the narrowest type from which they both [T and S] inherit
but that must always be Union{T,S}. However, my understanding is that typejoin doesn't return unions and that promote_typejoin was introduced exactly because of that. So what is this function returning? My guess would be something like
TifS<:T
SifT<:S
elsemin(TS)for whichT<:TSandS<:TSandisabstract(TS)
There was a problem hiding this comment.
I think I just copied "closest common ancestor" from a comment and tried to make it a little more explicit. You're right that typejoin returns an abstract supertype and never a Union AFAIK.
There was a problem hiding this comment.
If the definition I stated above is correct then it might be fine to just define ancestor to cover only declared abstract types (and concrete types), i.e. exclude unions. It probably makes sense the declared subset of the type lattice is a tree so ancestor feels natural.
The name of the function would be slightly a misnomer as the lattice join is the least upper bound, but I guess some upper bound is fine for our use.
Examples would then also be helpful in the docstring. I wouldn't mind preparing the PR but I would need a confirmation that my understanding of the function is correct.
This is a continuation of #24332, which cannot be reopened. It's an alternative to adding a more general strict/exact promotion mechanism (#25423). It achieves the same goal, i.e. it ensures that we use
Union{T, Nothing/Missing}instead ofAnywithcollect,map,broadcastand withTupleandNamedTuplepromotion.