Minimal self-containing example of code transformation using generated functions?

As always, writing down a question brings a lot of new ideas. Such as watching the Jarrett’s talk on Cassette design, especially this moment where he explains that generated functions can return either an expressions, or CodeInfo instance. So I tried this:

@generated function transform(f, args...)
    ci = @code_lowered f(args...)
    return ci
end

inc(x) = x + 1
transform(inc, 2.0)

which didn’t work and just returned an empty Core.CodeInfo[]. The problem of course was that generated functions work not on values, but on types, so f, args are actually (typeof(inc), (Float64,)). Thus we need a slightly different way of getting the CodeInfo:

@generated function transform(f, args...)
    ci = code_lowered(f.instance, args)[1]
    return ci
end

transform(inc, 2.0)

This version fails with segfault, but in this case it’s a good thing - it means that Julia accepted the new CodeInfo instance, just couldn’t validate it. I know that generating a valid instance of CI can be done using tools from the JuliaCompilerPlugins org, but if somebody wants to jump in with a quick example, you are welcome!