But is that limit set to ensure termination or for performance?
Both, in practice. Dialyzer iterates to a fix point to find the appropriate types for your code. Having unboundedly unrolled recursive types would mean the inferred types can keep growing. Also, some operations scale poorly with the size of the types, so keeping a conservative limit on them keeps the performance from drastically degrading as a codebase grows.
How could one write an infinite union type (except integer ranges which allow us to express (+|-)inf)?
Depends on precisely what you are looking for. There’s no (or a very high) limit on the size of specs, so you can write very detailed function type definitions, albeit not arbitrarily complex nor all infinite types. Notably though, once any specs are combined with Dialyzer’s inferred success types (and during the inference of the success types themselves), then types are limited in various ways (level of unrolling of recursive types, sizes of sets of integers, atoms, etc., unions of ranges of numbers are coalesced, etc.).
I suppose, as with any such system, there’s some trade-off between expressiveness, soundness and performance, and Dialyzer sits in a fairly unconventional position in that space.
To your original question:
Is there any way except parse transformations to make those specs more precise without exhaustively creating all those boilerplate spec clauses
Whether you manually create all those clauses or have a tool generate them, Dialyzer (and, of course, other tools may do other things) probably won’t benefit from them, due to the various simplifying generalisations it makes. Whilst you can increase those very conservative limits, performance will suffer, so there will always be a point where you want to express a type which is too complex to feasibly exhaustively check with Dialyzer. What’s more, Dialyzer errors can be tricky for a human to trace back to a root cause, so even if Dialyzer could generate a warning, it might still be infeasible to understand and rectify it.
On a positive note, I am working on substantially improving Dialyzer’s performance (talk at CodeBEAM in Berlin next month, if you’re interested!), and I am aware of some techniques to improve the quality of error messages by displaying the reasoning steps Dialyzer took to reach its conclusion, so whilst the fundamental limits will continue to exist, we might well have a better experience in practice in coming releases.