Dialyzer: inferring types when using Mox

The approach as stated does loose type information, but not because of mox or behaviours, but because of the runtime selection of the used implementation. No static analysis can catch errors based on information not available statically in the code.

If you make impl() return MyImplementation statically or correctly hardcode the typespec return value of it as MyImplementation then dialyzer can help you. But loosening the type information to not return a specific module means dropping to any module(), which is an alias for atom(). There’s nothing to check if the returned module is unknown.

The typesystem dialyzer uses doesn’t allow you to say “but the module returned implements that behaviour”. It’s either one specific module or any module for that typesystem.

Given the typesystem doesn’t help you can however go the “statically known” route. If you don’t need runtime selection you can compile the configured implementation into the module statically.

@impl Application.compile_env(:dialyzer_mox_behaviours, :impl, MyImplementation)
@spec impl() :: module()
defp impl(), do: @impl