rusttraitslifetime

`impl Trait` return type causes wrong lifetime elision


The impl Trait syntax for return types seems to cause the compiler to incorrectly assume that the lifetime of the input argument must match the output in some situations. Consider the function

fn take_by_trait<T: InTrait>(_: T) -> impl OutTrait {}

If the input type contains a lifetime the compiler complains when the output outlives the it even though they are completely independent. This will not happen if the input type is not generic, or if the output is a Box<dyn OutTrait>.

Full code:

trait InTrait {}

struct InStruct<'a> {
    _x: &'a bool, // Just a field with some reference
}

impl<'a> InTrait for InStruct<'a> {}

trait OutTrait {}

impl OutTrait for () {}

fn take_by_type(_: InStruct) -> impl OutTrait {}

fn take_by_trait<T: InTrait>(_: T) -> impl OutTrait {}

fn take_by_trait_output_dyn<T: InTrait>(_: T) -> Box<dyn OutTrait> {
    Box::new(())
}

fn main() {
    let _ = {
        let x = true;
        take_by_trait(InStruct{ _x: &x }) // DOES NOT WORK
        // take_by_type(InStruct { _x: &x }) // WORKS
        // take_by_trait_output_dyn(InStruct { _x: &x }) // WORKS
    };
}

Is there some elided lifetime here that I could qualify to make this work, or do I need to do heap allocation?


Solution

  • Edit: Since PR #116733 + 'static works.

    fn take_by_trait<T: InTrait>(_: T) -> impl OutTrait + 'static {}
    

    impl Trait in return position implicitly captures the any lifetime appearing in generic parameters. This is not something you can express in normal Rust, only with impl Trait.

    On stable as far as I know there is no way to avoid that. On nightly you can use type_alias_impl_trait:

    #![feature(type_alias_impl_trait)]
    
    type Ret = impl OutTrait;
    fn take_by_trait<T: InTrait>(v: T) -> Ret {}
    

    See issues Unclear compiler error when impl Trait return value captures non-'static argument (#82171), impl Trait capturing lifetime of type parameter (#79415), False-positive "temporary dropped while borrowed" involving return-position impl Trait (#98997), impl Trait + 'static is not static if returned from generic function (#76882).