Repository: dtolnay/anyhow (rust)

Issue:
Adding context breaks type inference
Adding context seems to break type inference. For example:

```rust
use anyhow::{Context, Result};

fn main() -> Result<()> {
    let x = "k";
    let y: u32 = x.parse().context("context")?;
    println!("{}", y);
    Ok(())
}
```

gives 

```
error[E0284]: type annotations required: cannot resolve `<_ as std::str::FromStr>::Err == _`
 --> src\main.rs:5:20
  |
5 |     let y: u32 = x.parse().context("context")?;
  |
```

obviously using turbofish syntax works, like: 

```rust
let y = x.parse::<u32>().context("context")?;
```

but it is surprising behaviour. Might be a compiler limitation but I still wanted to mention it.


Pull request:
Consolidate to one Context impl for Result to improve inference
Fixes #18.

Patch:
diff --git a/src/context.rs b/src/context.rs
index 421c7da..2483f34 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -65,37 +65,49 @@ pub trait Context<T, E>: private::Sealed {
         F: FnOnce() -> C;
 }
 
-impl<T, E> Context<T, E> for Result<T, E>
-where
-    E: StdError + Send + Sync + 'static,
-{
-    fn context<C>(self, context: C) -> Result<T, Error>
-    where
-        C: Display + Send + Sync + 'static,
-    {
-        self.map_err(|error| Error::new(ContextError { error, context }))
+mod ext {
+    use super::*;
+
+    pub trait StdError {
+        fn ext_context<C>(self, context: C) -> Error
+        where
+            C: Display + Send + Sync + 'static;
     }
 
-    fn with_context<C, F>(self, context: F) -> Result<T, Error>
+    impl<E> StdError for E
     where
-        C: Display + Send + Sync + 'static,
-        F: FnOnce() -> C,
+        E: std::error::Error + Send + Sync + 'static,
     {
-        self.map_err(|error| {
+        fn ext_context<C>(self, context: C) -> Error
+        where
+            C: Display + Send + Sync + 'static,
+        {
             Error::new(ContextError {
-                error,
-                context: context(),
+                error: self,
+                context,
             })
-        })
+        }
+    }
+
+    impl StdError for Error {
+        fn ext_context<C>(self, context: C) -> Error
+        where
+            C: Display + Send + Sync + 'static,
+        {
+            self.context(context)
+        }
     }
 }
 
-impl<T> Context<T, Error> for Result<T, Error> {
+impl<T, E> Context<T, E> for Result<T, E>
+where
+    E: ext::StdError + Send + Sync + 'static,
+{
     fn context<C>(self, context: C) -> Result<T, Error>
     where
         C: Display + Send + Sync + 'static,
     {
-        self.map_err(|error| error.context(context))
+        self.map_err(|error| error.ext_context(context))
     }
 
     fn with_context<C, F>(self, context: F) -> Result<T, Error>
@@ -103,7 +115,7 @@ impl<T> Context<T, Error> for Result<T, Error> {
         C: Display + Send + Sync + 'static,
         F: FnOnce() -> C,
     {
-        self.map_err(|error| error.context(context()))
+        self.map_err(|error| error.ext_context(context()))
     }
 }
 
@@ -198,12 +210,10 @@ where
 }
 
 mod private {
-    use crate::Error;
-    use std::error::Error as StdError;
+    use super::*;
 
     pub trait Sealed {}
 
-    impl<T, E> Sealed for Result<T, E> where E: StdError + Send + Sync + 'static {}
-    impl<T> Sealed for Result<T, Error> {}
+    impl<T, E> Sealed for Result<T, E> where E: ext::StdError {}
     impl<T> Sealed for Option<T> {}
 }


Test patch:
diff --git a/tests/test_context.rs b/tests/test_context.rs
new file mode 100644
index 0000000..1d35c13
--- /dev/null
+++ b/tests/test_context.rs
@@ -0,0 +1,10 @@
+use anyhow::{Context, Result};
+
+// https://github.com/dtolnay/anyhow/issues/18
+#[test]
+fn test_inference() -> Result<()> {
+    let x = "1";
+    let y: u32 = x.parse().context("...")?;
+    assert_eq!(y, 1);
+    Ok(())
+}