Frames Catherine White
Frames Catherine White

Reputation: 28212

How do I check if a given `Method` object accepts a given `Tuple` of types in Julia 0.6?

The goal is to define a function that takes a method, and a tuple of types, and returns true those types are a valid input for that method. Not function, method

accepts(meth::Method, types::Tuple)::Bool

Here is a testset for this

using Base.Test
@testset "accepts method checker" begin
    concrete = first(methods(length, (String,)))
    #length(s::String) in Base at strings/string.jl:162

    abstract_ = last(collect(methods(length,(AbstractArray,))))
    #length(t::AbstractArray) in Base at abstractarray.jl:131

    triangular = first(methods(length, (StepRange,)))
    # length(r::StepRange{T,S} where S) where T<:Union{Int64, UInt64} in Base at range.jl:381

    a = "hello"
    a_t = (typeof(a),) #(String,)
    @test accepts(concrete, a_t)
    @test !accepts(abstract_, a_t)
    @test !accepts(triangular, a_t)

    b = 1.5:10
    b_t = (typeof(b),) #(StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}})
    @test !accepts(concrete, b_t)
    @test accepts(abstract_, b_t)
    @test !accepts(triangular, b_t)

    c_t = (StepRange{Float64, Float64},) # Nothing real has this type as it can't be constructed
    @test !accepts(concrete, c_t)
    @test accepts(abstract_, c_t)
    @test !accepts(triangular, c_t)

    d = 1:2:10
    d_t = (typeof(d),) #(StepRange{Int64,Int64}
    @test !accepts(concrete, d_t)
    @test accepts(abstract_, d_t)
    @test accepts(triangular, d_t)
end

Since julia don't have much of a public reflection API (as I have griped before), I am fine with code that is going to break potentially every patch version

The goal of this question is to help me understand what I am going to need to do to update this part of InterfaceTesting.jl from 0.5 to 0.6

The thing that makes my old code no longer work is changes that were introduced to allow for triangular dispatch. So the triangular tests are the hard ones to pass.

Upvotes: 3

Views: 87

Answers (1)

Frames Catherine White
Frames Catherine White

Reputation: 28212

This is frankly scary code but:

function accepts(d::Method, ts::Tuple)
    ps = Base.unwrap_unionall(d.sig).parameters[2:end]
    length(ts) != length(ps) && return false

    all(zip(ts, ps)) do tp
        t, p = tp
        x = Base.rewrap_unionall(p, d.sig)
        Base.type_close_enough(x, t) || t <: x
    end
end

passes all of your tests. I'm not certain there isn't some corner case it misses though. You have no tests with multiple types in that Tuple. It is basically ripped off from methodswith

Upvotes: 4

Related Questions