How can I access typespecs of compiled but not yet stored to BEAM file module?

I am struggling to figure out how can I get to typespecs in the sibling module during the compilation phase.

The minimal viable example would be:

defmodule Typespecs.Types do
  @type my_type :: atom()
end

defmodule Typespecs do
  alias Typespecs.Types

  # Try to load typespecs from the sibling module.
  IO.inspect(Code.Typespec.fetch_types(Types), label: "Types #1")
  Types = Code.ensure_compiled!(Types)
  IO.inspect(Code.Typespec.fetch_types(Types), label: "Types #2")
end

it evidently produces :error in both cases because Code.Typespec.fetch_types/1 requires a BEAM file and at the moment it’s not yet flushed to disk.

Kernel.Typespec.translate_typespecs_for_module/2 is not quite helpful because :ets tables are available only while the module (Types in this case) is open and it’s already closed at the moment I get to it.

I have tried to implement my own compile tracer, but there is no proper event to grab the content of :ets tables and store it somewhere at fingers, plus this solution seems to be too hacky.

I am positive I am missing something obvious. Any insights on how can I get to typespecs of already compiled but not yet stored to the disk module?

1 Like

It’s not quite fair, but I’m posting this comment to emerge the question once more.

Any insight, including but not limited to blind suggestions would be extremely appreciated.

I feel compelled to point out that Code.Typespec is @moduledoc false (source_link) so it is private and you shouldn’t be calling it in your code as it’s behavior could change in any Elixir patch release.

Unfortunately I’m not aware of any public function to fetch typespecs (although one may exist), if there was a public function it would be nice to use it in ElixirSense (which powers ElixirLS).

1 Like

Yes, thanks, I am fully aware of this. I am playing with things that require types and I’d better follow up on the changes in the undocumented core rather than roll on my own wheel.