-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Irrefutable while-let pattern in log4rs-rolling-file-0.2.0, Rust 1.16 #38972
Comments
Why was this made an error in the first place? |
To save other people from digging through the crate, the situation is: #[derive(Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
} The generated code (cleaned up) looks like: impl Deserialize for Config {
fn deserialize<D>(deserializer: &mut D) -> Result<Config, D::Error>
where D: Deserializer
{
enum Field {}
impl Deserialize for Field {
/* ... */
}
struct Visitor<D: Deserializer>(PhantomData<D>);
impl<D: Deserializer> Visitor for Visitor<D> {
type Value = Config;
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<Config, V::Error>
where V: SeqVisitor
{
try!(visitor.end());
Ok(Config{})
}
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Config, V::Error>
where V: MapVisitor
{
// ERROR: irrefutable while-let pattern
while let Some(key) = try!(visitor.visit_key::<Field>()) {
match key {}
}
try!(visitor.end());
Ok(Config{})
}
}
const FIELDS: &'static [&'static str] = &[];
deserializer.deserialize_struct("Config", FIELDS, Visitor::<D>(PhantomData))
}
} This looks like the code for an ordinary braced struct except there are zero fields. So the error is because the line I filed serde-rs/serde#676 to fix this in Serde and I will leave it to you guys to debate whether this should be an error. |
Sounds like there's some debate to be had yet about the behavior here. Assigning to niko to make sure something happens. |
cc @canndrew -- @eddyb and I agree this should be a warning. It's not clear what definition of "irrefutable pattern" is being used here, presumably it is checking that the other variants are not reachable, probably so that this works: #![feature(never_type)]
fn foo(x: Result<u32, !>) {
let Ok(y) = x;
}
fn main() {
} |
I love the new behavior and plan to use it in Serde, for example here: // Before
try!(visitor.visit_key::<__Field>()).map(|impossible| match impossible {});
// After
let None::<__Field> = try!(visitor.visit_key()); But it seems like this should be consistent with how unreachable patterns in enum Void {}
fn f() -> Option<Void> { None }
fn main() {
match f() {
None => println!("none"),
// WARNING: unreachable pattern, #[warn(unreachable_patterns)] on by default
Some(_) => println!("some"),
}
// ERROR: irrefutable if-let pattern
// (previously okay)
if let None = f() {
println!("definitely none");
}
// ERROR: irrefutable if-let pattern
// (previously okay)
if let Some(_) = f() {
println!("definitely some");
}
} Also "irrefutable pattern" makes sense for |
I think the definition is correct, it's just that this should not be an error. |
at least for now =) |
Yeah, this should be fixed properly. |
Looks like #39127 did not include a test for this particular case, so I'm going to add E-needs-test. |
I am marking this issue as E-mentor and E-easy. The task is to add a test case for the The other problem is that there is no reduced form of the test. @dtolnay gave a relatively minimized example but it seems like it could be reduced further. The crux of the problem is that we have an enum #[deny(warnings)]
enum Foo { }
fn make_foo() -> Option<Foo> { None }
fn main() {
while let Some(_f) = make_foo() { }
} This should generate a warning about dead-code, ideally, but it should not generate an error. (At least, not on the current nightly: it should generate an error on the older nightly, if I did the reduction right.) So the steps to close are:
|
This seems to still be broken on latest master, actually. The exact test you provide fails with
|
@canndrew see @russellmcc's comment above; that's a bit surprising, no? |
Surprising and wrong 😕, that pattern is definitely refutable. I'll have a look into it... |
Alright, sorry for saying this should be fixed when it was, in fact, not at all fixed. It's fixed now though! |
So with your patch, we end up in a situation where: enum Foo { }
fn make_foo() -> Option<Foo> { None }
fn main() {
match make_foo() {
None => {},
Some(_) => {}, //~ WARN unreachable pattern
}
} but if you remove the arm: enum Foo { }
fn make_foo() -> Option<Foo> { None }
fn main() {
match make_foo() { //~ ERROR non-exhaustive patterns
None => {}
}
} If you want to shut it up, you have to use: enum Foo { }
fn make_foo() -> Option<Foo> { None }
fn main() {
match make_foo() {
None => {},
_ => {}
}
} |
@arielb1 Heh. That's... kind of amusing. Though to be fair to @canndrew he would have preferred the second example to work, we kind of asked him not to allow it to work just yet. I'm not unhappy with the status quo, in some sense, as long as it's temporary; but it does seem likely to be awfully confusing. I could imagine a couple of things:
I think the TL;DR is that we should discuss and settle some kind of unreachable semantics. But I'm not 100% sure I'm ready to do that yet. I guess at minimum I gotta catch up on the RFC + old conversation. |
@arielb1 Arrgh. The problem is my Hide uninhabitedness checks behind feature gate PR didn't completely hide them. The changes I made for the uninhabited patterns stuff were:
When I tried to hide this stuff I hid (2) but didn't revert (0) and (1) (I guess because they seemed like more of a fix than a major change). I can hide them aswell with a follow-up PR though if you'd like? |
We had some discussion about that yesterday. You can read the notes at |
@canndrew I think the semantics we ultimately decided that we want kind of fall somewhere in between the older behavior and the newest behavior =) |
I found another regression from 1.15 to 1.16 that involves empty enums. The following will compile on rust version 1.15: enum Void { }
fn use_void(v: &Void) -> u32 {
match v { }
}
fn main() { } But on
Does this seem like the same issue or should I ticket it separately? |
…komatsakis check_match: don't treat privately uninhabited types as uninhabited Fixes rust-lang#38972, which is a regression in 1.16 from @canndrew's patchset. r? @nikomatsakis beta-nominating because regression.
…komatsakis check_match: don't treat privately uninhabited types as uninhabited Fixes rust-lang#38972, which is a regression in 1.16 from @canndrew's patchset. r? @nikomatsakis beta-nominating because regression.
UPDATE: The underlying problem has been solved (we believe), but there is not yet a regression test in the test base. Here are some instructions for how to add a regression test.
https://github.com/sfackler/log4rs-rolling-file 1ce36b4301c86fa750134d35cb815d146c5836ee
Not on stable/beta.
This case is interesting. The loop is generated by serde and from inspection seems be a degenerate case. I can't tell if it was previously right or wrong.
cc @sfackler @erickt
The text was updated successfully, but these errors were encountered: