Add stack annotation primop
Motivation
Reading the IPE Backtrace can be quite unhelpful, see #26040.
The apparent solution to add HasCallStack constraints is unsatisfactory as well, as it changes the public API of the function and may affect optimisation.
Adding HasCallStack just for debugging is also a tedious process, either automated via a plugin or done manually.
However, if the exception is thrown from within library code that lacks HasCallStack constraints, then the callstacks are often still useless!
Proposal
To improve upon this situation, we introduce a new primop called annotateStack# :: a -> IO b -> IO b (simplified), which allows the user to push stack frames containing arbitrary data.
This data can be recovered when decoding the stack, allowing us to enhance IPE backtraces with additional, human-readable stack entries.
The main advantage over HasCallStack constraints are:
- Doesn't need to change the signature of a function
- remains an implementation detail
- More general, as more than just source locations can be added
These stack frames are otherwise no-ops and supposed to be cheap, so adding them to the implementation of a function has a negligible performance impact.