-
-
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
Fix return type in broadcast when there are Type arguments #19421
Conversation
@nanosoldier |
Am I making a mistake below? julia> begin
ftype(f, A) = typeof(f)
ftype(f, A...) = typeof(a -> f(a...))
ftype(T::Type, A) = Type{T}
ftype(T::Type, A...) = Type{T}
ziptype(A) = Tuple{eltype(A)}
ziptype(T::Type) = Tuple{Type{T}}
ziptype(A, B) = Iterators.Zip2{ziptype(A), ziptype(B)}
@inline ziptype(A, B, C, D...) = Iterators.Zip{ziptype(A), ziptype(B, C, D...)}
end
ziptype (generic function with 4 methods)
julia> As = (Int, [1,2,3])
(Int64,[1,2,3])
julia> zt = ziptype(As...)
Base.Iterators.Zip2{Tuple{Type{Int64}},Tuple{Int64}}
julia> ft = ftype(round, As...)
##1#2{Base.#round}
julia> Base._default_eltype(Base.Generator{zt,ft})
Any yet julia> Core.Inference.return_type(round, Tuple{Type{Int},Int})
Int64 (I imagine there is a good reason for the |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels |
@Sacha0 I don't understand all the underlying details in inference all too well, but I'll try to convey what I can grasp from the problems that led to the current mechanism, which has the limitation you noticed.
Maybe there is another approach that could work, but I haven't been able to devise one. The only thing that I have found to work most of the time is the |
That's backwards. It's distinctly not pure, so it must never be called from a function annotated as such. But since the bound on its return value is actually inferrable, it has special handling inside type inference. (I still need to look at this PR to understand if it's correct, but I've been afk for Thanksgiving) |
@vtjnash Thanks for clarifying. That makes more sense. |
Just a question then (to understand the situation better). Under what conditions the bound of |
ftype(T::DataType, A) = Type{T} | ||
ftype(T::DataType, A...) = Type{T} | ||
ftype(T::Type, A) = Type{T} | ||
ftype(T::Type, A...) = Type{T} |
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.
IIUC, the eltype
of the type ziptype
constructs is a tuple, which necessitates ftype(f, A...) = typeof(a -> f(a...))
rather than ftype(f, A...) = f
. Is that correct? If so, why does ftype(T::Type, A...) = Type{T}
suffice rather than something like ftype(T::Type, A...) = typeof(a -> T(a...))
? Thanks!
@vtjnash: |
Absolutely. |
b6e6ad5
to
0f50336
Compare
The use of |
Could we ask |
@inline ziptype(A, B, C, D...) = Iterators.Zip{Tuple{eltype(A)}, ziptype(B, C, D...)} | ||
@pure typestuple(a) = Tuple{eltype(a)} | ||
@pure typestuple(T::Type) = Tuple{Type{T}} | ||
@pure typestuple(a, b...) = Tuple{typestuple(a).types..., typestuple(b...).types...} |
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.
💯
@nanosoldier |
The most recent simplifications look great! Do they make the test result now inferable? Best! |
Yep |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels |
@@ -352,3 +352,6 @@ StrangeType18623(x,y) = (x,y) | |||
# Issue 18622 | |||
@test @inferred muladd.([1.0], [2.0], [3.0])::Vector{Float64} == [5.0] | |||
@test @inferred tuple.(1:3, 4:6, 7:9)::Vector{Tuple{Int,Int,Int}} == [(1,4,7), (2,5,8), (3,6,9)] | |||
|
|||
# 19419 | |||
@test @inferred broadcast(round, Int, [1])::Vector{Int} == [1] |
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.
With broadcast(round, Int, [1])
now inferred, drop the ::Vector{Int}
? Also, shouldn't these combined @test-@inferred
tests be written @test @inferred(broadcast(round, Int, [1])) == [1]
instead? Otherwise the @inferred
checks whether the ==
expression is inferable rather than the LHS? Likewise several of the preceding tests. Best!
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.
These changes look great. Travis, Appveyor, and Nanosoldier approve. Absent objections or requests for time, I plan to merge this following the test touchups. Best!
0f50336
to
02596f9
Compare
(As an aside, though this PR dramatically reduces the amount of red in |
Tests fixed. The AV error was an unrelated server failure. Some of the |
Thanks again @pabloferz! 💯 |
This (probably) caused the following regression: julia> using StaticArrays
julia> s = rand(SVector{3});
julia> Base.Test.@inferred s * 0.0 Ping @andyferris |
Not saying that there is anything wrong with this PR, it could be how |
The problem with I could implement a mixed approach between the one in this PR and the previous mechanism that handles (except for some possible corner cases) both issues. Another option is see if something can be done on the inference end @JeffBezanson? Here is an example of something that used to work with the old approach but currently does not foo(f, A, n) = broadcast(x -> f(x, n), A)
foo(+, [1.0, 2.0, 3.0], 1) # Not inferable but it was before |
Ouch. Just confirmed foo(f, A, n) = broadcast(x -> f(x, n), A)
Base.Test.@inferred foo(+, [1.0, 2.0, 3.0], 1) previously worked (with concrete inferred type), but now fails. Odd though, the |
Checked, both the example above and that from the linked discourse thread fail on master, but both work on the commit prior to the merge commit for this pull request. I must've made a mistake when testing for the related discourse thread? Best! |
If there isn't an easy fix to be had soon, could at least add some test_broken cases that we would ideally like to work, for tracking purposes |
Ref. |
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype, typestuple -> eltypestuple).
…re cases. Re-simplify broadcast's eltype promotion mechanism as in JuliaLang#19421. With benefit of JuliaLang#19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype, typestuple -> eltypestuple).
…re cases. (#19723) Re-simplify broadcast's eltype promotion mechanism as in #19421. With benefit of #19667, this simplified mechanism should handle additional cases (e.g. closures accepting more than two arguments). Also rename the mechanism more precisely (_broadcast_type -> _broadcast_eltype, typestuple -> eltypestuple).
Fixes #19419