Skip to content
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

Is this difference in lifetime elision for impl Trait arguments between async and non-async function intended? #85417

Open
LukasKalbertodt opened this issue May 17, 2021 · 4 comments
Labels
A-async-await Area: Async & Await A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting.

Comments

@LukasKalbertodt
Copy link
Member

This compiles:

async fn foo(_: impl Iterator<Item = &u32>) {}

But this doesn't:

fn foo(_: impl Iterator<Item = &u32>) {}
error[E0106]: missing lifetime specifier
 --> src/lib.rs:1:32
  |
1 | fn foo(_: impl Iterator<Item = &u32>) {}
  |                                ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
1 | fn foo<'a>(_: impl Iterator<Item = &'a u32>) {}
  |       ^^^^                         ^^^

This difference strikes me as very odd. Is this intended? If so, why?

This is formulated as a question, but if I had to guess, I would classify this as oversight or bug -- that's why I created an issue instead of askig in the forum.

(originally asked here)

@jonas-schievink jonas-schievink added the A-async-await Area: Async & Await label May 17, 2021
@tmandry tmandry added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. labels May 21, 2021
@tmandry
Copy link
Member

tmandry commented May 21, 2021

We discussed this in our meeting today. The difference in behavior comes from this code:

let lt_mode = if make_ret_async.is_some() {
// In `async fn`, argument-position elided lifetimes
// must be transformed into fresh generic parameters so that
// they can be applied to the opaque `impl Trait` return type.
AnonymousLifetimeMode::CreateParameter
} else {
self.anonymous_lifetime_mode
};

While we decided that async fn probably exhibits the right behavior, it's possible this could affect other things too which could lead to bugs. Before declaring this fixed we should account for anything that might appear in arguments and be affected by this code.

We also noticed that in sync code, we aren't consistent in the behavior of impl Trait and dyn Trait. For example:

trait Something { type Item; }
fn foo(x: &dyn Something<Item = &u32>) { }   // works fine
fn foo(x: &impl Something<Item = &u32>) { }  // error

We should be more consistent and document the elision rules for all these cases in the reference. Since dyn already accepts this, we decided we should go ahead and accept this for impl Trait too.

@eholk
Copy link
Contributor

eholk commented Oct 4, 2021

This seems sort of related to #74256 and #74597.

@estebank
Copy link
Contributor

estebank commented Aug 16, 2022

The output of this is regressing in 1.64.

1.63:

error[[E0106]](https://doc.rust-lang.org/stable/error-index.html#E0106): missing lifetime specifier
 --> src/lib.rs:1:32
  |
1 | fn foo(_: impl Iterator<Item = &u32>) {}
  |                                ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
1 | fn foo<'a>(_: impl Iterator<Item = &'a u32>) {}
  |       ++++                          ++

1.64:

error[[E0658]](https://doc.rust-lang.org/beta/error-index.html#E0658): anonymous lifetimes in `impl Trait` are unstable
 --> src/lib.rs:1:32
  |
1 | fn foo(_: impl Iterator<Item = &u32>) {}
  |                                ^

@cjgillot
Copy link
Contributor

cjgillot commented Sep 1, 2022

#97720 originally suggested to remove the difference between the async and regular fns. In order to avoid and insta-stable change, the choice was made to introduce the feature gate instead in #97720 (comment).

Removing this feature gate is trivial: revert 5a20834.
Re-introducing suggestions there is more complicated: the feature gate happens after the suggestion code. (AST-based resolution accepts the code and does not suggest anything, and HIR-based lifetime resolution issues the feature gate later.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting.
Projects
Status: On deck
Development

No branches or pull requests

6 participants