Split elided_lifetime_in_paths into finer-grained lints#120808
Split elided_lifetime_in_paths into finer-grained lints#120808shepmaster wants to merge 7 commits intorust-lang:mainfrom
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
danielhenrymantilla
left a comment
There was a problem hiding this comment.
Thanks for pushing this forward! ❤️
This comment was marked as resolved.
This comment was marked as resolved.
57a0a90 to
88dd6fc
Compare
This comment has been minimized.
This comment has been minimized.
This comment was marked as resolved.
This comment was marked as resolved.
|
r? @jieyouxu |
|
Changes to the size of AST and/or HIR nodes. cc @nnethercote |
compiler/rustc_hir/src/hir.rs
Outdated
| 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.
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.
jieyouxu
left a comment
There was a problem hiding this comment.
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_syntaxesandhidden_lifetimes_in_output_pathssituation, and whether to perform some kind of "suppression" to havemismatched_lifetime_syntaxestake precedence overhidden_lifetimes_in_output_pathsunlesshidden_lifetimes_in_output_pathshave 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.
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_pathshandled 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_pathslint group umbrella:
hidden_lifetimes_in_input_pathshidden_lifetimes_in_output_pathshidden_lifetimes_in_type_paths
| lint_hidden_lifetime_in_path = | ||
| paths containing hidden lifetime parameters are deprecated |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
| /// explicitly stated, even if it is the `'_` [placeholder | ||
| /// lifetime]. |
There was a problem hiding this comment.
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.
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.
There was a problem hiding this comment.
my intention was that we'd add a new system, but I do realize now it's not incremental friendly (which isn't an issue for errors).
| /// [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.
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.
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) |
|
The tests should include the following cases as well, with the lints enabled: This will prevent us from accidentally changing whether |
compiler/rustc_hir/src/hir.rs
Outdated
| /// Details not yet needed. Feel free to give useful | ||
| /// categorization to these usages. | ||
| Other, | ||
| } |
There was a problem hiding this comment.
Can we avoid having this enum and have the lint compute where the type appears?
There was a problem hiding this comment.
Specifically: you can look at the parent, or implement the lint on paths and look at the first segment
There was a problem hiding this comment.
I don't know how to do this to achieve the goals. Interested parties can watch as I flail about over in Zulip.
|
☔ The latest upstream changes (presumably #142962) made this pull request unmergeable. Please resolve the merge conflicts. |
|
@rustbot author |
|
These commits modify the If this was unintentional then you should revert the changes before this PR is merged. Some changes occurred in need_type_info.rs cc @lcnr HIR ty lowering was modified cc @fmease |
This comment has been minimized.
This comment has been minimized.
|
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
This comment has been minimized.
This comment has been minimized.
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.
|
@rustbot ready |
| paths containing hidden lifetime parameters are deprecated | ||
|
|
||
| lint_hidden_lifetime_in_path_suggestion = | ||
| indicate the anonymous lifetime |
There was a problem hiding this comment.
| indicate the anonymous lifetime | |
| indicate the inferred lifetime |
I'd probably say "inferred" here for a couple reasons. One, I'm planning to update the Reference to call this the inferred lifetime (as we call _ the inferred type/const). Two, the lifetime isn't necessarily anonymous. It could be inferred to be a named lifetime, though of course we lint against that separately.
| /// The `hidden_lifetimes_in_output_paths` lint detects the use | ||
| /// of hidden lifetime parameters in types occurring as a function | ||
| /// return value. |
There was a problem hiding this comment.
| /// The `hidden_lifetimes_in_output_paths` lint detects the use | |
| /// of hidden lifetime parameters in types occurring as a function | |
| /// return value. | |
| /// The `hidden_lifetimes_in_output_paths` lint detects use of | |
| /// hidden lifetime parameters in the return type of a function. |
| /// Hidden lifetime parameters can make it difficult to see at a | ||
| /// 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.
| /// Hidden lifetime parameters can make it difficult to see at a | |
| /// 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. | |
| /// Hidden lifetime parameters can make it difficult to see at a | |
| /// glance that borrowing is occurring. This is especially true | |
| /// when the return type of a function hides a lifetime. Lifetime | |
| /// elision will link the lifetime in the return type to an input | |
| /// lifetime without any indication of this in the signature. |
(This is to clean up (or avoid) some terminology around types/values and arguments/parameters.)
| /// The `hidden_lifetimes_in_type_paths` lint detects the use of | ||
| /// hidden lifetime parameters in types not part of a function's | ||
| /// arguments or return values. |
There was a problem hiding this comment.
| /// The `hidden_lifetimes_in_type_paths` lint detects the use of | |
| /// hidden lifetime parameters in types not part of a function's | |
| /// arguments or return values. | |
| /// The `hidden_lifetimes_in_type_paths` lint detects the use of | |
| /// hidden lifetime parameters in types other than those used | |
| /// within parameters or within the return type of a function. |
| lint_hidden_lifetime_in_path = | ||
| paths containing hidden lifetime parameters are deprecated |
There was a problem hiding this comment.
|
Since this thread has become long and there were multiple FCP proposals, I'll mention for @oli-obk's convenience the one we're reviewing this against is #120808 (comment). |
|
☔ The latest upstream changes (presumably #145366) made this pull request unmergeable. Please resolve the merge conflicts. |
Description
Converts the existing
elided_lifetime_in_pathslint into three smaller pieces:hidden_lifetimes_in_input_paths— fires forfn(ContainsLifetime) -> ...hidden_lifetimes_in_output_paths— fires forfn(...) -> ContainsLifetimehidden_lifetimes_in_type_paths— fires for many other usages ofContainsLifetime, such as in astaticor in a turbofishA new group
hidden_lifetimes_in_pathsis created with the three smaller lints and places that use the oldelided_lifetime_in_pathsname are updated to match.Background
In general, we want to discourage function signatures like
fn (&T) -> ContainsLifetime,fn (ContainsLifetime) -> &T, andfn (ContainsLifetime) -> ContainsLifetimeas it is not obvious that a lifetime flows through the function and back out as there is no visual indication thatContainsLifetimehas 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_pathsinto 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.