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

rustc thinks a lifetime bound is necessary when passing an associated type into a nested call #101601

Closed
BGR360 opened this issue Sep 9, 2022 · 4 comments
Labels
A-associated-items Area: Associated items (types, constants & functions) A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@BGR360
Copy link
Contributor

BGR360 commented Sep 9, 2022

No idea how to more effectively describe this problem in the title. Open to suggestions.

The following code fails to compile on stable (1.63.0) and nightly (playground):

trait Trait {
    type Associated;
}

struct Type<'a, T> {
    field: &'a T,
}

impl<'a, T> Type<'a, T>
where
    T: Trait,
{
    fn foo(param: T::Associated) {
        Self::bar(param);
    }

    fn bar(_: T::Associated) {}
}
error[E0309]: the parameter type `T` may not live long enough
  --> src/lib.rs:15:9
   |
15 |         Self::bar(param);
   |         ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
11 |     T: Trait + 'a,
   |              ++++

Removing the call to Self::bar makes the code compile just fine. It only fails when you try to call bar from inside foo.

This is really baffling to me. How is 'a even involved here?

Hint 1: It compiles if Type instead owns the T (playground):

struct Type<'a, T> {
    field: T,
    extra: &'a str
}

Hint 2: It compiles if foo and bar are methods instead of associated functions (playground).

Hint 3: It compiles if you do Type::<'_, T>::bar instead of Self::bar (playground).

I suppose it's possible that this isn't a bug, but if that's the case, then it's a corner of the language I have never hit before, and the diagnostics need a lot of work.

@rustbot label +A-associated-items +A-traits +A-lifetimes

@BGR360 BGR360 added the C-bug Category: This is a bug. label Sep 9, 2022
@rustbot rustbot added A-associated-items Area: Associated items (types, constants & functions) A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system labels Sep 9, 2022
@BGR360
Copy link
Contributor Author

BGR360 commented Sep 9, 2022

@rustbot label +T-compiler

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Sep 9, 2022
@BGR360
Copy link
Contributor Author

BGR360 commented Sep 9, 2022

And it gets even weirder! Let's say you do what rustc asks and add the T: 'a bound. Then if you add another field to the type that normally implies certain lifetime bounds (like field: &'b &'a () normally implies that 'a: 'b), the compiler suddenly can't infer those relationships / makes the user specify them manually! (playground)

trait Trait {
    type Associated;
}

struct Type<'a, 'b, T> {
    a: &'a T,
    b: &'b &'a (),
}

impl<'a, 'b, T> Type<'a, 'b, T>
where
    T: Trait + 'a,
{
    fn foo(param: T::Associated) {
        Self::bar(param);
    }

    fn bar(_: T::Associated) {}
}
error: lifetime may not live long enough
  --> src/lib.rs:15:9
   |
10 | impl<'a, 'b, T> Type<'a, 'b, T>
   |      --  -- lifetime `'b` defined here
   |      |
   |      lifetime `'a` defined here
...
15 |         Self::bar(param);
   |         ^^^^^^^^^ requires that `'a` must outlive `'b`
   |
   = help: consider adding the following bound: `'a: 'b`

That one fails to compile even when Type owns T:

struct Type<'a, 'b, T> {
    a: T,
    b: &'b &'a (),
}

And???????? It fails to compile even if there's no trait or associated type involved at all! (playground)

struct Type<'a, 'b> {
    field: &'b &'a (),
}

impl<'a, 'b> Type<'a, 'b> {
    fn foo() {
        Self::bar()
    }
    
    fn bar() {}
}

In all of those cases, removing the call to Self::bar or using an explict, turbofished Type makes it compile.

What is going on here?

@aliemjay
Copy link
Member

aliemjay commented Sep 10, 2022

The root cause is #98852. #100976 will improve the diagnostics by suggesting replacing Self with the the type name.

Consider closing it as a duplicate of either #98852 or #101393.

@BGR360
Copy link
Contributor Author

BGR360 commented Sep 11, 2022

Awesome, thank you for working on the fix!

@BGR360 BGR360 closed this as completed Sep 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants