Description
When an error type is guaranteed to come From<>
a result error type by means of a trait constraint in a generic function with a constant result type, the idiom some_result.map_err(|e| e.into())
works, but the should-be equivalent Ok(some_result?)
does not and produces:
the trait `std::convert::From<<W as Worker>::Error>` is not implemented for `GenericError`
That can be alleviated by explicitly demanding that From<<W as Worker>::Error>
of the generic function's error type, but my expectation would be that this is implied by the type constraint -- especially since the .map_err
version that should be equivalent to the ?
one does "get it".
Full example:
#[derive(Debug)]
struct GenericError();
// impl Into<GenericError> for i32 {
// fn into(self) -> GenericError {
// GenericError()
// }
// }
impl From<i32> for GenericError {
fn from(_: i32) -> Self {
GenericError()
}
}
trait Worker {
type Error: Into<GenericError>;
fn do_something(&self) -> Result<(), Self::Error>;
}
struct IntegerWorker();
impl Worker for IntegerWorker {
type Error = i32;
fn do_something(&self) -> Result<(), Self::Error> {
Err(42)
}
}
fn process<W>(w: W) -> Result<(), GenericError> where
W: Worker,
// GenericError: From<<W as Worker>::Error>
{
let some_result = w.do_something();
// // This works:
// some_result.map_err(|e| e.into())
// This doesn't
Ok(some_result?)
}
fn main() {
let w = IntegerWorker();
println!("Result: {:?}", process(w));
}
This fails to build with the above error message, while the commented-out version with .map_err(|e| e.into())
builds fine. Adding the GenericError: From<...>
"where" clause solves the build error, but is unergonomic (it'd clutter all functions working on that type).
In case it is relevant: If Into<>
is implemented instead of the equivalent From<>
(top comment block), then the problem still exists, but adding the additional constraint does not solve it any more but produces a different error message.
Meta
Previous research on web and issue tracker search turned out dry, and disucssion on IRC just helped rule out some possible oversights. The behavior is the same with 1.29.0, 1.30.0 and current nightly; full example version:
rustc 1.30.1 (1433507eb 2018-11-07)
binary: rustc
commit-hash: 1433507eba7d1a114e4c6f27ae0e1a74f60f20de
commit-date: 2018-11-07
host: x86_64-unknown-linux-gnu
release: 1.30.1
LLVM version: 8.0