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

Impl Trait forces unnecessary lifetime bounds #80083

Open
CryZe opened this issue Dec 16, 2020 · 2 comments
Open

Impl Trait forces unnecessary lifetime bounds #80083

CryZe opened this issue Dec 16, 2020 · 2 comments
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions A-variance Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)

Comments

@CryZe
Copy link
Contributor

CryZe commented Dec 16, 2020

It seems like impl Trait forces its own lifetime bound onto anything that it touches, even if that doesn't make sense.

struct Never<T>(fn() -> T);

impl<T> Iterator for Never<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        None
    }
}

fn actual_type<T>(f: fn() -> T) -> Never<T> {
    Never(f)
}

fn impl_trait<T>(f: fn() -> T) -> impl Iterator<Item = T> + 'static {
    Never(f)
}

Here I create an iterator like type that takes a function that produces T values. The implementation of the iterator doesn't really matter here. If I now create a function constructing that type, returning the actual type lets the borrow checker correctly understand that T doesn't require any lifetimes. However if I return impl Iterator instead, the compiler is apparently seeing that T is part of the impl Trait and therefore forces me to apply the same lifetime as the iterator itself to the elements T, even if that makes no sense. I'm guessing impl Trait is not properly respecting variance.

error[E0310]: the parameter type `T` may not live long enough
  --> src/lib.rs:14:35
   |
14 | fn impl_trait<T>(f: fn() -> T) -> impl Iterator<Item = T> + 'static {
   |               -                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `Never<T>` will meet its required lifetime bounds
   |               |
   |               help: consider adding an explicit lifetime bound...: `T: 'static`

error: aborting due to previous error

Playground

@HeroicKatora mentioned that a similar problem happens with trait objects as well: Playground

@camelid camelid added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions labels Dec 16, 2020
@BGR360
Copy link
Contributor

BGR360 commented Dec 27, 2021

#88682 (comment) gives a potential explanation for why returning impl-trait is behaving differently wrt variance:

[...] return position impl Trait is invariant (because it could potentially be fulfilled by a type which is invariant over the lifetime(s)) [...]

@rustbot label +A-variance

@rustbot rustbot added the A-variance Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html) label Dec 27, 2021
@aliemjay
Copy link
Member

aliemjay commented May 15, 2022

I don't think this is bug.

Here I create an iterator like type that takes a function that produces T values. The implementation of the iterator doesn't really matter here.

RFC 1214 allows us to require/imply <Never<T> as Iterator>::Item: 'static if we know Never<T>: 'static. Similarly for function pointers, fn() -> T can't be 'static unless T: 'static.

See how 'static types with non-'static associated type can lead to the unsoundness in #84366.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions A-variance Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)
Projects
None yet
Development

No branches or pull requests

5 participants