In-band lifetimes: Lint against single-use lifetime names
Once support for '_ lands in https://github.com/rust-lang/rust/pull/44691, the next step for https://github.com/rust-lang/rust/issues/44524 is to implement a lint that warns against "single use" lifetime names.
Current status
The lint is partially implemented but needs to be completed. Here is a checklist:
- [x] Issue warnings at the right times; this gist provides a comprehensive test case.
- "Warning: never used at all" falls under
unused_lifetimes
- "Warning: never used at all" falls under
- [x] For each warning, issue a suggested fix:
- For a single-use lifetime
'aappearing in&'a T, suggest&T - For a single-use lifetime
'aappearing in any other place, suggest'_ - One challenge: the binder must be removed too
- cc @estebank -- is it possible to give suggested fixes that make changes to multiple spots at once? I guess that might just be multiple suggestions?
- For a single-use lifetime
- [] We'll know this is really done when we can enable by default in rustc crates and apply rustfix with suggestions
Older Background
The idea is that an explicit name like 'a should only be used (at least in a function or impl) to link together two things. Otherwise, you should just use '_ to indicate that the lifetime is not linked to anything.
Until https://github.com/rust-lang/rust/issues/15872 is closed, we should only lint for single-use lifetime names that are bound in functions. Once #15872 is closed, we can also lint against those found in impl headers.
We can detect cases where a lint is valid by modifying the resolve_lifetimes code:
- This code basically walks over the HIR and resolves all lifetime names.
- It maintains a stack of scopes indicating what names are valid.
- The function
with()is used to push new scopes on the stack. It is also given a closure which will execute with the new name bindings in scope.with()gets called for impls and other kinds of items from here; for methods and functions in particular it is called fromvisit_early_late).
- Once a name is in scope,
resolve_lifetime_ref()is called to resolve an actual reference to a named lifetime.- This could be used, for example, to update some information in the
Scope, e.g. counting how many times a particular lifetime was referenced.
- This could be used, for example, to update some information in the
- Then, before
with()returns, we could scan the lifetimes and check for those that were only referenced 1 time (or 0 times...) and issue a lint warning.
(There are some directions for how to add a lint under the header "Issuing future compatibility warnings" in the rustc-bug-fix-procedure page on forge -- we can skip the "future compatibility" parts here.)
we should only lint for single-use lifetime names that are bound in functions
Also, I believe, only for lifetime names that appear in argument position. Currently we require explicitly binding output-only lifetimes with a name:
fn bar<'a>() -> &'a u8 { &5 } // OK fn bar() -> &'_ u8 { &5 } // ERROR: missing lifetime specifierTaylor Cramer at 2017-09-22 00:28:00
@cramertj Hmm. I would consider the proper way to declare
bar()to probably befn bar() -> &'static u8, really, though there are subtleties involved in rare cases (e.g., around invariance).Niko Matsakis at 2017-09-22 15:01:28
@nikomatsakis Yes,
'staticis the right thing to use. I wanted to point out that we shouldn't recommend'_here, as it won't work.Taylor Cramer at 2017-09-22 16:09:29
Is this up for grabs?
Gauri Kholkar at 2017-09-30 18:41:48
@gaurikholkar Go for it!
Taylor Cramer at 2017-10-03 01:01:12
Will start working on it
Gauri Kholkar at 2017-10-03 13:03:19
@gaurikholkar hey, just checking in! How's it going? Any blockers?
Niko Matsakis at 2017-10-16 13:49:46
Some examples:
fn foo<'x>(_: &'x u32) { }This should lint against
'xand suggest&u32instead.struct Foo<'a> { x: &'a u32 } fn foo<'x>(_: Foo<'x>) { }This should lint against
'xand suggestFoo<'_>instead.struct Foo<'a, 'b> { f: &'a &'b u32 } fn foo<'x, 'y>(foo: Foo<'x, 'y>) -> &'x u32 { foo.f }This should lint against
'yand suggestFoo<'x, '_>instead.struct Foo<'a, 'b> { f: &'a &'b u32 } fn foo<'x, 'y>(foo: Foo<'x, 'y>) -> &'y u32 { foo.f }This should lint against
'xand suggestFoo<'_, 'y>instead.fn foo<'x>() -> &'x u32 { &22 }This should not lint, because
'xappears only in the return type.trait Trait<'a> { } impl<'a, T> Trait<'a> for T { } fn foo<'x, T>(t: T) where T: Trait<'x> { } fn main() { foo(22); }This should not lint, because at present
'_does not work in that position (which we should fix).Niko Matsakis at 2017-10-31 19:47:50
OK, let's start with this specific test:
fn deref<'x>(v: &'x u32) -> u32 { *v } fn main() { }When we are done, we want to issue a warning, probably like this:
fn deref<'x>(v: &'x u32) -> u32 { // ^^ lifetime name `'x` only used once *v } fn main() { }In this case, the one use of
'xis as the operand to a&-type, so I think we don't have to say much more than that. If the one use of'xwere in a struct, we might want to have a hint indicating that it can be replaced with'_, but let's leave that stuff to future work.The first thing we want to do then is to figure out how many times each name is used and where. Now, accounting around lifetimes (e.g., early-bound, late-bound, etc) can get kind of complicated, but luckily we can ignore most of that crap for our purposes. I imagine we would want to add to the
LifetimeContextstruct a new field:lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>where a
LifetimeUseSet<'tcx>is defined like:enum LifetimeUseSet<'tcx> { One(&'tcx hir::Lifetime), Many, }We don't really need to track more detail than that -- once there are many uses of a lifetime, we don't want to warn about it anymore, so we don't need to track them. Now, when we are resolving a lifetime in
resolve_lifetime_ref, we want to update these lifetime use sets. Actually, I think the place to add code is theinsert_lifetimemethod, which records a successful lifetime resolution:https://github.com/rust-lang/rust/blob/3cf28f3002470f61a471c69b869e4f55ae1766f7/src/librustc/middle/resolve_lifetime.rs#L1516-L1518
Here, we want to match on the
def, which is of the typeRegion. We want to do something like:match def { LateBoundAnon(..) | Static => { // These are anonymous lifetimes or lifetimes that are not declared. } Free(_, def_id) | LateBound(_, def_id) | EarlyBound(_, def_id) => { // A lifetime declared by the user. if !self.lifetime_uses.contains_key(&def_id) { self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); } else { self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); } } }Now we have a record of where each lifetime def was used. The next step will be going over the set of lifetime names defined and warning if they are
LifetimeUseSet::One. I'm going to stop here, but we can talk about the best way to do that later.Niko Matsakis at 2017-11-11 19:20:40
I've been in touch with @nikomatsakis over this. The current status is: I've followed the instructions he has given above and written code for the same locally.
Gauri Kholkar at 2017-11-13 14:11:58
So, if we follow the steps above, we wind up with a map from the def-id of each
LifetimeDefto either zero (no key), one, or many uses of it. I think maybe the easiest thing way to handle things is to do a second walk of the krate, just looking for lifetime defs, and issuing the warnings. Originally I had thought we could do them as we walk the first time, but now that seems like it would just clutter the code unnecessary.This is the main function for
resolve_lifetime:https://github.com/rust-lang/rust/blob/master/src/librustc/middle/resolve_lifetime.rs#L259-L285
I am imagining that we can basically write a second visitor,
struct LifetimeSingleUseWarnVisitoror something. LikeLintContext, it will implement the visitor trait and returnAllfor itsnested_visitor_map:https://github.com/rust-lang/rust/blob/master/src/librustc/middle/resolve_lifetime.rs#L287-L290
It would only implement one method, though,
visit_lifetime_def:fn visit_lifetime_def(&mut self, lifetime_def: &hir::LifetimeDef) { let def_id = self.tcx.hir.as_local_def_id(lifetime_def.id); ... }In there, it will check if the map contains
def_id. If not, it can issue a warning "lifetime never used". If so, and it containsOne, it will issue a warning "lifetime used only once". Otherwise, no warning. (Issuing a warning is done by callingadd_lint, you can grep around for example.)OK, this is a not quite right -- we're going to eventually want to be a bit more selective, since it will depend whether that use is one that could be elided or replaced with
'_. But let's start there and then narrow it down.Niko Matsakis at 2017-11-13 19:38:39
Actually I take that back. Don't use a visitor. Just iterate over the map we built and look things up in the HIR map. For example, given the
DefIdof some lifetime def, we can look up its span in the HIR map by doinglet node_id = hir.as_local_node_id(def_id).unwrap(); // guarnateed to be local let hir_lifetime: &hir::Lifetime = match hir.get(node_id) { hir_map::NodeLifetime(l) => l, _ => bug!() }; let span = hir_lifetime.span;Niko Matsakis at 2017-11-13 20:26:51
Well, that won't allow you to catch lifetimes used zero times. To do that, we either need a separate visitor, or visit the map during
withand store a "zero times" entry (extending the enum), or to visit the entries at the end ofwithand issue warnings.Niko Matsakis at 2017-11-13 20:29:44
Track the progress here
Gauri Kholkar at 2017-11-23 20:03:36
| 3 | fn deref<'x>(v: &'x u32) -> u32 { | ^^ | note: lint level defined here --> /home/user/mp/foo.rs:1:9 | 1 | #![warn(single_use_lifetime)] | ^^^^^^^^^^^^^^^^^^^Is what gets generated for now
Gauri Kholkar at 2017-11-25 10:55:36
@nikomatsakis it's compile-fail tests that are failing now
Gauri Kholkar at 2017-12-08 16:08:41
I started trying to record all places where this lint might be needed and document their expected behavior. This is not done, but I have to go, so I'm saving my status here for now. My goal is to make a checklist and try to mentor the remaining improvements.
File can be found in this gist.
Niko Matsakis at 2018-03-13 22:14:40
Here is an updated check-list of the overall goals:
moved to issue header
Niko Matsakis at 2018-03-14 19:29:41
Well, that won't allow you to catch lifetimes used zero times
This isn't implemented either
Gauri Kholkar at 2018-03-14 19:32:57
Ah, good point. I was wondering if we might want to actually handle the "multiple edits" this way -- that is, we could first suggest removing the
'afrom&'a u32, then suggest removing an unused lifetime.Niko Matsakis at 2018-03-14 19:36:36
Kind of annoying to have to run
rustfixto a fixed point though =)Niko Matsakis at 2018-03-14 19:36:45
@gaurikholkar I updated the list of warnings
Niko Matsakis at 2018-03-14 19:38:16
is it possible to give suggested fixes that make changes to multiple spots at once? I guess that might just be multiple suggestions?
The suggestions machinery is capable of having multiple suggestions at one time, and each suggestions being different
Spans, but there's no method access these features, which means it hasn't been thoroughly tested.
EDIT
The support to suggest multiple substitutions at once was added in #50943, and a slight tweak to the presentation will be added in #50987.
Esteban Kuber at 2018-03-14 20:24:36
Issuing warnings at the right times
This is the first step for the mentoring instructions. The lint as is is partially implemented, but it often fires at the wrong times.
Step one: Add the tests. I've created a fairly comprehensive set of test cases in this gist. The first step then would be to add these tests into your branch, by doing something like the following. This will put all of the tests into
src/test/ui/in-band-lifetimes/single-use-lint.> cd src/test/ui/in-band-lifetimes > mkdir single-use-lint > git clone git@gist.github.com:f13da812c97b8094a9566ca9b3d9677d.git tmp > mv tmp/*rs single-use-lint > rm -rf tmp(Unfortunately, I forgot when making those tests that we already had a fair number of tests with names like
src/test/ui/in-band-lifetimes/single_use_lifetimes-*rs. You might just want to remove those tests, or else compare them to the new ones.)We can then run all the tests by running this command from the main directory:
> ./x.py test --stage 1 -i src/test/ui --test-args single-use-lintThat should run just the new tests and nothing else. You should see various failures. (You can learn more about rustc's test suite here, in the rustc-guide; these test are ui tests.)
Step two: Examine existing code. The way that the current lint works is in the
resolve_lifetimepass. Basically, for each lifetime that is declared, we track aLifetimeUseSetindicating how many times it is used:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L61-L66
These are kept in a map, indexed by the
DefIdfrom the lifetime definition:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L258
This map is populated in the
insert_lifetimeroutine, which is what we invoke when we have resolved some reference to a lifetime. So e.g. if you have a type&'a u32, this method has the job of recording which lifetime that'arefers to:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L2201
Towards the bottom you will see this code, which upgrades the number of times that the reference is used:
https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L2228-L2233
Examine the test failures. Looking at the test failures, we can group them into two categories:
- Lifetimes that appear in some places should not be warned about, even if they are only used once. For example, using a lifetime name in a struct, or in a return type.
- Lifetimes that are never used are not warned.
Making lifetimes used in particular places issue a warning. I think what we want to do here is to extend the
LifetimeContextstruct with a new field:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L228
Let's call the flag
track_individual_lifetime_uses: bool. The idea is that, when this flag is false,insert_lifetimeis not going to track whether a lifetime is used once or many times: if it finds any use, it will treat it as though it is used many times. So we might modify theinsert_lifetimecode as follows:if self.track_individual_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); } else { self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); }The basic idea is that this field should be
truewhenever a single-use lifetime could be replaced with'_. This is actually not true most of the time, so we can initialize the field tofalse. We can then modify thewithfunction, which is the function that adds a new lifetime scope, to update the field:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L1247-L1249
withshould take a new argument (track_lifetime_uses: bool); it should save the old value of the flag, modify it, and then restore it before returning.Usually, we will want to pass
falseas the value of this flag, but there are some exceptions. For example, when checking fn arguments:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L1627-L1637
and function bodies:
https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L451-L466
Anyway, that should be the rough idea. We'll have to see if it starts to issue warnings at strange times!
Making lifetimes that are never used issue a warning. Warnings are actually issued in this loop:
https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L1273-L1299
The problem here is that, if a lifetime is never used, it will never be added to the map, so we never see it to issue a warning! To fix that, we have to keep a separate set of all lifetimes and iterate over that set. Otherwise, we could walk the IR one more time with a separate visitor to find each lifetime definition.
Niko Matsakis at 2018-03-21 14:28:51
@nikomatsakis thanks for the detailed instructions!
The approach you outline doesn't totally work out, I think. Consider two-uses-in-fn-argument-and-return - we want to permit the lifetime here because it has two uses, but we want to pass
falsewhen callingself.withon the output (because lifetimes on the output alone are permitted).I think we need to always populate
self. lifetime_usesbut only check it whentrack_lifetime_usesistrue. What do you think?Other than that, to do the last part (finding lifetimes with zero uses): where would you populate the set of lifetimes?
Tamir Duberstein at 2018-04-08 01:12:41
Also, a few of the tests are incoherent:
- one-use-in-inherent-method-argument: the comment says "DO NOT warn" and the test is missing the "run-pass" annotation, but various expected errors are included.
- one-use-in-inherent-method-return: same.
- one-use-in-trait-method-argument: same (does have run-pass, though).
- two-uses-in-inherent-method-argument-and-return: same (does have run-pass, though).
Tamir Duberstein at 2018-04-08 01:42:38
@tamird
Sorry I missed those comments!
Regarding the incoherent tests:
- one-use-in-inherent-method-argument: I believe the comment is wrong. We should warn now, as you could write
impl Foo<'_>. - one-use-in-inherent-method-return: I think the impl should be changed to
impl Foo<'_>, but no error is expected. - one-use-in-trait-method-argument: here a warning IS expected, but for
'g, not'f - two-uses-in-inherent-method-argument-and-return: should be changed I think to
impl Foo<'_>, and then no warnings would be expected
Niko Matsakis at 2018-04-12 14:21:15
- one-use-in-inherent-method-argument: I believe the comment is wrong. We should warn now, as you could write
@tamird
The approach you outline doesn't totally work out, I think
Regarding this... I think actually that the two-uses-in-fn-argument-and-return test:
fn c<'a>(x: &'a u32) -> &'a u32 { // OK: used twice &22 }is ok for two independent reasons: first, because the lifetime is used twice, but also because it is used in the return type. So it would be ok to invoke
withwithfalse(while visiting the return type). Hence tests like one-use-in-inherent-method-return still do not warn.Put another way, I do not yet see the problem. =)
Other than that, to do the last part (finding lifetimes with zero uses): where would you populate the set of lifetimes?
Hmm. I was thinking about this later. Keeping a set of "all lifetimes" doesn't feel right to me. In fact, the point where we iterate over the lifetimes in order to issue warnings is precisely the point where a set of declared lifetimes are going out of scope:
https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L1273-L1299
That is, the purpose of the
withfunction is to bring new lifetimes into scope. The lifetimes are found on thescopeparameter, which is of typeScope<'a>:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L261-L315
we could iterate over all the lifetimes that were declared in
Scope. We basically only care about the case whereScopeis aBinder, in which case we can iterate over thelifetimesmap:https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L268
For each
Regionvalue found within, we can extract aDefId(look for the/* lifetime_decl */comments):https://github.com/rust-lang/rust/blob/c19264fa835a1eca86de4fd2e86a87b3919e57cf/src/librustc/middle/resolve_lifetime.rs#L68-L83
then we can lookup that
DefIdthelifetime_usesmap. If it is not present, that should be zero uses.Niko Matsakis at 2018-04-12 17:31:21
@tamird -- do you think you are going to try and tackle this issue? That would be great! (If not, though, let me know so I can find someone else; I'd like to see this get done.)
Niko Matsakis at 2018-04-12 17:31:56
@nikomatsakis yep, I'm looking at this. Is there any reason to keep
lifetime_uses? it seems cleaner to combine the usage information into the binder'slifetimesmap.Tamir Duberstein at 2018-04-19 10:01:49
@tamird
Is there any reason to keep
lifetime_uses?If you think you see a cleaner way, go for it!
Niko Matsakis at 2018-04-25 14:27:36
@tamird btw, just checking -- how goes? I was away last week for PTO
Niko Matsakis at 2018-04-25 14:36:41
ping @tamird -- not trying to bug ya', just want to know if you're still working on this. I'm doing my weekly sweep and trying to figure out what I should do to ensure that this moves forward. It's .. mildly high priority, mostly because we'd like to encourage people to try out the in-band lifetimes feature, and for them to do that effectively, this lint ought to be a big help...
Niko Matsakis at 2018-04-30 18:26:14
First PR: https://github.com/rust-lang/rust/pull/50440
(I checked with @tamird and they would not be able to get to this for some time yet)
Niko Matsakis at 2018-05-04 09:56:00
Given that the 2018 edition preview included in-band lifetimes, it seems like we need to have this lint available for either the next preview or the 2018 edition stable release.
Josh Triplett at 2018-06-24 18:02:34
Even without in-band lifetimes, I think this is an important idiom lint, so I've added it to an edition milestone to get eyes on it. Edition folks: please move or remove if you think otherwise.
scottmcm at 2018-08-15 03:57:05
Wow, it's been three years...
I still think this is important. I started looking at how
in_band_lifetimesinrustc_mir_transform, and I immediately found a bunch of examples of unnecessary'as. Here's just incoverage/spans.rs, since it was at the bottom of the error list:- pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { + pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String { - pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { + pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String { - pub fn format_coverage_statements( + pub fn format_coverage_statements<'tcx>( &self, tcx: TyCtxt<'tcx>, - mir_body: &'a mir::Body<'tcx>, + mir_body: &mir::Body<'tcx>, ) -> String { -pub(super) fn filtered_statement_span(statement: &'a Statement<'tcx>) -> Option<Span> { +pub(super) fn filtered_statement_span<'tcx>(statement: &Statement<'tcx>) -> Option<Span> { -pub(super) fn filtered_terminator_span(terminator: &'a Terminator<'tcx>) -> Option<Span> { +pub(super) fn filtered_terminator_span<'tcx>(terminator: &Terminator<'tcx>) -> Option<Span> {scottmcm at 2021-12-06 04:57:05
Okay, I've created the
F-lint-single_use_lifetiemslabel and tagged the 6 relevant issues open for this.The examples in the "current status" section at the top all warn and have a suggestion, except for the unused lifetime, which falls under the
unused_lifetimelint.Marking S-tracking-impl-complete, given that there are several linked issues that need to be fixed.
Jack Huey at 2022-03-18 17:10:44
With #96833 merged, there has been progress on this issue recently. The number of false positives is now way down, but there's still one remaining, according to the PR's description.
est31 at 2022-05-29 21:38:18
@est31 what is the remaining false positive?
Camille Gillot at 2022-06-11 09:04:36
@cjgillot I was referring to:
Remaining false positive: single-use lifetimes in argument-position impl-trait. I'm waiting for #96529 to be fixed to have a clean and proper solution here.
Or is the false positive fixed now?
est31 at 2022-06-11 11:56:22
Indeed, the remaining false positive is:
trait Foo<'a> {} #[warn(single_use_lifetimes)] fn foo<'a>(_: impl Foo<'a>) {}Where the lifetime cannot be elided. There is an inconsistency here between plain functions and async functions (which allow elision). I suggested to allow elision in https://github.com/rust-lang/rust/pull/97720.
If that change is accepted, there won't be a false positive any more, and the suggestion will be correct.
Camille Gillot at 2022-06-12 12:17:26
I think the following might be an unaddressed false positive:
pub fn get_json<T>(&self, limit: u64) -> Result<(Meta, T)> where for<'de> T: Deserialize<'de>,error: lifetime parameter `'de` only used once --> crates/client/src/entity.rs:182:13 | 182 | for<'de> T: Deserialize<'de>, | ^^^ --- ...is used only here | | | this lifetime...I'm not aware of any way to use anonymous lifetimes to avoid the single-use lifetime here.
bstrie at 2022-08-09 14:26:15
Another false positive:
fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Mime, D::Error> {error: lifetime parameter `'de` only used once --> crates/type/src/meta.rs:31:16 | 31 | fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Mime, D::Error> { | ^^^ this lifetime... --- ...is used only hereAre anonymous lifetimes supposed to work here? The error:
error[E0637]: `'_` cannot be used here --> crates/type/src/meta.rs:31:32 | 31 | fn deserialize<D: Deserializer<'_>>(deserializer: D) -> Result<Mime, D::Error> { | ^^ `'_` is a reserved lifetime name
Similar example:
fn decode<'i, I>(values: &mut I) -> Result<Self, HeadErr> where Self: Sized, I: Iterator<Item = &'i HeaderValue>,bstrie at 2022-08-09 14:44:01
@bstrie, those cases are correctly handled by beta 1.63.0 https://play.rust-lang.org/?version=beta&mode=debug&edition=2021&gist=4fd54ae5a4d4a3a936054787f6655b7b
Camille Gillot at 2022-08-09 16:22:42
This appears to ignore the fact that lifetimes inside
impl Traitare currently unstable. See:#![warn(single_use_lifetimes)] fn test<'a>(val: &(impl 'a + Iterator)) {}This actually suggests removing the lifetime, which in turn is suggested to be added back with:
#![warn(single_use_lifetimes)] fn test(val: &(impl '_ + Iterator)) {}Clar Fon at 2023-09-08 18:43:56
Summarizing the current state of this:
- https://github.com/rust-lang/rust/pull/97720 was merged, but it requires the unstable feature
anonymous_lifetime_in_impl_trait anonymous_lifetime_in_impl_traitdoesn't have a tracking issue, but https://github.com/rust-lang/rust/pull/107378 proposes stabilization of it.- https://github.com/rust-lang/rust/pull/107378 is blocked on a concern about interaction with GATs. There are some suggestions to reduce the scope of what's being stabilized, but I wasn't clear on the state of that.
anonymous_lifetime_in_impl_traitalso has an ICE: https://github.com/rust-lang/rust/issues/124340
I think to make forward progress on this:
- We need a fix for the ICE, and
- Either:
- Lang needs to discuss the GAT issue and reach a consensus, or
- The stabilization scope needs to reduce to not include that, and lang needs to come to a consensus on the reduced-scope stabilization
Josh Triplett at 2024-08-26 22:21:04
- https://github.com/rust-lang/rust/pull/97720 was merged, but it requires the unstable feature