Can you elaborate? E.g. give an example use-case with an unhelpful error message and explain how #[track_caller] on map_err would have helped? Feel free to re-implement map_err to demonstrate adding it really does what you expect it does.
map_err doesn't panic and the closure argument likely doesn't have #[track_caller] either. As such #[track_caller] on map_err will have no effect at all.
Right now this captures the location of — FnOnce::call_once()?? Huh, worse than I expected.
Currently, it is possible to do this if you use ? rather than map_err (since there are then no higher-order-function call frames involved); this captures the location in main():
I'm working around it for that concrete use case by an "anchoring" wrapper which captures the location itself and forwards it to the eventual call ops:
That of course comes at an ergonomic cost in calling, reading and writing the code. Basically having to duplicate the constructors. It was always a minor annoyance but those tracing information is typically removed after prototyping anyways, so I never truly minded. That may be complacency though.
A followup experiment: I tried to find out if this could be trivially patched into the standard library, and the answer is no.
I tried adding #[track_caller] to Result::map_err(), and, unsurprisingly given the previous experiment, this didn't help — the location reported was the declaration of FnOnce::call_once().
FnOnce::call_once() cannot have #[track_caller] since its ABI is not "Rust".
So, progress here would require the compiler to allow #[track_caller] on the "rust-call" ABI, which I would imagine is hard and possibly disruptive.
It's certainly a nontrivial amount of work, but FWIW, extern "rust-call" exclusively acts to make extern "rust-call" fn call(&self, args: (A, B, C)) have the same ABI as extern "rust" fn call(&self, a: A, b: B, c: C). Adding #[track_caller] to extern "rust-call" thus has a single obvious interpretation (to be equivalent to adding #[track_caller] to the splatted form).
That said, if you take the example and instead do failing().map_err(|e| capture(e)), the captured location is «crate::main::{{closure}} at ./src/main.rs:LL:CC» instead, which is much more useful.
the full panic backtrace shows something interesting: with the closure, the backtrace is Result::map_err/main::{{closure}}/then_panic, but without the closure, it's Result::map_err/FnOnce::call_once/then_panic. With then_panic as fn(_) -> ! we get a Location capture pointing at the fn keyword of fn then_panic and a backtrace of Result::map_err/FnOnce::call_once/then_panic{{reify.shim}}/then_panic
I think instead of making the FnOnce::call_once frame #[track_caller], I think that's the behavior to target if we want to improve behavior here; at least make it such that using the function object directly for a #[track_caller] acts like the closure rather than getting a FnOnce::call_once frame that doesn't show up otherwise.