-
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
Decision: semantics of the #[expect]
attribute
#115980
Comments
@rustbot labels +T-lang |
@rfcbot fcp merge I propose that we adopt option 1. |
Team member @nikomatsakis has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
@rustbot labels +F-lint_reasons |
Mind clarifying the title to reference the lint attribute, to not confuse it with |
#[expect]
attribute
It also wouldn't hurt clarifying where the two semantics differ. I think they only differ in case the lint is allowed, in which case option 2 would always cause an error on |
You already mentioned the difference, when it comes to the lint being allowed in the outer scope. The semantics also change, how inner lint levels are handled. Let's take this example: #![allow(unused)]
#[expect(unused_variables)]
fn foo() {
#[warn(unused_variables)]
let bar = "Marker is cool";
}
This is one of the examples, why I favor option 1. In this example, I would expect to get a warning for |
With option 2 your example would also error I think? Removing |
This is the difference, between the semantic models.
|
Option 2 got described as "The expectation is fulfilled if removing the #[expect] attribute would cause the warning to be emitted". Under that specification, clearly your example would error, since removing the expect attribute would not cause anything to happen, it would be a complete NOP. Maybe there's a third option that was discussed on Zulip, but to me "option 2" described above does not agree with your characterization of "suppress any warn or error lint emission in the marked scope". |
This is my intuition as well, which is why I propose and have implemented option 1. However, during the lang meeting and discussion on Zulip, I understood option 2 as stated above. With option 2 the |
No, for me this doesn't map. You described two distinct options:
Those are not the same semantics, they behave different on your example above. From what you are saying, t-lang was considering 2b during the Zulip discussion, and maybe @nikomatsakis meant 2b in the issue description, but their summary is sufficiently ambiguous that it sounds like 2a to me. |
During the meeting, I believe we discussed option 1 and option 2b. For option 2 (regardless of 2a or 2b) it was hard to find a short "one sentence" explanation of the semantics. The one in the issue description came from @tmandry. I guess it's the best to wait on a response from him which option he meant. |
@rustbot labels +I-lang-nominated |
OK, I'm having a hard time following all of this. Let me try to restate the "options" as precisely as I can. DefinitionsWhen a lint is detected at a particular program point P, there is a stack of lint scopes determined by lexical structure of the program. Each one can be warn/allow/forbid or expect. Prior to expect, we would take the innermost one to determine whether or not a diagnostic was printed. The various options then introduce expect and describe the behavior. In each case, the expect can be marked as fulfilled. If that does not happen, the expect reports an error. Stack levelThe stack level can be defined as: fn stack_level(stack: &[Level] -> Level {
let n = stack.len() - 1;
match stack[n] {
ALLOW | WARN | DENY => stack[n],
EXPECT => stack_level(&stack[0..n-1]),
}
} ExamplesHere are some examples Obvious-case #[expect(unused_variables)]
fn foo() {
let x;
} Lint stack here is just: Allowed-Outside In this example, there is a crate-wide allow, but also an #![allow(unused_variables)]
#[expect(unused_variables)]
fn foo() {
let x;
} Lint stack here is: Allowed-Inside In this example, there is a warning block inside the function that is more specific than the expect. #[expect(unused_variables)]
fn foo() {
#[allow(unused_variables)]
let x;
} Lint stack here is: Warn-Inside In this example, there is a warning block inside the function that is more specific than the expect. #[expect(unused_variables)]
fn foo() {
#[warn(unused_variables)]
let x;
} Lint stack here is: OptionsOption 1: "expect must supress a lint from inside its scope" If EXPECT is at the top of the stack, mark the EXPECT as fulfilled, and suppress the lint. Option 2a: "removing the expect would cause something to be printed" If EXPECT is at the top of the stack at position N, consider Option 2b: "expectation is fulfilled if a warning is emitted inside the scope of the attribute (and then that warning is suppressed)" If TableKey (multiple options are allowed):
(NOTE: table corrected from its original form, see comments below) |
Yes that makes sense, thanks. I think the semantics I expected from expect before delving into this discussion are option 1. Option 2b means many EXPECT can become fulfilled by a single lint being emitted. That seems very non-intuitive to me. But I also didn't really consider nesting |
Thank you for the table @nikomatsakis, I think this is an excellent way to showcase the differences. However, with my understanding of 2b would make the row slightly different:
From these options, I favor option 1. It also seems like this model is easier to grasp and explain than option 2*. Footnotes
|
@xFrednet Yes. I think you are correct, I made some mistakes. Here is how I defined Option 2b (annotated):
On this basis, I agree with your results for Option 2b. Allowed-Outside and Allowed-Inside ❌, because part a ( |
Reviewing the comments here, I agree that Option 1 is the most reasonable overall. There is a use case I had in mind that essentially does want to act more like a try/catch, which would be overriding a warn attribute on some inner code you don't control (like a macro expansion). But that doesn't seem to come up in practice, and if it did it would best be serviced with a different attribute (or compiler flag). @rfcbot reviewed |
Has anyone discussed what the behavior with renamed and removed lints will be? One fairly straightforward possibility is to 🟡 renamed_and_removed_lints and turn it into a |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Thanks, the Allowed-Outside example is very helpful. Compositionally I agree that being in an allow context like that shouldn't make things "stop working", so option 1 sounds good. @rfcbot reviewed |
@rustbot labels -I-lang-nominated This is now in FCP, so we can unnominate this. |
Turning it into a wildcard #![feature(lint_reasons)]
#[expect(
unused_mut,
// ^^^^^^^^^^
// This creates an expectation which is fulfilled.
// Nothing is emitted for this one.
duck_and_such,
// ^^^^^^^^^^^^^
// This is an unknown lint for Rust 1.77. The
// `unknown_lints` lint is emitted, but no expectation
// is created.
unused_variables,
// ^^^^^^^^^^^^^^^^
// This creates an expectation that is unfulfilled, since
// all variables are used. Therefore, `unfulfilled_lint_expectations`
// is emitted for this lint.
)]
fn main() {
let mut x = 10;
println!("{x}");
} Edit: Just noticed that I misread |
To clarify, the behavior for renamed lints is that the old lint name still works as-if you used the new lint name, plus it will fire Removed lints will fire |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
…u,blyxyas Let's `#[expect]` some lints: Stabilize `lint_reasons` (RFC 2383) Let's give this another try! The [previous stabilization attempt](rust-lang/rust#99063) was stalled by some unresolved questions. These have been discussed in a [lang team](rust-lang/lang-team#191) meeting. The last open question, regarding the semantics of the `#[expect]` attribute was decided on in rust-lang/rust#115980 I've just updated the [stabilization report](rust-lang/rust#54503 (comment)) with the discussed questions and decisions. Luckily, the decision is inline with the current implementation. This hopefully covers everything. Let's hope that the CI will be green like the spring. fixes #115980 fixes #54503 --- r? `@wesleywiser` Tacking Issue: rust-lang/rust#54503 Stabilization Report: rust-lang/rust#54503 (comment) Documentation Update: rust-lang/reference#1237 <!-- For Clippy: changelog: [`allow_attributes`]: Is now available on stable, since the `lint_reasons` feature was stabilized changelog: [`allow_attributes_without_reason`]: Is now available on stable, since the `lint_reasons` feature was stabilized --> --- Roses are red, Violets are blue, Let's expect lints, With reason clues
…u,blyxyas Let's `#[expect]` some lints: Stabilize `lint_reasons` (RFC 2383) Let's give this another try! The [previous stabilization attempt](rust-lang/rust#99063) was stalled by some unresolved questions. These have been discussed in a [lang team](rust-lang/lang-team#191) meeting. The last open question, regarding the semantics of the `#[expect]` attribute was decided on in rust-lang/rust#115980 I've just updated the [stabilization report](rust-lang/rust#54503 (comment)) with the discussed questions and decisions. Luckily, the decision is inline with the current implementation. This hopefully covers everything. Let's hope that the CI will be green like the spring. fixes #115980 fixes #54503 --- r? `@wesleywiser` Tacking Issue: rust-lang/rust#54503 Stabilization Report: rust-lang/rust#54503 (comment) Documentation Update: rust-lang/reference#1237 <!-- For Clippy: changelog: [`allow_attributes`]: Is now available on stable, since the `lint_reasons` feature was stabilized changelog: [`allow_attributes_without_reason`]: Is now available on stable, since the `lint_reasons` feature was stabilized --> --- Roses are red, Violets are blue, Let's expect lints, With reason clues
…u,blyxyas Let's `#[expect]` some lints: Stabilize `lint_reasons` (RFC 2383) Let's give this another try! The [previous stabilization attempt](rust-lang/rust#99063) was stalled by some unresolved questions. These have been discussed in a [lang team](rust-lang/lang-team#191) meeting. The last open question, regarding the semantics of the `#[expect]` attribute was decided on in rust-lang/rust#115980 I've just updated the [stabilization report](rust-lang/rust#54503 (comment)) with the discussed questions and decisions. Luckily, the decision is inline with the current implementation. This hopefully covers everything. Let's hope that the CI will be green like the spring. fixes #115980 fixes #54503 --- r? `@wesleywiser` Tacking Issue: rust-lang/rust#54503 Stabilization Report: rust-lang/rust#54503 (comment) Documentation Update: rust-lang/reference#1237 <!-- For Clippy: changelog: [`allow_attributes`]: Is now available on stable, since the `lint_reasons` feature was stabilized changelog: [`allow_attributes_without_reason`]: Is now available on stable, since the `lint_reasons` feature was stabilized --> --- Roses are red, Violets are blue, Let's expect lints, With reason clues
…u,blyxyas Let's `#[expect]` some lints: Stabilize `lint_reasons` (RFC 2383) Let's give this another try! The [previous stabilization attempt](rust-lang/rust#99063) was stalled by some unresolved questions. These have been discussed in a [lang team](rust-lang/lang-team#191) meeting. The last open question, regarding the semantics of the `#[expect]` attribute was decided on in rust-lang/rust#115980 I've just updated the [stabilization report](rust-lang/rust#54503 (comment)) with the discussed questions and decisions. Luckily, the decision is inline with the current implementation. This hopefully covers everything. Let's hope that the CI will be green like the spring. fixes #115980 fixes #54503 --- r? `@wesleywiser` Tacking Issue: rust-lang/rust#54503 Stabilization Report: rust-lang/rust#54503 (comment) Documentation Update: rust-lang/reference#1237 <!-- For Clippy: changelog: [`allow_attributes`]: Is now available on stable, since the `lint_reasons` feature was stabilized changelog: [`allow_attributes_without_reason`]: Is now available on stable, since the `lint_reasons` feature was stabilized --> --- Roses are red, Violets are blue, Let's expect lints, With reason clues
This issue is spun out from #54503 to serve as the decision issue for a specific question. The question is what the 'mental model' for the
expect
attribute should be. Two proposed options:#[expect]
attribute would cause the warning to be emitted. (src)@xFrednet created a list of use cases to help with the discussion of these two models; they found both models work equally well, except for use case 4 which would only be possible with the first model.
The text was updated successfully, but these errors were encountered: