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

Implicit lifetime bound on impl type parameter not applied to associated function #83014

Closed
detly opened this issue Mar 11, 2021 · 3 comments
Closed
Labels
A-implied-bounds Area: Implied bounds / inferred outlives-bounds C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@detly
Copy link

detly commented Mar 11, 2021

Consider this code:

struct Updater<'m, S: Copy> {
    store: &'m mut S,
}

impl<'m, S: Copy> Updater<'m, S> {
    fn craft<T: Copy>(builder: &Vec<T>) {}

    fn craft_reply<T: Copy>(update: Vec<T>)
    {
        Self::craft(&update)
    }       
}

It fails to compile on 1.50 and nightly 1.52.0-nightly (2021-03-10 f98721f) with:

   Compiling playground v0.0.1 (/playground)
error[E0309]: the parameter type `S` may not live long enough
  --> src/lib.rs:11:9
   |
5  | impl<'m, S: Copy> Updater<'m, S> {
   |          -- help: consider adding an explicit lifetime bound...: `S: 'm +`
...
11 |         Self::craft(&update)
   |         ^^^^^^^^^^^ ...so that the type `S` will meet its required lifetime bounds

error: aborting due to previous error

For more information about this error, try `rustc --explain E0309`.
error: could not compile `playground`

If I add a &self parameter to craft_reply(), it compiles. I cannot see what needs to be parameterised by the &self lifetime when it's not there, though.

Other things that work:

  • using impl<'m, S: Copy + 'm> (but I would have thought that S: 'm was implied by the reference to S requiring lifetime 'm)
  • adding where S: 'm to craft_reply()
  • moving the associated functions out of the impl (but I like organising associated functions alongside the methods that use them)
  • use Updater::<'_, S>::craft instead of Self::craft inside the function body

Some comments from the Discord (user Yandros FR-ES):

Basically your Updater struct has an implicit bound of S : 'm to be well formed. In the "good old days", one had to write that bound explicitly in many many places. That was considered cumbersome, given that the existence of a &'m [mut] S type already implies this.
So the compiler was tweaked to elide this bound, when such as type (e.g., &'m [mut] S or a wrapper around it, such as Self) appears in the function signature.
Which does not happen in your craft_reply function. This means that within the body of the function, the compiler does not know if S : 'm holds, and you thus can't name the Self = Updater<'m, S> type which needs that bound to hold 😄

I'd consider that a bug (and I expect there to be some issue about it already): the outer impl block ought to already imply that S : 'm holds

(Thread starts here.)

@detly detly added the C-bug Category: This is a bug. label Mar 11, 2021
@Kestrer
Copy link
Contributor

Kestrer commented Jun 26, 2021

If you encountered this bug in the context of attempting to return an associated type inside a trait method, you can work around it by explicitly specifying the associated type instead of using its name. So this code does not compile:

trait SomeTrait {
    type X;
    fn x() -> Self::X;
}

struct Foo<'a, 'b>(&'a &'b ());

impl<'a, 'b> SomeTrait for Foo<'a, 'b> {
    type X = &'a &'b ();
    fn x() -> Self::X {
        //    ^^^^^^^ associated type used
        let tuple: &'a &'b () = &&();
        tuple
    }
}

But this code does:

trait SomeTrait {
    type X;
    fn x() -> Self::X;
}

struct Foo<'a, 'b>(&'a &'b ());

impl<'a, 'b> SomeTrait for Foo<'a, 'b> {
    type X = &'a &'b ();
    fn x() -> &'a &'b () {
        //    ^^^^^^^^^^ explicit type used
        let tuple: &'a &'b () = &&();
        tuple
    }
}

@Chris00
Copy link

Chris00 commented May 3, 2022

Here is another example of such a situation inspired by a real life™ situation.

@fmease fmease added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. A-implied-bounds Area: Implied bounds / inferred outlives-bounds and removed needs-triage-legacy labels Jan 23, 2024
@fmease
Copy link
Member

fmease commented Jan 23, 2024

This now successfully compiles on nightly. #120019 has fixed this. Closing as completed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-implied-bounds Area: Implied bounds / inferred outlives-bounds C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants