I haven't managed to minimize this yet, but github+cargo makes it pretty easy to reproduce:
git clone -b i32-inference-problem-demo https://github.com/dekellum/http
rustc --version
cargo test
cargo test --doc src/response.rs # more failures here
On our MSRV 1.39.0 and recent nightly as shown:
rustc 1.49.0-nightly (1773f60ea 2020-11-08)
error[E0277]: the trait bound `http::StatusCode: From<i32>` is not satisfied
--> tests/status_code.rs:30:15
|
30 | let max = StatusCode::try_from(999).unwrap();
| ^^^^^^^^^^^^^^^^^^^^ the trait `From<i32>` is not implemented for `http::StatusCode`
|
= help: the following implementations were found:
<http::StatusCode as From<&'a http::StatusCode>>
= note: required because of the requirements on the impl of `Into<http::StatusCode>` for `i32`
= note: required because of the requirements on the impl of `TryFrom<i32>` for `http::StatusCode`
= note: required by `try_from`
error: aborting due to previous error
A workaround in tests/status_code.rs is to use 999u32. But why is that needed?
Or impl TryFrom<UT> for StatusCode and From<StatusCode> for UT for UT over all signed types (git revert d54d394).
More mysteriously, removing TryFrom<UT> and From<StatusCode> for UT, UT over u32, usize and u64 also avoids the issue? So adding only unsigned conversions can effectively be a breaking change to your public interface? See that change below:
Yup. This is the major part of why we haven't allowed array indexing by u8, for example -- right now a[4] knows the 4 is a usize because that's the only integer with an implementation (Index<usize>), but if we added Index<u8> then it'd go "wait, there's two? I'll fallback to i32 then" and start failing everything for there not being an Index<i32>.
Unfortunately you either need to pick just one integer type, or to basically allow all of them.
When there's one possibility for the TryFrom, that will be the inference. If there is more than one possibility, though, it won't choose between them and ends up falling back to i32. If you add i32 to the list (without making the list complete), it will work (due to the fallback, not inference). But as @scottmcm said, better to do them all if sensible.
The type in question here, http::StatusCode is unsigned for its supported range, so that's why we initially picked support for all unsigned integer type conversions, and skipped the signed ones. Is there somewhere, literally, a "fallback to i32" for unannotated positive integer literals? Perhaps asked another way, why wouldn't rustc try usize or u64 or u32 before giving up with this error?
Not that I''m aware of (but I didn't go look either). Changing the fallback generally would be a breaking change, but I'm less sure about something like "I've narrowed the choice down to all unsigned integers and i32 won't compile, guess I'll go with u32 instead". I'd be interested to see what other people think.