backtraces are collected in the wrong place when using error (vs throw)
If we look at the definition of `error` vs `throw` you will see
```
77 -- | Throw an exception. Exceptions may be thrown from purely
78 -- functional code, but may only be caught within the 'IO' monad.
79 --
80 -- WARNING: You may want to use 'throwIO' instead so that your pure code
81 -- stays exception-free.
82 throw :: forall (r :: RuntimeRep). forall (a :: TYPE r). forall e.
83 (HasCallStack, Exception e) => e -> a
84 throw e =
85 -- Note the absolutely crucial bang "!" on this binding!
86 -- See Note [Capturing the backtrace in throw]
87 -- Note also the absolutely crucial `noinine` in the RHS!
88 -- See Note [Hiding precise exception signature in throw]
89 let se :: SomeException
90 !se = noinline (unsafePerformIO (toExceptionWithBacktrace e))
91 in raise# se
```
However, error calls `raise#` directly, which bypasses this important bang in `throw.
```
33 -- | 'error' stops execution and displays an error message.
34 error :: forall (r :: RuntimeRep). forall (a :: TYPE r).
35 HasCallStack => [Char] -> a
36 error s = raise# (errorCallWithCallStackException s ?callStack)
199 errorCallWithCallStackException :: String -> CallStack -> SomeException
200 errorCallWithCallStackException s stk = unsafeDupablePerformIO $ do
201 withFrozenCallStack $ toExceptionWithBacktrace (ErrorCall s)
202 where ?callStack = stk
```
The result is that exceptions raised by `error` don't have IPE backtraces which point to the correct location, since the IPE backtrace is only collected when the exception context is forced.
The notes `[Capturing the backtrace in throw]` and `[Hiding precise exception signature in throw]` explain the implementation.
issue