-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Fix typeassert dropping PartialStruct information #36622
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
Conversation
029bca4 to
4954d05
Compare
martinholters
left a comment
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.
Generally LGTM.
Without knowing that it's defined in the middle of _tfuncs, the name typeassert_instance might be quite misleading, but I don't want to stall this PR in naming bikeshedding.
base/compiler/tfuncs.jl
Outdated
| function typeassert_tfunc(@nospecialize(v), @nospecialize(t)) | ||
| t = instanceof_tfunc(t)[1] | ||
| t === Any && return v | ||
| function typeassert_instance(@nospecialize(v), @nospecialize(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.
I'm not too happy about this name, though I don't really have a better idea. Maybe at least drop a comment that t here is the one meant to be the "instance" (of a Type{...}), not v?
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.
Maybe just make it an inner function inside typeassert_tfunc?
base/compiler/tfuncs.jl
Outdated
| has_free_typevars(t) && return v | ||
| widev = widenconst(v) | ||
| newT = typeintersect(widev, t) | ||
| if newT === widev |
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 newT === widev | |
| if newT == widev |
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.
I know these seem almost the same (since .typ is usually concrete), but the type-system knows that too, and can handle the exceptions better
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.
I figured the case where typeintersect would return something that's == to one of the inputs, but not === to one of the inputs would be pretty rare, and in the case where it doesn't, using === would bypass the useless sometype query that we don't really care about.
base/compiler/tfuncs.jl
Outdated
| newT = typeintersect(widev, t) | ||
| if newT === widev | ||
| return v | ||
| end |
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.
| newT = typeintersect(widev, t) | |
| if newT === widev | |
| return v | |
| end | |
| if widev <: t | |
| return v | |
| elseif typeintersect(widev, t) === Bottom | |
| return Bottom | |
| end |
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.
Calling typeintersect here would force us to call abstract_apply on tuple_tfunc over the result, to recompute widev from newT. That's awkward (sometimes more accurate, sometimes less), so let's avoid that.
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.
I don't understand what you're saying here.
base/compiler/tfuncs.jl
Outdated
| end | ||
| new_fields = Vector{Any}(undef, length(v.fields)) | ||
| for i = 1:length(new_fields) | ||
| new_fields[i] = typeassert_instance(v.fields[i], getfield_tfunc(newT, Const(i))) |
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.
| new_fields[i] = typeassert_instance(v.fields[i], getfield_tfunc(newT, Const(i))) | |
| new_fields[i] = typeassert_instance(v.fields[i], getfield_tfunc(t, Const(i))) |
This would be strictly more precise.
base/compiler/tfuncs.jl
Outdated
| return Bottom | ||
| end | ||
| end | ||
| return PartialStruct(newT, new_fields) |
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.
| return PartialStruct(newT, new_fields) | |
| return tuple_tfunc(new_fields) |
This would be strictly more correct.
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.
t is not necessarily a tuple
base/compiler/tfuncs.jl
Outdated
| function typeassert_tfunc(@nospecialize(v), @nospecialize(t)) | ||
| t = instanceof_tfunc(t)[1] | ||
| t === Any && return v | ||
| typeassert_instance(v, 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.
| typeassert_instance(v, t) | |
| return typeassert_instance(v, t) |
I know a computer doesn't care about the different, but I treat it as a trivial comment for future human readers
4954d05 to
b7aad0e
Compare
There was a complaint on discourse that Generator splats weren't
infering precisely enough [1]. I thought the recent improvement
to abstract iteration precision would have fixed that, but that
turns out not to be the case of a stupid reason. At the moment,
any type assert (even something silly like `x::Any`), will drop
`PartialStruct` information. Now, generators have an
`::Tuple{Any, Any}` typeassert, which prevented the new iteration
logic from working properly. This fixes typasserts, to not drop
this information. The first couple of conditions that just
return the original `PartialStruct` if the typeassert has no
effect are doing most of the work here. As an add-on, I also
threw in the logic to narrow the PartialStruct if the typeassert
actually introduces additional information. It's not a particularly
common code path, but might as well.
[1] https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849
b7aad0e to
4533ea4
Compare
|
@vtjnash points out that currently if the type inside a PartialStruct is not a tuple, it must be concrete, so the fields parts of this didn't apply and just re-doing |
There was a complaint on discourse that Generator splats weren't
infering precisely enough [1]. I thought the recent improvement
to abstract iteration precision would have fixed that, but that
turns out not to be the case of a stupid reason. At the moment,
any type assert (even something silly like `x::Any`), will drop
`PartialStruct` information. Now, generators have an
`::Tuple{Any, Any}` typeassert, which prevented the new iteration
logic from working properly. This fixes typasserts, to not drop
this information. The first couple of conditions that just
return the original `PartialStruct` if the typeassert has no
effect are doing most of the work here. As an add-on, I also
threw in the logic to narrow the PartialStruct if the typeassert
actually introduces additional information. It's not a particularly
common code path, but might as well.
[1] https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849
There was a complaint on discourse that Generator splats weren't
infering precisely enough [1]. I thought the recent improvement
to abstract iteration precision would have fixed that, but that
turns out not to be the case for a stupid reason. At the moment,
any type assert (even something silly like
x::Any), will dropPartialStructinformation. Now, generators have an::Tuple{Any, Any}typeassert, which prevented the new iterationlogic from working properly. This fixes typasserts, to not drop
this information. The first couple of conditions that just
return the original
PartialStructif the typeassert has noeffect are doing most of the work here. As an add-on, I also
threw in the logic to narrow the PartialStruct if the typeassert
actually introduces additional information. It's not a particularly
common code path, but might as well.
[1] https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849