Wrong `Location::caller` through `map_err(Into::into)` / equivalency of `map_err(Into::into)` and `?`

is there a way around this? I've been using map_err(Into::into) as a way to not do Ok(maybe_error?) as the last statement of a body, but I've realised it's not equivalent in the way I really need it to be equivalent, when tracking caller location. This means my error reporting is not correct because I'm using map_err(Into::into) in many places...

The call below is the From -> Into

I tried sprinkling a #[track_caller] on that impl in the std, but that just leads the location to an even worse place

#[allow(warnings)]
fn main() {
    // correct
    dbg!(hey());
    // correct
    dbg!(Err::<(), _>(()).map_err(|_| hey()));
    // /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/convert/mod.rs:716:9 - not good
    let _: Result<(), Hey> = dbg!(Err::<(), _>(()).map_err(Into::into));
    // correct
    let _: Result<(), Hey> = dbg!(|| -> Result<_, _> { Ok(Err::<(), _>(())?) }());
}

#[derive(Debug)]
struct Hey {
    s: String,
}

impl From<()> for Hey {
    #[track_caller]
    fn from(_: ()) -> Self {
        Hey { s: hey() }
    }
}

#[track_caller]
fn hey() -> String {
    format!("{}", std::panic::Location::caller())
}
[src/main.rs:4] hey() = "src/main.rs:4:10"
[src/main.rs:6] Err::<(), _>(()).map_err(|_| hey()) = Err(
    "src/main.rs:6:39",
)
[src/main.rs:8] Err::<(), _>(()).map_err(Into::into) = Err(
    Hey {
        s: "/rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/convert/mod.rs:716:9",
    },
)
[src/main.rs:10] (|| -> Result<_, _> { Ok(Err::<(), _>(())?) })() = Err(
    Hey {
        s: "src/main.rs:10:59",
    },
)

Is Ok(maybe_error?) good enough? Is there another way to solve this that I'm not thinking about? Could this be fixed in the standard library?

it's more of a style or personal taste. I would prefer the question mark to map_err() in general. so it's good enough for me. but that's just me.

I don't know if it's better or worse, but it's at least an alternative, use a closure to wrap the From::from()

let _: Result<(), Hey> = dbg!(Err::<(), _>(()).map_err(|e| Hey::from(e)));

note, you must use From directly, not through the blanket Into, because- the blanket Into::into() doesn't track_caller. [1]

I don't think it will change.


  1. you can, e.g., impl Into<Hey> for () with an #[track_caller] attribute, but you lose the ability to use the question mark operator, which needs From ↩ī¸Ž

1 Like

This is actually a very good solution, it suggests I can replace .map_err(Into::into) with .map_err(|e| <_>::from(e))). But maybe I should just accept Ok(e?) as the easier way to do it