Despite some niceties like union types, Dialyzer is pretty limited. For example, here is example of something I would expect to be able to express in a modern type system but is not possible with Dialyzer (as far as I know):
@spec foo[a: SomeProtocol & SomeBehaviour](a, a) :: a
I've also noticed that it lets through stuff that I would expect to fail to compile, so it's hard to trust as I would a type system like Elm's, Haskell's or Rust's. The Elixir devs have done a great job with the language, and it's great to see the resurgence of interest in BEAM as a result, but I still really wish they had taken the opportunity to build in a decent type system...