Skip to content

impl Trait with multiple lifetimes imposes a strange lifetime requirement #61756

Open
@goffrie

Description

@goffrie

Consider the following code:

pub struct Store;
impl Store {
    fn scan<'a>(&'a self) -> Box<dyn Iterator<Item = u64> + 'a> { panic!() }
}
pub struct Transaction<'a> {
    kv: &'a Store,
    reads: Vec<u64>,
}

impl<'a> Transaction<'a> {
    pub fn scan(&mut self) -> impl Iterator<Item = u64> + 'a + '_ {
        let iter = self.kv.scan();
        iter.map(move |k| {
            self.reads.push(k);
            k
        })
    }
}

Compiling with #![feature(nll)] yields the following error:

error: lifetime may not live long enough
  --> src/lib.rs:24:9
   |
18 |   impl<'a> Transaction<'a> {
   |        -- lifetime `'a` defined here
19 |       pub fn scan(&mut self) ->
   |                   - let's call the lifetime of this reference `'1`
...
24 | /         iter.map(move |k| {
25 | |             self.reads.push(k);
26 | |             k
27 | |         })
   | |__________^ returning this value requires that `'1` must outlive `'a`

error: aborting due to previous error

That is, it's requiring that the reference to Transaction outlive 'a. Unfortunately, it doesn't explain at all why that requirement was imposed.

Also, just returning + '_ complains:

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
  --> src/lib.rs:20:9
   |
20 |         impl Iterator<Item = u64> + '_
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: hidden type `std::iter::Map<std::boxed::Box<dyn std::iter::Iterator<Item = u64>>, [closure@src/lib.rs:24:18: 27:10 self:&mut Transaction<'a>]>` captures the lifetime 'a as defined on the impl at 18:6
  --> src/lib.rs:18:6
   |
18 | impl<'a> Transaction<'a> {
   |      ^^

This is odd to me because if we return Box<dyn Iterator<Item = u64> + '_>, everything works fine (and nobody complains about 'a). Furthermore, the equivalent to the impl Trait using an explicit existential type TransactionScan<'a, 'b>: Iterator<Item = u64>; works fine as well.

This may be related to/a dupe of #49431, but the errors produced are different so I'm not sure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-NLLArea: Non-lexical lifetimes (NLL)A-diagnosticsArea: Messages for errors, warnings, and lintsA-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.A-lifetimesArea: Lifetimes / regionsC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler 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