Argument-position `impl Trait` requires a named lifetime
cramertj opened this issue · 11 comments
This function produces an "expected lifetime parameter" error:
fn foo(_: impl Iterator<Item = &u8>) {}
This code should instead be accepted and bound the impl Trait
parameter by the elided lifetime.
cc #34511
In my opinion, we should accept '_
, in-band lifetimes, and friends in where clauses as well. I'm not 100% sure whether this was controversial though, have to check.
Still generates an error for me on nightly.
@cramertj Hmm yes, I should have tried first, my bad. This is independent of the two return-position impl Trait
lifetime-related bugs that you're fixing, right?
Ran into this today. Providing the '_
lifetime gives a very fun error:
fn f(_: impl Iterator<Item = &'_ ()>) {}
error[E0106]: missing lifetime specifier
--> src/lib.rs:1:31
|
1 | fn f(_: impl Iterator<Item = &'_ ()>) {}
| ^^ expected lifetime parameter
It's actually gotten slightly worse:
error[E0106]: missing lifetime specifier
--> src/lib.rs:1:31
|
1 | fn f(_: impl Iterator<Item = &'_ ()>) {}
| ^^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
1 | fn f(_: 'a, impl Iterator<Item = &'a ()>) {}
| ^^ ^^^
#68583 will address that. After it gets merged the output will be
I feel that's going to be as good a diagnostic we're gonna have for this.
I feel that's going to be as good a diagnostic we're gonna have for this.
@estebank Does that mean that this will be the "final" state for this feature? As in, anonymous lifetimes will not be usable in the positions mentioned by @nikomatsakis in #49287 (comment)?
What I mean that until anonymous lifetimes are accepted in impl Trait we're going to have some diagnostic, and the one I posted is likely the best we can do given our constraints.
The reason that lifetimes were not permitted here, as I recall, was some uncertainty about what they should mean (in particular, should impl Foo<'_>
mean impl for<'a> Foo<'a>
or what). I am actually still a bit unsure as to my opinion here -- I've seen people expect it to mean both things.
In this case, impl for<'a> Foo<'a>
wouldn't work, but could you show me a case where it would? I feel that the only case where impl for<'a> X
is common is for Fn()
and in that case unnamed lifetimes usually work, and in the case where a named lifetime that hasn't been introduced is used produces the following now (not yet in the latest nightly):
error[E0261]: use of undeclared lifetime name `'a`
--> file4.rs:1:27
|
1 | fn foo(_compare: impl Fn(&'a u8)) {
| ^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider introducing lifetime `'a` here
|
1 | fn foo<'a>(_compare: impl Fn(&'a u8)) {
| ^^^^
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
1 | fn foo(_compare: impl for<'a> Fn(&'a u8)) {
| ^^^^^^^
I'm not sure what you mean by "show you a case where it would work", I guess you mean a realistic example where that is what you would want? I don't really have one off the top of my head, but I agree with you it's probably quite a bit less common -- after all, I almost never write for
bounds in practice.
So yeah, I pretty much agree it'd be the wrong meaning, and I think it'd even be somewhat counter-intuitive. We have a pretty strong precedent right now that '_
binds into the "innermost enclosing parentheses", in a sense, and I would be quite surprising to find impl Foo<'_>
create a lifetime bound within the scope of impl
keyword.