rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
95.24k stars 12.28k forks source link

Tracking issue for `resolve_trait_on_defaulted_unit` compatibility lint #39216

Open canndrew opened 7 years ago

canndrew commented 7 years ago

This is the summary issue for the resolve_trait_on_defaulted_unit future-compatibility warning and other related errors. The goal of this page is describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our breaking change policy guidelines.

What is this lint about

Ordinarily, when a user doesn't specify the type of an expression and the type cannot be inferred, rust will raise an error. For example, consider this code:

let _ = Default::default();

Because we haven't specified the type of _ the compiler doesn't know what type of value the user is asking for a default of. And so we get this error:

error[E0282]: unable to infer enough type information about `Self`
 --> example.rs:2:13
  |
2 |     let _ = Default::default();
  |             ^^^^^^^^^^^^^^^^ cannot infer type for `Self`
  |
  = note: type annotations or generic parameter binding required

error: aborting due to previous error

However, due to an unfortunate quirk in Rust's type inference algorithms it is sometimes possible to sneak situations like this past the compiler. In these cases, the unspecified type is defaulted to (). For an example of this, you can try deserializing an unspecified type with serde:

let _ = Deserialize::deserialize(foo)?;

In this case, the code will compile and will deserialize a value of type ().

This behaviour is set to change with the eventual rolling-out of feature(never_type). Where defaulting is still used types will instead default to !. In the best case, code that currently relies on unspecified types defaulting to () will stop compiling. In the worst case, code will continue to compile but may execute differently, as in the above example where a ! will be deserialised instead.

The resolve_trait_on_defaulted_unit warning is raised wherever the compiler thinks your program's behaviour may depend on the current defaulting rules.

How to fix this warning/error

Be specific about what type you're using. In the serde example above this could be done by simply adding a type annotation:

let _: () = Deserialize::deserialize(foo)?;

Current status

dtolnay commented 7 years ago

Is there any hope of treating let _ = Deserialize::deserialize(foo)? more like let _ = Default::default() and producing the same "cannot infer type" message? Inferring ! does not make any more or less sense to me than inferring ().

Has this already been discussed elsewhere? I don't see any links in your comment.

alexcrichton commented 7 years ago

FWIW futures-rs ran into this warning and I found it pretty hard to fix, I was just randomly annotating unknown types until I finally found that location in the commit.

Also out of curiosity, what PR was this introduced with?

canndrew commented 7 years ago

@dtolnay: @eddyb and @nikomatsakis have brought that idea up before and they might have an opinion on whether it's worth trying to implement.

@alexcrichton: This was added in https://github.com/rust-lang/rust/pull/39009. I guess the diagnostics will need to be improved :/

nikomatsakis commented 7 years ago

@dtolnay I believe that case of the ? expressions in particular was a bug, and should have been fixed by https://github.com/rust-lang/rust/pull/39485.

nikomatsakis commented 7 years ago

@alexcrichton hmm, yeah, that's frustrating; we're not super good at highlighting where a type annotation is needed, though we've been getting somewhat better. Maybe "closure return type" would make a good example.

canndrew commented 7 years ago

@dtolnay I believe that case of the ? expressions in particular was a bug, and should have been fixed by #39485.

True, though the general case of us having "defaulting" behavior around ()/! at all still remains.

bluss commented 7 years ago

Thanks for the extensive write-up. petgraph's test suite triggered this in:

warning: code relies on type inference rules which are likely to change
   --> src/algo/dominators.rs:260:9
    |
260 |         assert_eq!(None, doms.dominators(99).map(|_| unreachable!()));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: #[warn(resolve_trait_on_defaulted_unit)] on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #39216 <https://github.com/rust-lang/rust/issues/39216>
    = note: this error originates in a macro outside of the current crate

Solution is to use for example None::<()> to have the type explicit. We'd of course like to use None::<!> when stable.

petgraph might have the record in running into most Rust breaking changes ever.

nikomatsakis commented 7 years ago

@bluss note that i've overhauling a lot of this machinery to address regressions in https://github.com/rust-lang/rust/pull/40224 as well. I'm not sure what affect this will have on petgraph though.

Xion commented 6 years ago

I've got to this issue from a compiler message when trying some serde/serde_json workaround, and I noticed the message still says the problem will become a hard error.

Well, it is a hard error already :) I'm thinking the message should be reworded perhaps?

nikomatsakis commented 6 years ago

@Xion it is not, but we are starting to move towards making it so.

pnkfelix commented 2 years ago

Visiting for T-compiler backlog bonanza.

Blocking bug: #51125

@rustbot label: +S-tracking-impl-incomplete