Skip to content

Conversation

@Keno
Copy link
Member

@Keno Keno commented Jul 11, 2020

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 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

@Keno Keno added compiler:inference Type inference iteration Involves iteration or the iteration protocol labels Jul 11, 2020
@Keno Keno force-pushed the kf/partialstructtypeassert branch from 029bca4 to 4954d05 Compare July 12, 2020 00:45
Copy link
Member

@martinholters martinholters left a 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.

function typeassert_tfunc(@nospecialize(v), @nospecialize(t))
t = instanceof_tfunc(t)[1]
t === Any && return v
function typeassert_instance(@nospecialize(v), @nospecialize(t))
Copy link
Member

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?

Copy link
Member Author

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?

has_free_typevars(t) && return v
widev = widenconst(v)
newT = typeintersect(widev, t)
if newT === widev
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if newT === widev
if newT == widev

Copy link
Member

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

Copy link
Member Author

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.

Comment on lines 496 to 499
newT = typeintersect(widev, t)
if newT === widev
return v
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
newT = typeintersect(widev, t)
if newT === widev
return v
end
if widev <: t
return v
elseif typeintersect(widev, t) === Bottom
return Bottom
end

Copy link
Member

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.

Copy link
Member Author

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.

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)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

return Bottom
end
end
return PartialStruct(newT, new_fields)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return PartialStruct(newT, new_fields)
return tuple_tfunc(new_fields)

This would be strictly more correct.

Copy link
Member Author

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

function typeassert_tfunc(@nospecialize(v), @nospecialize(t))
t = instanceof_tfunc(t)[1]
t === Any && return v
typeassert_instance(v, t)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

@Keno Keno force-pushed the kf/partialstructtypeassert branch from 4954d05 to b7aad0e Compare July 13, 2020 19:09
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
@Keno Keno force-pushed the kf/partialstructtypeassert branch from b7aad0e to 4533ea4 Compare July 15, 2020 23:14
@Keno
Copy link
Member Author

Keno commented Jul 15, 2020

@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 tuple_tfunc would be strictly more precise. Updated to do that.

@Keno Keno merged commit 8a0e0c8 into master Jul 16, 2020
@Keno Keno deleted the kf/partialstructtypeassert branch July 16, 2020 20:25
simeonschaub pushed a commit to simeonschaub/julia that referenced this pull request Aug 11, 2020
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler:inference Type inference iteration Involves iteration or the iteration protocol

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants