begin-rescue-end and def-rescue-end stacktraces inconsistent
I have filed this as type Misc because I don't know whether the current behaviour is intended or a true bug. Please re-allocate appropriately if that's desired.
When an exception is thrown from within a rescue clause, it captures a frame representing the language construct the rescue is part of. This could be a dedicated begin-rescue-end construct or the def-rescue-end construct that combines method definition and exception handling. In the case of begin-rescue-end, it is represented in the stacktrace as the line on which the header of the construct (ie the "begin" statement) is written. However, in the case of def-rescue-end, it is represented in the stacktrace as the line on which the first statement in the construct's body is written. In the most typical code this is the line following the line containing the header (ie the "def" statement).
I expect this is difference doesn't cause a significant problem when backtraces are read by human developers. However, I have found this can cause extra difficulty for writing computer-assisted debugging tools.
My preference would be for both constructs to follow the begin-rescue-end behaviour (report the header line in the backtrace). Begin and def header lines do not appear 'normally' in a backtrace, and therefore their presence unambiguously refers to rescue flow. Because def-rescue-end uses the first statement of the body, this statement could also be reported in a backtrace due to regular method-entry, therefore it is not as clear what is being reported. I feel reporting with the header line is preferable both for human ease of reading and writing tools.
Tested in version ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]
begin # Line A 2 + 2 raise '' rescue 2 + 2 puts 'in block' begin raise '' # Line B rescue => e puts e.backtrace end end def test # Line C 2 + 2 # Line D raise '' rescue => e 2 + 2 puts 'in method' begin raise '' # Line E rescue => e puts e.backtrace end end test() # Line F
in block [Line B]:in `rescue in <main>' [Line A]:in `<main>' in method [Line E]:in `rescue in test' [Line D]:in `test' [Line F]:in `<main>'
in block [Line B]:in `rescue in <main>' [Line A]:in `<main>' in method [Line E]:in `rescue in test' [Line C]:in `test' [Line F]:in `<main>'
Thank you very much for providing the fantastic ruby language.