-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Detect when a field default is not using that field's type's default values #135859
Conversation
…values Given ```rust pub struct Foo { pub something: i32 = 2, } pub struct Bar { pub foo: Foo = Foo { something: 10 }, } ``` The value for `Bar { .. }.foo.something` is different to the value in `Foo { .. }.something`. This can cause confusion so we lint against it. We don't check that the values actually differ. At just the mere presence of the default value we suggest `..` to avoid the possibility of divergence. This is just a lint to allow for APIs where that divergence is intentional.
r? @chenyukang rustbot has assigned @chenyukang. Use |
Perhaps I'm missing something, but I don't think this needs to be linted against? I would not expect the default value of a struct field to match the default value of the type of that field. And I think this is going to be common enough that it's going to be extremely annoying if it is linted against (although I guess it's easy enough to turn off a lint globally). For example, wouldn't this lint against any |
Given #![feature(default_field_values)]
enum Option<T> {
Some(T),
None,
}
use Option::None;
struct Foo {
a: Option<()> = None,
}
struct Bar {
foo: Foo = Foo { a: None },
} you get
What the lint is asking is that you write struct Bar {
foo: Foo = Foo { .. },
} If you were to write struct Foo {
a: Option<()> = Some(()),
}
struct Bar {
foo: Foo = Foo { a: None },
} it would complain, as well as if you were to write struct Foo {
a: Option<()> = Some(()),
}
struct Bar {
foo: Foo = Foo { a: Some(()) },
} The intention of the lint is to detect that you are writing a default which is a literal for a struct that has a default field value instead of using that default. I do think that this lint is likely better as a clippy pedantic lint, but would be concerned if it wasn't warn by default, so that it could catch mistakes. Note that enums don't have a concept of "default variant", beyond the (The lint should have a structured suggestion, which it doesn't now.) |
I'm confused, if I wanted to use #[derive(Default)]
struct Foo {
a: Option<()> = Some(()),
}
#[derive(Default)]
struct Bar {
foo: Foo = Foo::default(),
} If I'm going out of my way to write an explicit default value, it's presumably intentional. Could you spell out the kind of mistake you want to catch, ideally with a realer example instead of EDIT: oops, forgot about the const restriction. |
Here's one case that this arguably would catch: #[derive(Default)]
struct Pet {
name: String,
age: i128 = 42, // impl Default for Pet will use the literal 42 for age
foo: Foo = Foo { something: 10 },
}
#[derive(Default)]
struct Foo {
something: i32 = 2,
otherthing: i32 = 4,
}
fn main() {
let my_pet = Pet {
name: "ferris".into(),
foo: Foo { otherthing = 12, .. },
};
} I can imagine the user expecting |
That is indeed the case I want to catch. I would like to hear your reasoning there because I feel like I'm missing something? In my eyes this is a warning to the API author for "you might be causing confusion to your users" instead of a warning to users for "you might be getting confused by the API". (Note that on |
This is what I'm not seeing. The author believes that value to be the default value that's most relevant for that struct, why would the global default be relevant? To me that feels like if you linted against I guess that's my main stance, I'm not sure how I can explain that more. Maybe we have wildly different usages in mind? I do see that a user writing On top of that, with your lint the only option to keep the desired behavior is to |
Hmm... I can see that this might potentially be confusing. On the other hand, I would expect the majority of the examples of this to be valid uses cases that would then need to ignore the lint. I feel like this might be something that users just need to learn. In general, it's already the case that:
|
@nicoburns you're absolutely right that this is exactly the same thing that can be done with To all, I still think having a lint doing this analysis would be useful, but I am convinced that it doesn't need to live in rustc itself and be more suitable for clippy, likely allow-by-default under the pedantic family, given all the feedback. |
Given
The value for
Bar { .. }.foo.something
is different to the value inFoo { .. }.something
. This can cause confusion so we lint against it. We don't check that the values actually differ. At just the mere presence of the default value we suggest..
to avoid the possibility of divergence. This is just a lint to allow for APIs where that divergence is intentional.