Skip to content

Possible missing backedges and spurious (?) invalidation triggered by UnionAll #36892

Closed

Description

I've been poking at this for a while now and still can't quite isolate this the way I want, so let me show you what I have. I'm trying to figure out how to set up a test for a fix for invalidations from loading ColorTypes.

The invalidations are triggered by adding new eltype(::Type) specializations. The ColorTypes issue is fixed just by adding

eltype(::Type{<:NamedTuple}) = Any

but I wonder if there's a more systematic fix? For the record we already have a definition

eltype(::Type{NamedTuple{names,T}} where names) where {T} = eltype(T)

so this is just about handling the case where the type is not fully specified.

Here is a prototype and analysis:

julia> f(::Type{T}) where T = eltype(T)
f (generic function with 1 method)

julia> function g()
           while true  # block interpreter
               return f(T where T<:NamedTuple{(:indent,)})
           end
       end
g (generic function with 1 method)

julia> g()
Any

julia> using SnoopCompileCore

julia> abstract type Container{T} end

julia> invlist = @snoopr Base.eltype(::Type{C}) where {T,C<:Container{T}} = T;

julia> using SnoopCompile

julia> trees = invalidation_trees(invlist)
1-element Vector{SnoopCompile.MethodInvalidations}:
 inserting eltype(::Type{C}) where {T, C<:Container{T}} in Main at REPL[6]:1 invalidated:
   backedges: 1: superseding eltype(::Type) in Base at array.jl:123 with MethodInstance for eltype(::Type{A} where A<:(NamedTuple{(:io,),_A} where _A<:Tuple{IO})) (3 children)
              2: superseding eltype(::Type) in Base at array.jl:123 with MethodInstance for eltype(::Type{A} where A<:(NamedTuple{(:init,),_A} where _A<:Tuple{IOContext})) (4 children)
              3: superseding eltype(::Type) in Base at array.jl:123 with MethodInstance for eltype(::Type{A} where A<:(NamedTuple{(:indent, :first_block, :sorted, :by),_A} where _A<:Tuple{Int64,Bool,Bool,Function})) (4 children)
              4: superseding eltype(::Type) in Base at array.jl:123 with MethodInstance for eltype(::Type{A} where A<:(NamedTuple{(:indent, :sorted, :by),_A} where _A<:Tuple{Int64,Bool,Function})) (5 children)
              5: superseding eltype(::Type) in Base at array.jl:123 with MethodInstance for eltype(::Type{A} where A<:(NamedTuple{(:indent, :region_active),_A} where _A<:Tuple{Any,Bool})) (171 children)


julia> m = only(methods(f))
f(::Type{T}) where T in Main at REPL[1]:1

julia> m.specializations
svec(#undef, #undef, #undef, #undef, #undef, #undef, MethodInstance for f(::Type{NamedTuple{(:indent,),T} where T<:Tuple}), MethodInstance for f(::Type{T}) where T)

julia> mi = m.specializations[end]
MethodInstance for f(::Type{T}) where T

julia> mi.backedges
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(x::Core.MethodInstance, f::Symbol)
   @ Base ./Base.jl:33
 [2] top-level scope
   @ REPL[13]:1

To edit a specific method, type the corresponding number into the REPL and press Ctrl+Q

julia> mi = m.specializations[end-1]
MethodInstance for f(::Type{NamedTuple{(:indent,),T} where T<:Tuple})

julia> mi.backedges
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(x::Core.MethodInstance, f::Symbol)
   @ Base ./Base.jl:33
 [2] top-level scope
   @ REPL[15]:1

To edit a specific method, type the corresponding number into the REPL and press Ctrl+Q

Where are the backedges? I guess they must be runtime dispatched...I was just surprised since there's only one method. But of course that's good in many ways since it severs the chain of invalidations. However, that's not what happens with the cases above. They are triggered by the REPL, as you can verify with node = only(trees).backedges[end]; ascend(node).

I've also tried this:

# This first part is my attempt to set up a test that will replicate some of the code in REPL that gets invalidated
# Doesn't work yet
julia> nteltypekw(; indent=0,region_active::Bool=false,kwargs...) = indent
nteltypekw (generic function with 1 method)

julia> nteltype(c) = (x = c[]; nteltypekw(; indent=x.indent, extra=:none))
nteltype (generic function with 1 method)

julia> struct HasIndent indent::Int end

julia> hi = HasIndent(3)
HasIndent(3)

julia> nteltype(Ref{Any}(hi))
3

as a way of aiming for the same thing without explicitly manipulating NamedTuple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions