-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Split elided_lifetime_in_paths into finer-grained lints #120808
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
base: master
Are you sure you want to change the base?
Split elided_lifetime_in_paths into finer-grained lints #120808
Conversation
This comment has been minimized.
This comment has been minimized.
As I've now tried to add this test twice and to help prevent trying to add it again... this fails because elision can't take place: fn top_level_nested_to_top_level_nested(v: &ContainsLifetime) -> &ContainsLifetime { v }
|
eaf0446
to
8f5390c
Compare
This comment has been minimized.
This comment has been minimized.
8f5390c
to
f1f5c32
Compare
f1f5c32
to
cc85718
Compare
This generally looks fine. I had a few questions about what we expect to happen in a corner case.
@rustbot label: +S-waiting-on-author -S-waiting-on-review |
Oh, I suppose there is still an open question about the use of the "tied"/"untied" terminology, which I admit threw me for a loop at first. I'm not sure which group is the best to handle resolving that question, though. And I'm also not entirely sure that resolving that question should block landing this work. Is resolving a question like that a matter for WG-diagnostics, or for T-lang? |
That's a great question that I don't have an answer for. I posed it in the Zulip thread hoping there was some existing terminology. Unfortunately, no one seemed aware of one. "Tied" made some intuitive sense for the small handful of people I asked one-on-one. It feels like this is something that we must have talked about before and potentially even documented somewhere, but 🤷 |
f6d8513
to
da16b9b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pushing this forward! ❤️
This comment was marked as resolved.
This comment was marked as resolved.
57a0a90
to
88dd6fc
Compare
… r=traviscross,jieyouxu Add a new `mismatched-lifetime-syntaxes` lint The lang-team [discussed this](https://hackmd.io/nf4ZUYd7Rp6rq-1svJZSaQ) and I attempted to [summarize](rust-lang/rust#120808 (comment)) their decision. The summary-of-the-summary is: - Using two different kinds of syntax for elided lifetimes is confusing. In rare cases, it may even [lead to unsound code](rust-lang/rust#48686)! Some examples: ```rust // Lint will warn about these fn(v: ContainsLifetime) -> ContainsLifetime<'_>; fn(&'static u8) -> &u8; ``` - Matching up references with no lifetime syntax, references with anonymous lifetime syntax, and paths with anonymous lifetime syntax is an exception to the simplest possible rule: ```rust // Lint will not warn about these fn(&u8) -> &'_ u8; fn(&'_ u8) -> &u8; fn(&u8) -> ContainsLifetime<'_>; ``` - Having a lint for consistent syntax of elided lifetimes will make the [future goal](rust-lang/rust#91639) of warning-by-default for paths participating in elision much simpler. --- This new lint attempts to accomplish the goal of enforcing consistent syntax. In the process, it supersedes and replaces the existing `elided-named-lifetimes` lint, which means it starts out life as warn-by-default.
1304850
to
4a41f53
Compare
This comment has been minimized.
This comment has been minimized.
4a41f53
to
22cfbc6
Compare
… r=traviscross,jieyouxu Add a new `mismatched-lifetime-syntaxes` lint The lang-team [discussed this](https://hackmd.io/nf4ZUYd7Rp6rq-1svJZSaQ) and I attempted to [summarize](rust-lang/rust#120808 (comment)) their decision. The summary-of-the-summary is: - Using two different kinds of syntax for elided lifetimes is confusing. In rare cases, it may even [lead to unsound code](rust-lang/rust#48686)! Some examples: ```rust // Lint will warn about these fn(v: ContainsLifetime) -> ContainsLifetime<'_>; fn(&'static u8) -> &u8; ``` - Matching up references with no lifetime syntax, references with anonymous lifetime syntax, and paths with anonymous lifetime syntax is an exception to the simplest possible rule: ```rust // Lint will not warn about these fn(&u8) -> &'_ u8; fn(&'_ u8) -> &u8; fn(&u8) -> ContainsLifetime<'_>; ``` - Having a lint for consistent syntax of elided lifetimes will make the [future goal](rust-lang/rust#91639) of warning-by-default for paths participating in elision much simpler. --- This new lint attempts to accomplish the goal of enforcing consistent syntax. In the process, it supersedes and replaces the existing `elided-named-lifetimes` lint, which means it starts out life as warn-by-default.
… r=traviscross,jieyouxu Add a new `mismatched-lifetime-syntaxes` lint The lang-team [discussed this](https://hackmd.io/nf4ZUYd7Rp6rq-1svJZSaQ) and I attempted to [summarize](rust-lang/rust#120808 (comment)) their decision. The summary-of-the-summary is: - Using two different kinds of syntax for elided lifetimes is confusing. In rare cases, it may even [lead to unsound code](rust-lang/rust#48686)! Some examples: ```rust // Lint will warn about these fn(v: ContainsLifetime) -> ContainsLifetime<'_>; fn(&'static u8) -> &u8; ``` - Matching up references with no lifetime syntax, references with anonymous lifetime syntax, and paths with anonymous lifetime syntax is an exception to the simplest possible rule: ```rust // Lint will not warn about these fn(&u8) -> &'_ u8; fn(&'_ u8) -> &u8; fn(&u8) -> ContainsLifetime<'_>; ``` - Having a lint for consistent syntax of elided lifetimes will make the [future goal](rust-lang/rust#91639) of warning-by-default for paths participating in elision much simpler. --- This new lint attempts to accomplish the goal of enforcing consistent syntax. In the process, it supersedes and replaces the existing `elided-named-lifetimes` lint, which means it starts out life as warn-by-default.
… r=traviscross,jieyouxu Add a new `mismatched-lifetime-syntaxes` lint The lang-team [discussed this](https://hackmd.io/nf4ZUYd7Rp6rq-1svJZSaQ) and I attempted to [summarize](rust-lang/rust#120808 (comment)) their decision. The summary-of-the-summary is: - Using two different kinds of syntax for elided lifetimes is confusing. In rare cases, it may even [lead to unsound code](rust-lang/rust#48686)! Some examples: ```rust // Lint will warn about these fn(v: ContainsLifetime) -> ContainsLifetime<'_>; fn(&'static u8) -> &u8; ``` - Matching up references with no lifetime syntax, references with anonymous lifetime syntax, and paths with anonymous lifetime syntax is an exception to the simplest possible rule: ```rust // Lint will not warn about these fn(&u8) -> &'_ u8; fn(&'_ u8) -> &u8; fn(&u8) -> ContainsLifetime<'_>; ``` - Having a lint for consistent syntax of elided lifetimes will make the [future goal](rust-lang/rust#91639) of warning-by-default for paths participating in elision much simpler. --- This new lint attempts to accomplish the goal of enforcing consistent syntax. In the process, it supersedes and replaces the existing `elided-named-lifetimes` lint, which means it starts out life as warn-by-default.
This comment was marked as resolved.
This comment was marked as resolved.
Removing the `issue-91763` test as the implementation is completely different now. Bootstrap forces `rust_2018_idioms` to the warning level in the rustc_lint doctests using `-Zcrate-attr`. This overrides the doctest's crate-level `deny` attributes, so I've changed those to be statement-level attributes.
22cfbc6
to
b0e622e
Compare
r? @jieyouxu |
Changes to the size of AST and/or HIR nodes. cc @nnethercote |
@@ -4996,7 +5012,7 @@ mod size_asserts { | |||
static_assert_size!(StmtKind<'_>, 16); | |||
static_assert_size!(TraitItem<'_>, 88); | |||
static_assert_size!(TraitItemKind<'_>, 48); | |||
static_assert_size!(Ty<'_>, 48); | |||
static_assert_size!(Ty<'_>, 56); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is unfortunate. Ty
is a very common type, an extra 8 bytes just to fit a boolean?
This comment was marked as outdated.
This comment was marked as outdated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! The broad implementation looks good to me modulo some nits, however I have two implementation specifics that I'm not very sure about.
Here's my initial review pass, but I would like to ask for a second opinion from @oli-obk (or @nnethercote) regarding two questions:
- The "overlapping"
mismatched_lifetime_syntaxes
andhidden_lifetimes_in_output_paths
situation, and whether to perform some kind of "suppression" to havemismatched_lifetime_syntaxes
take precedence overhidden_lifetimes_in_output_paths
unlesshidden_lifetimes_in_output_paths
have a stronger lint level. And if that is desired, the more important question is how, since these two lints run in their own lint passes. AFAICT, it doesn't seem easy to stash both lint diagnostics and their respective effective lint levels, then perform some kind of post-diagnostics-construction precedence filter that accounts for the relative lint levels between the two lints. - I'm also not very sure about the increase in size of
Ty<'_>
, since this is a very commonly used type, as @nnethercote pointed out in an earlier review comment. It seems like tracking source of the type is desirable, but I'm not too sure about an alternative scheme that doesn't involve increasing size ofTy<'_>
.
I'm going to hand this review off to oli for a second opinion.
// signatures, but they can also appear in other places! The original | ||
// version of this lint handled all these cases in one location, but | ||
// it's desired that the one lint actually be multiple. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit (wording): maybe for clarity (I was reading this, and it wasn't immediately clear)
Most of the time, we focus on elided lifetimes in function signatures, but they can also appear in other places! The original lint
elided_lifetime_in_paths
handled all these cases in one location, but it's more desirable to split it into 3 more fine-grained lints under a newhidden_lifetimes_in_paths
lint group umbrella:
hidden_lifetimes_in_input_paths
hidden_lifetimes_in_output_paths
hidden_lifetimes_in_type_paths
lint_hidden_lifetime_in_path = | ||
paths containing hidden lifetime parameters are deprecated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion [WORDING-STRENGTH 1/2]: I think I agree with @tmandry's comment earlier
hidden lifetime parameters in types are deprecated
I also think we should remove this wording at least until we upgrade some lint to warn-by-default.
where if this set of 3 lints are initially allow-by-default in this PR, we should not use "deprecated" in this PR, but instead add "deprecated" in the follow-up PR that bumps these three lints and the hidden_lifetimes_in_paths
to warn-by-default, so that the deprecation is part of the follow-up decision to explicitly deprecate this form.
In this PR, I would reword this less strong initially, maybe something like
paths containing hidden lifetime parameters can be confusing
/// explicitly stated, even if it is the `'_` [placeholder | ||
/// lifetime]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit (wording): To make it easier to search for '_
, maybe
This lint ensures that lifetime parameters are always explicitly stated, even if it is the placeholder lifetime
'_
.
Actually hm, this is more so trying to express
This lint ensures that lifetime parameters are explicit in types occuring as function arguments. Where lifetime elision may occur, the placeholder lifetime
'_
may be used to make the presence of lifetime constraints explicit.
/// glance that borrowing is occurring. This is especially true | ||
/// when a type is used as a function's return value: lifetime | ||
/// elision will link the return value's lifetime to an argument's | ||
/// lifetime, but no syntax in the function signature indicates | ||
/// that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion: right, I see what you meant by having both mismatched_lifetime_syntaxes
and hidden_lifetimes_in_output_paths
firing against the same return position type-with-hidden-lifetime.
For reference, the discussion about what a reasonable scheme is to suppress the lower-lint-level of the two lints, or have mismatched_lifetime_syntaxes
"shadow" hidden_lifetimes_in_output_paths
when both are at the same lint level is at #t-compiler/diagnostics > Avoiding emitting one lint if another has been emitted.
@oli-obk suggested in that thread something among the lines of
Since we already have stashed errors we could have lint marking where we can explicitly mark spans as having linted and other lints can check if spans have been linted
Tho I'm not sure how to cleanly massage e.g. the stashed diagnostics mechanism and StashKey
to indicate how to resolve if both lints are to be emitted (since they'd be ran in separate lint passes). I'll hand the review over to oli for this part.
/// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions | ||
pub HIDDEN_LIFETIMES_IN_TYPE_PATHS, | ||
Allow, | ||
"hidden lifetime parameters in types outside function signatures are discouraged" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion [WORDING-STRENGTH 2/2]: same here, maybe lessen the "strength" conveyed in this initial PR adding this lint as allow-by-default, and defer the lint level bump + wording strengthening (to "deprecate" and "discourage") in the follow-up upgrade-to-warn-by-default PR. I.e. maybe
hidden lifetime parameters in types outside function signatures can be confusing
But I don't feel too strongly about this.
#[deny(hidden_lifetimes_in_paths)] | ||
mod w { | ||
fn test2(_: super::Foo) {} | ||
//~^ ERROR paths containing hidden lifetime parameters are deprecated | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: can you add a little more elaboration on what this test intends to exercise? Is it to check that we recurse into items with mods, and/or the lint level can be properly controlled through lint level attributes?
r? @oli-obk (for a second opinion, unless you're busy) |
Description
Converts the existing
elided_lifetime_in_paths
lint into three smaller pieces:hidden_lifetimes_in_input_paths
— fires forfn(ContainsLifetime) -> ...
hidden_lifetimes_in_output_paths
— fires forfn(...) -> ContainsLifetime
hidden_lifetimes_in_type_paths
— fires for many other usages ofContainsLifetime
, such as in astatic
or in a turbofishA new group
hidden_lifetimes_in_paths
is created with the three smaller lints and places that use the oldelided_lifetime_in_paths
name are updated to match.Background
In general, we want to discourage function signatures like
fn (&T) -> ContainsLifetime
,fn (ContainsLifetime) -> &T
, andfn (ContainsLifetime) -> ContainsLifetime
as it is not obvious that a lifetime flows through the function and back out as there is no visual indication thatContainsLifetime
has a lifetime generic (such types are not usually literally called "contains lifetime" 😃).In #120808 (comment) (and multiple followup comments, e.g. #120808 (comment)), the lang team decided on a plan where we introduce a new warn-by-default lint
mismatched_lifetime_syntaxes
(supersedingelided_named_lifetimes
) which helps insure consistency between input and output lifetime syntaxes and then splitelided_lifetime_in_paths
into three parts. The combination of these lints should be enough to accomplish the original goal.History
Note that this PR has substantially changed from its original version. Check the (copious) comments below as well as the edit history of this message.