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

Unconstrained lifetime error does not consider 'static bound on associated type #107997

Closed
benschulz opened this issue Feb 13, 2023 · 3 comments
Closed
Labels
C-bug Category: This is a bug.

Comments

@benschulz
Copy link
Contributor

The compiler fails to exploit a 'static bound, requiring a verbose workaround via supertrait.

I tried the following code (playground).

trait Foo {
    type Assoc;
}

trait Bar<'a> {
    type Assoc: 'static;
}

struct S<T>(T);

impl<'a, T> Foo for S<T>
where
    T: Bar<'a>,
{
    type Assoc = <T as Bar<'a>>::Assoc;
}

I expected it to compile. Instead I was greeted by E0207, lamenting that 'a is unconstrained. However, the following code works without issue (playground).

trait Foo {
    type Assoc;
}

trait Bar0 {
    type Assoc;
}

trait Bar<'a>: Bar0 {}

struct S<T>(T);

impl<'a, T> Foo for S<T>
where
    T: Bar<'a>,
{
    type Assoc = <T as Bar0>::Assoc;
}

Note that introducing the supertrait allows referring to Bar0::Assoc without mentioning the lifetime 'a. However, unless I'm missing any subtleties, the compiler should be able to deduce (due to the bound on Bar::Assoc) that <T as Bar<'a>>::Assoc: 'static and that therefore it does not matter that the lifetime is unconstrained.

Meta

Affects all rustc versions, including 1.69.0-nightly (5b8f284 2023-02-12).

@benschulz benschulz added the C-bug Category: This is a bug. label Feb 13, 2023
@benschulz
Copy link
Contributor Author

benschulz commented Feb 23, 2023

It think I've found a workaround (playground). All references to the lifetime can be elided by declaring a supertrait which gets blanket-implemented.

trait Foo {
    type Assoc;
}

trait Bar<'a>: BarStatics<Assoc = <Self as Bar<'a>>::Assoc> {
    type Assoc: 'static;
}

trait BarStatics {
    type Assoc;
}

impl<'a, T> BarStatics for T
where
    T: Bar<'a>,
{
    type Assoc = <Self as BarStatics>::Assoc;
}

struct S<T>(T);

impl<'a, T> Foo for S<T>
where
    T: Bar<'a>,
{
    type Assoc = <T as BarStatics>::Assoc;
}

I have yet to confirm that the workaround applies to my original problem. I'll leave this issue open regardless because I believe it's an unnecessary paper cut.


Edit: This workaround runs straight into #39959 when trying to implement the trait (playground).

@aliemjay
Copy link
Member

aliemjay commented Feb 27, 2023

Note that a type being 'static doesn't necessarily mean it cannot be generic over lifetimes. This is evident in opaque types:

#![feature(type_alias_impl_trait)]

type Opaque<'a> = impl Fn(&'a str) + 'static;

fn test<'a>() -> Opaque<'a> {
    |_| {}
}

If we were to permit your suggested behavior, we would be accepting an implementation like the following:

impl<'a> Foo for () {
    type Assoc = Opaque<'a>;
}

An then <() as Foo>::Assoc wouldn't resolve to a unique type, because 'a appears unconstrained in Opaque<'a>.

@benschulz
Copy link
Contributor Author

Oh, good point, thanks!

Note that a type being 'static doesn't necessarily mean it cannot be generic over lifetimes. This is evident in opaque types:

#![feature(type_alias_impl_trait)]

type Opaque<'a> = impl Fn(&'a str) + 'static;

fn test<'a>() -> Opaque<'a> {
    |_| {}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

2 participants