It can do that, but since the call to make_test_Float16() is in the same compilation unit as the dynamic part, it doesn’t. You can make it do that by creating a function barrier though:
julia> function call_barrier(f::F, args...) where {F}
f(args...)
end;
julia> let
make_test_Float16 = _make_test(Float16)
call_barrier(make_test_Float16) do f
@allocated f()
end
end
0
Since call_barrier needs to specialize on the type of make_test_Float16, it forces its type to be resolved before it is called.
See also: this section of the performance tips