Skip to content

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

Closed
@detly

Description

@detly

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.)

Activity

Kestrer

Kestrer commented on Jun 26, 2021

@Kestrer
Contributor

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

Chris00 commented on May 3, 2022

@Chris00

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

added
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
T-typesRelevant to the types team, which will review and decide on the PR/issue.
A-implied-boundsArea: Implied bounds / inferred outlives-bounds
and removed on Jan 23, 2024
fmease

fmease commented on Jan 23, 2024

@fmease
Member

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-implied-boundsArea: Implied bounds / inferred outlives-boundsC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @detly@Chris00@ChrisDenton@fmease@Kestrer

        Issue actions

          Implicit lifetime bound on impl type parameter not applied to associated function · Issue #83014 · rust-lang/rust