-
-
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 a precision issue in abstract_iteration
#41839
Conversation
Ah, no, this isn't it. We need to compute a new |
19d2f4c
to
228e0fb
Compare
Bump. @Keno, mind taking another look? |
Bump. Any objections against merging this? |
Thanks for solving this. It looks like it is actually a bugfix so we should backport it, but that only the iterate function needs to be moved (the other changes just make it slower / less accurate) |
I don't think this is a bugfix in the sense that inference was unsound before. At least I could not come up with a case, although that may not be too strong an indicator... On the other hand, the fact that you proposed an alternative which did end up being unsound is a strong indicator that this is quite tricky to get right, so I'm not sure backporting is a good idea. |
If you mean that we should not do the removal of |
defd0a7
to
e60bcee
Compare
e60bcee
to
2666188
Compare
Prodding at this, I've found another case where we could consider improving precision: julia> struct NoneOrFailOnSecond{T}
itr::T
end
julia> Base.iterate(itr::NoneOrFailOnSecond) = iterate(itr.itr)
julia> f_splat(x) = (x...,)
f_splat (generic function with 1 method)
julia> f_splat(NoneOrFailOnSecond([]))
()
julia> f_splat(NoneOrFailOnSecond([1]))
ERROR: MethodError: no method matching iterate(::NoneOrFailOnSecond{Vector{Int64}}, ::Int64)
[...]
julia> @code_typed f_splat(NoneOrFailOnSecond([1]))
CodeInfo(
1 ─ %1 = Core._apply_iterate(Base.iterate, Core.tuple, x)::Tuple
└── return %1
) => Tuple (Same for master and this PR in its current form.) Conceivably, this could be inferred as So I'd say leave that as is (for now, at least). Opinions? |
I think we can easily handle that, by choosing not to widen valtype, and avoiding adding Vararg{Bottom} to the array Another case we can improve is to model the implicit typeassert call, by adding a |
valtype = Any | ||
break | ||
end | ||
if nounion.parameters[1] <: valtype && nounion.parameters[2] <: statetype | ||
# reached a fixpoint or iterator failed/gave invalid answer | ||
if typeintersect(stateordonet, Nothing) === Union{} |
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.
if typeintersect(stateordonet, Nothing) === Union{} | |
if !(Nothing <: stateordonet) |
As Nothing
is a leaf type, this should be equal but more efficient?
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.
It should be almost identical (since typeintersect can check that property too), so not worth worrying about the difference too much
if nounion === Union{} | ||
# handle iterator failing or giving an invalid answer below | ||
nounion = Tuple{Union{}, Union{}} | ||
elseif !isa(nounion, DataType) || !(nounion <: Tuple) || isvatuple(nounion) || length(nounion.parameters) != 2 |
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.
elseif !isa(nounion, DataType) || !(nounion <: Tuple) || isvatuple(nounion) || length(nounion.parameters) != 2 | |
elseif !isa(nounion, DataType) |
Should be sufficient with the typeintersect
above, but in corner cases it might give funnily too wide types which then might make these extra checks necessary?
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Fixes #41022.
Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit.
Avoid recomputation of a `widenconst` and initialize `valtype` and `statetype` to `Bottom` before second loop to simplify a `⊑`to a `<:` there.
b200a62
to
8669893
Compare
@vtjnash anything left I should address or good to go? |
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit. Fixes #41022 Co-authored-by: Jameson Nash <vtjnash@gmail.com> (cherry picked from commit 92337b5)
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit. Fixes #41022 Co-authored-by: Jameson Nash <vtjnash@gmail.com> (cherry picked from commit 92337b5)
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit. Fixes #41022 Co-authored-by: Jameson Nash <vtjnash@gmail.com> (cherry picked from commit 92337b5)
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit. Fixes JuliaLang#41022 Co-authored-by: Jameson Nash <vtjnash@gmail.com>
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit. Fixes JuliaLang#41022 Co-authored-by: Jameson Nash <vtjnash@gmail.com>
If the first loop exits in the first iteration, the `statetype` is still `Bottom`. In that case, the new `stateordonet` needs to be determined with the two-arg version of `iterate` again. Explicitly test that inference produces a sound (and reasonably precise) result when splatting an iterator (in this case a long range) that allows constant-propagation up to the `MAX_TUPLE_SPLAT` limit. Fixes #41022 Co-authored-by: Jameson Nash <vtjnash@gmail.com> (cherry picked from commit 92337b5)
The first loop is left before
valtype
andstatetype
are updated from the currentstateordonet
, so the second loop should first process it before obtaining a new one instead of vice versa.Fixes #41022.