How to avoid compilation of an uncalled function

I have some code that generates a lot of function calls within different code branches. Each function call generates a different function instance. All these function instances are getting precompiled when my module is precompiled, which is killing the precompilation time. The thing is, even though many functions are instantiated (i.e. a call exists in the code), very few of them will actually get called. I would like to ensure that certain functions are only compiled when they are actually called, and not when they are instantiated. Is this possible?

Here is a MWE of the problem:

function valuedispatch_expr(::Val{lower}, ::Val{upper}, val, fun) where {lower, upper}
    if lower >= upper
        return :( $fun(Val($upper)) ) 
    end
    midpoint = lower + div(upper - lower, 2)
    expr_a = valuedispatch_expr(Val(lower), Val(midpoint), val, fun)
    expr_b = valuedispatch_expr(Val(midpoint+1), Val(upper), val, fun)
    return quote
        if $val <= $midpoint
            $expr_a
        else
            $expr_b
        end
    end
end

macro valuedispatch_macro(lower::Int, upper::Int, val, fun)
    ex = valuedispatch_expr(Val(lower), Val(upper), esc(val), esc(fun))
    quote
        $ex
        return nothing
    end
end

@eval valuedispatch_1_32(val, fun) = @valuedispatch_macro(1, 32, val, fun)

@generated function myfun(::Val{v}) where v
    println("Compiling ", v)
    return :(println("Running ", $v))
end

println(valuedispatch_1_32(3, myfun))

While only one function actually gets called, 32 get compiled.

EDIT: At first I thought this might be because the compiler wants to understand the output type, so needs to compile all functions for that reason. However, I’ve now changed the code so that the valuedispatch function always returns nothing. The problem still persists.

You can use the @nospecialize macro at the beginning of the generated function, as follows:

macro valuedispatch_macro(lower::Int, upper::Int, val, fun)
    ex = valuedispatch_expr(Val(lower), Val(upper), esc(val), esc(fun))
    return quote
        @nospecialize
        $ex
        return nothing
    end
end

Because valuedispatch_1_32 is now a generic function, it knows nothing about the function myfun being passed in, and so cannot precompile it.

I have a similar problem, but in a @generated function. I haven’t, as yet, been able to fix it.