-
-
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 #32699, more accurate apply_type_tfunc for NamedTuple #36366
Conversation
The inference looks great! In #36322 I failed to record which package's invalidations I was looking at. I think it was FilePathsBase, and I haven't seen |
Yep, the inference is looking super spiffy, though it seems the last part of my work-flow is failing to inline ( │ %33 = Core.tuple(%20, %32)::Tuple{Int64,Union{Missing, Float64}}
│ %34 = (NamedTuple{(:x, :y),T} where T<:Tuple)(%33)::NamedTuple{(:x, :y),_A} where _A<:Tuple{Int64,Union{Missing, Float64}}
└─── goto #14
14 ─ goto #15
15 ┄ %37 = φ (#7 => true, #14 => false)::Bool
│ %38 = φ (#14 => %34)::NamedTuple{(:x, :y),_A} where _A<:Tuple{Int64,Union{Missing, Float64}}
│ %39 = φ (#14 => %16)::Int64
└─── goto #17 if not %37
16 ─ goto #20
17 ─ %42 = Base.add_int(%3, 1)::Int64
│ Tables.eachcolumns(Tables.add_or_widen!, sch, %38, columns, %42, updated, $(QuoteNode(Base.HasLength())))::Any Is that failure to inline related? Like, the inline-cost is calculated too expensive because we have (I've double checked that my definitions of |
base/compiler/tfuncs.jl
Outdated
if isnamedtuple && isa(ua, UnionAll) && uw.parameters[2] === ua.var | ||
# If the names are known, keep the upper bound (which we know is | ||
# at most Tuple), but otherwise widen to Tuple. | ||
# This is a widening heuristic to avoid keeping type information | ||
# that's unlikely to be useful. | ||
if uw.parameters[1] isa Tuple || (i == 2 && tparams[1] isa Tuple) |
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.
This feels like it assumes NamedTuple can only be used in very specific ways. But I don't see a particular reason to believe that i == 2
implies anything about it being the bound for the second parameter. As a trivial counter example, we can just flip the order of them:
julia> NamedTuple{T, S} where {S, T}
NamedTuple{T,S} where T where S
julia> ans{Tuple{Int}, (:a,)}
NamedTuple{(:a,),Tuple{Int64}}
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.
That's what uw.parameters[2] === ua.var
above is trying to check for --- that the var we're substituting for corresponds to the second parameter.
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.
Ah. I guess it's just the i == 2 && tparams[1] isa Tuple
that seemed strange, but I suppose that variable can be assumed that it must appear as the names for the NamedTuple in this case. And it's hopefully not important to deal with the case where the variables are swapped.
0d17843
to
fb82add
Compare
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.
Very late night thought: didn't we attempt part of this 6 months ago, before we realized this bound would be wrong, and did #33472 instead?
Counter-example:
julia> NamedTuple{<:Any, <:Any}
NamedTuple{var"#s1",var"#s2"} where var"#s2" where var"#s1"
base/compiler/tfuncs.jl
Outdated
if uw.parameters[1] isa Tuple || (i == 2 && tparams[1] isa Tuple) | ||
ub = typeintersect(ub, Tuple) | ||
else | ||
ub = Tuple | ||
end | ||
else | ||
ub = Any | ||
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.
if uw.parameters[1] isa Tuple || (i == 2 && tparams[1] isa Tuple) | |
ub = typeintersect(ub, Tuple) | |
else | |
ub = Tuple | |
end | |
else | |
ub = Any | |
end | |
if !(uw.parameters[1] isa Tuple || (i == 2 && tparams[1] isa Tuple)) | |
ub = Any | |
end | |
else | |
ub = Any | |
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.
Ah, yes. The Tuple
bound should be valid only if ai_w <: Type
above holds, i.e. if whatever we're putting in there is not a typevar.
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 think not even then?
julia> NamedTuple{<:Any, Val{T}} where T
NamedTuple{var"#s1",Val{T}} where var"#s1" where 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.
Ouch.
fb82add
to
734df30
Compare
4136c78
to
61cef56
Compare
Exciting! @JeffBezanson , do you have any thoughts on my inlining question from above? Just wondered if you were aware of something obvious. I'm planning on looking into it a little deeper as well. |
Since we infer |
This can make inference a bit slower, so I tried limiting it to NamedTuple types with known names, to mitigate the effects a bit.
@quinnj @timholy See how this works for you.
fixes #32699