`compile_internal` generates the cache key

Passing a cache key to compile_internal is error prone and
laborious, so this PR changes `compile_internal` to generate the
cache key. This also enables caching for all calls to it, some of
which were previously not enabled because they passed no
`cache_key`.

This also adds a test for the caching, which checks the size of
the cache after the compilation of functions to determine whether
the cache is being used correctly.