Skip to content

improve inference of keys(::Dict{String}) to fix invalidations #47089

@ranocha

Description

@ranocha

Can we improve inference of the following snippet?

julia> code_warntype(keys, (Dict{String},))
MethodInstance for keys(::Dict{String})
  from keys(a::AbstractDict) in Base at abstractdict.jl:105
Arguments
  #self#::Core.Const(keys)
  a::Dict{String}
Body::Base.KeySet{String, _A} where _A<:(AbstractDict{String})
1%1 = Base.KeySet(a)::Base.KeySet{String, _A} where _A<:(AbstractDict{String})
└──      return %1

I am using Julia v1.8.2. I think the return type should be inferred more concretely, with _A<:(Dict{String}) and not _A<:(AbstractDict{String}). This would fix a big amount of invalidations, e.g.,

julia> import Pkg; Pkg.activate(temp=true); Pkg.add("DataStructures")

julia> using SnoopCompileCore; invalidations = @snoopr(using DataStructures); using SnoopCompile

julia> length(uinvalidated(invalidations))
482

julia> trees = invalidation_trees(invalidations)
...
 inserting iterate(v::Union{Base.KeySet{<:Any, <:SwissDict}, Base.ValueIterator{<:SwissDict}}, state) in DataStructures at ~/.julia/packages/DataStructures/59MD0/src/swiss_dict.jl:646 invalidated:
...

julia> ascend(root)
Choose a call for analysis (q to quit):
     iterate(::Base.KeySet{String, _A} where _A<:(Dict{String}), ::Int64)
       iterate(::T) where T<:(Base.KeySet{String, _A} where _A<:(Dict{String}))
         copyto!(::Vector{String}, ::Base.KeySet{String, _A} where _A<:(AbstractDict{String}))
           _collect(::UnitRange{Int64}, ::Base.KeySet{String, _A} where _A<:(AbstractDict{String}), ::Base.HasElt
             collect(::Base.KeySet{String, _A} where _A<:(AbstractDict{String}))
 >             #_print#10(::Int64, ::Bool, ::Bool, ::Function, ::typeof(TOML.Internals.Printer._print), ::Nothing
...

The relevant part is

akeys = keys(a)
if sorted
akeys = sort!(collect(akeys); by)
end

In the first line, akeys is inferred as Base.KeySet{String, _A} where _A<:(AbstractDict{String}). If inference gave Dict{String} here, the invalidations would be gone. I also don't see a nice way to fix these invalidations since _print accepts a::AbstractDict and some comments suggest that AbstractDict is really required, not just Dict

# Use runtime dispatch here since the type of value seems not to be enforced other than as AbstractDict

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions