Skip to content

rustc sometimes resolves an ambiguous generic parameter instead of erroring #91369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
TheBlueMatt opened this issue Nov 29, 2021 · 0 comments
Labels
A-inference Area: Type inference C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@TheBlueMatt
Copy link

Apologies that I don't have a minimum reproduction but I've tried a few ways and thus far failed to reproduce outside of the original crate.

We recently had an error where we were deserializing a dummy object for backwards-compatibility, but the type being read was ambiguous, causing the code to behave unexpectedly. For some reason rustc concretized the object to an Option<()> (guessing based on {:?} output, as I can't tell why it was concretized) when it was ambiguous (we really wanted an Option<u64> but didn't specify it).

You can see the change which fixes it at lightningdevkit/rust-lightning#1195, which makes pretty clear that the object's type was, in fact, ambiguous (switching the changed declaration to None::<()> works just as well, while changing behavior). The read_tlv_fields macro isn't all that complicated - https://github.com/lightningdevkit/rust-lightning/blob/main/lightning/src/util/ser_macros.rs#L332 - it basically just calls into decode_tlv_stream which is pretty straightforward - https://github.com/lightningdevkit/rust-lightning/blob/main/lightning/src/util/ser_macros.rs#L168.

I tried (and failed) to get a minimum reproduction which at least shows the high-level code structure at https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=c873827053afdaa20d333703d00fd16f (the actual relevant things are mostly in util::ser and util::ser_macros in the real code).

@TheBlueMatt TheBlueMatt added the C-bug Category: This is a bug. label Nov 29, 2021
@inquisitivecrystal inquisitivecrystal added A-inference Area: Type inference T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 30, 2021
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this issue Jul 1, 2022
This fixes an insta-panic in `ChannelMonitor` deserialization where
we always `unwrap` a previous value to determine the default value
of a later field. However, because we always ran the `unwrap`
before the previous field is read, we'd always panic.

The fix is rather simple - use a `OptionDeserWrapper` for
`default_value` fields and only fill in the default value if no
value was read while walking the TLV stream.

The only complexity comes from our desire to support
`read_tlv_field` calls that use an explicit field rather than an
`Option` of some sort, which requires some statement which can
assign both an `OptionDeserWrapper<T>` variable and a `T` variable.
We settle on `x = t.into()` and implement `From<T> for
OptionDeserWrapper<T>` which works, though it requires users to
specify types explicitly due to Rust determining expression types
prior to macro execution, completely guessing with no knowlege for
integer expressions (see
rust-lang/rust#91369).
TheBlueMatt added a commit to TheBlueMatt/rust-lightning that referenced this issue Jul 5, 2022
This fixes an insta-panic in `ChannelMonitor` deserialization where
we always `unwrap` a previous value to determine the default value
of a later field. However, because we always ran the `unwrap`
before the previous field is read, we'd always panic.

The fix is rather simple - use a `OptionDeserWrapper` for
`default_value` fields and only fill in the default value if no
value was read while walking the TLV stream.

The only complexity comes from our desire to support
`read_tlv_field` calls that use an explicit field rather than an
`Option` of some sort, which requires some statement which can
assign both an `OptionDeserWrapper<T>` variable and a `T` variable.
We settle on `x = t.into()` and implement `From<T> for
OptionDeserWrapper<T>` which works, though it requires users to
specify types explicitly due to Rust determining expression types
prior to macro execution, completely guessing with no knowlege for
integer expressions (see
rust-lang/rust#91369).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Area: Type inference C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

2 participants