Skip to content

Potentially false positive of "lifetime may not live long enough" after introduction of Sized bound on associated type #137184

Open
@yannham

Description

@yannham

I tried this code:

use std::marker::PhantomData;

/// Some data. In real life, imagine that its content is arena-allocated with lifetime `'a`.
struct Data<'a> {
    _marker: PhantomData<&'a ()>,
}

struct DataAlloc;

/// Data with borrowed content that can be copied from one location to another.
trait CopyTo {
    /// This is always `Self`, be we need associated types to make Rust understand that `Self` is
    /// actually parametric over some lifetime.
    type Data<'a>;

    /// Copy data from the current allocator to `dest`.
    fn copy_to<'from, 'to>(data: Self::Data<'from>, dest: &'to DataAlloc) -> Self::Data<'to>;
}

impl CopyTo for Data<'_> {
    type Data<'a> = Data<'a>;

    fn copy_to<'from, 'to>(data: Data<'from>, _dest: &'to DataAlloc) -> Data<'to> {
        Data {
            _marker: PhantomData,
        }
    }
}

impl DataAlloc {
    pub fn copy<'from, 'to, T: CopyTo>(&'to self, data: T::Data<'from>) -> T::Data<'to>
    where
        T: CopyTo<Data<'to>: Sized>,
    {
        T::copy_to(data, self)
    }
}

I expected to see this happen: this code should compile. In fact, if I remove the where T: CopyTo<Data<'to>: Sized> clause, which isn't used at all, this code compiles.

Instead, this happened: I get a lifetime may not live long enough error, with the note "Proving this value is Sized requires to to must outlive 'from" as well as the dual message:

error: lifetime may not live long enough
  --> src/lib.rs:35:20
   |
31 |     pub fn copy<'from, 'to, T: CopyTo>(&'to self, data: T::Data<'from>) -> T::Data<'to>
   |                 -----  --- lifetime `'to` defined here
   |                 |
   |                 lifetime `'from` defined here
...
35 |         T::copy_to(data, self)
   |                    ^^^^ proving this value is `Sized` requires that `'to` must outlive `'from`
   |
   = help: consider adding the following bound: `'to: 'from`

error: lifetime may not live long enough
  --> src/lib.rs:35:20
   |
31 |     pub fn copy<'from, 'to, T: CopyTo>(&'to self, data: T::Data<'from>) -> T::Data<'to>
   |                 -----  --- lifetime `'to` defined here
   |                 |
   |                 lifetime `'from` defined here
...
35 |         T::copy_to(data, self)
   |                    ^^^^ proving this value is `Sized` requires that `'from` must outlive `'to`
   |
   = help: consider adding the following bound: `'from: 'to`

Context

This is a simplified version of a real use-case where I have arena-allocated data and I want a trait that implements moving them from one arena to another with a different lifetime. Since Rust doesn't support general higher-kinded types, I use GATs as a poor man's HKT, which requires more annotations but it works ok. However, when I try to implement a variant of copy where I need additional bounds on the associated type, I started to get strange lifetime errors. What's surprising here is that the trait bound is unrelated to the body of the function and never used. It's surprising that adding a Sized bound adds any lifetime constraints at all, unless I'm missing something obvious.

Potential duplicate of #108345, but I wanted to make sure it's not a different error first.

Meta

rustc --version --verbose:

rustc 1.84.1 (e71f9a9a9 2025-01-27)
binary: rustc
commit-hash: e71f9a9a98b0faf423844bf0ba7438f29dc27d58
commit-date: 2025-01-27
host: x86_64-unknown-linux-gnu
release: 1.84.1
LLVM version: 19.1.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lifetimesArea: Lifetimes / regionsA-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-langRelevant to the language 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

    Issue actions