Maybe there’s a way to get a sorted list of all matching methods for a type signature?
Something like:
julia> methods(+, Tuple{Int, Any})
# 14 methods for generic function "+":
[1] +(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:87
[2] +(c::Union{Int16, Int32, Int64, Int8}, x::BigInt) in Base.GMP at gmp.jl:534
[3] +(c::Union{Int16, Int32, Int64, Int8}, x::BigFloat) in Base.MPFR at mpfr.jl:384
[4] +(x::Number, y::Base.TwicePrecision) in Base at twiceprecision.jl:271
[5] +(::Number, ::Missing) in Base at missing.jl:117
[6] +(x::Number, J::LinearAlgebra.UniformScaling) in LinearAlgebra at /Applications/Julia-1.6.app/Contents/Resources/julia/share/julia/stdlib/v1.6/LinearAlgebra/src/uniformscaling.jl:146
[7] +(x::Real, z::Complex{Bool}) in Base at complex.jl:300
[8] +(x::Real, z::Complex) in Base at complex.jl:312
[9] +(a::Integer, b::Integer) in Base at int.jl:919
[10] +(x::Integer, y::Ptr) in Base at pointer.jl:161
[11] +(y::Integer, x::Rational) in Base at rational.jl:295
[12] +(x::T, y::T) where T<:Number in Base at promotion.jl:396
[13] +(x::Number, y::Number) in Base at promotion.jl:321
[14] +(x::Integer, y::AbstractChar) in Base at char.jl:224
I’m not sure if this will be ordered. It seems ordered, but it’s easy enough to sort the methods:
signatures = getfield.(methods(+, Tuple{Int, Any}).ms, :sig)
sort(signatures, by=<:)
Of course, you can only get a partial order. You could turn this into a directed graph, then traverse that to find methods.
Some code to do that
Forgive the style, I’d been coding for maybe two years when I wrote this.
using LightGraphs
using Combinatorics
"""
Given a type graph, removes all redundant edges (e.g. a path between nodes
already exists.)
"""
function prune_tree(g)
pruning_order = sortperm(map(length, g.fadjlist), rev=true)
new_tree = DiGraph(nv(g))
for node in pruning_order
all_children = g.fadjlist[node]
if isempty(all_children)
new_children = copy(all_children)
else
new_children = setdiff(all_children, union(g.fadjlist[all_children]...))
end
for child in new_children
add_edge!(new_tree, node, child)
end
end
return new_tree
end
"""
Creates type lattice
Args:
types: Array of types to make a graph out of
Returns a DiGraph whose edges denote subtype relationships.
"""
function type_graph(types::AbstractArray)
idxmapping = IdDict()
for (idx, i) in enumerate(types)
idxmapping[i] = idx
end
typeedges = Iterators.filter(x->(x[1]!=x[2])&&(x[1]<:x[2]), permutations(types, 2)) |> collect
edges = map(x->map(k->idxmapping[k]::Int, x), typeedges)
g = DiGraph(length(types))
map(x->add_edge!(g, x[2], x[1]), edges)
g = prune_tree(g)
return g
end
signatures = getfield.(methods(+).ms, :sig)
lattice = type_graph(signatures)
Which looks like:
You could then insert nodes on this graph as you discover more types.
I think I was trying something a little like this way back in the day. I pulled the code for this from an old repo but most of it won’t work anymore)