Introspection for checking an implementation

After some trial and error, the solution so far looks like this:

code_info(x, tp=Tuple) = Base.CodeInfo[]
code_info(fun::Function, t=Tuple) = Base.code_lowered(fun, t)
function code_info(s::Symbol, tp=Tuple)
    local fun
    try
        fun = eval(s)
    catch
        return Base.CodeInfo[]
    else
        code_info(fun, tp)
    end
end
function code_info(v::AbstractVector, t=Tuple)
    unique(mapreduce(x->code_info(x, t), vcat, v,init=Base.CodeInfo[]))
end

global_refs(x) = Core.GlobalRef[]
global_refs(r::GlobalRef) = [r]
global_refs(ex::Expr) = global_refs(ex.args)
global_refs(ci::Base.CodeInfo) = global_refs(ci.code)
function global_refs(cis::AbstractVector)::Vector{GlobalRef}
    refs = mapreduce(global_refs, vcat, cis, init=Core.GlobalRef[])
    unique(refs)
end

Using these functions, I can check for the “bad” (or “good”) calls:

function search_main_calls(fun::Symbol, sym::Symbol, types=Tuple; recursion_limit=5)
	for k in 1:recursion_limit
        ci = code_info(fun, types)
        refs = global_refs(ci)
        if any(r.name===sym for r in refs if r.mod===Main)
            return :found
        end
        fun = [r.name for r in refs if r.mod===Main]
	end
	return :not_found
end

This does not try to recurse into standard library and detects your attempt to cheat:

julia> search_main_calls(:my_sum, :sum)
:found

If there’re any counterexamples to that solution, I’d appreciate hearing about them.

1 Like