Lifetime elision opportunity


#1

This code does not compile:

fn range_intersect(mut a: &Range<usize>, mut b: &Range<usize>) -> Option<Range<usize>> {
    if a.start > b.start {
        std::mem::swap(&mut a, &mut b);
    }
    
    if b.start < a.end {
        Some(b.start..a.end)
    } else {
        None
    }
}

This is because a and b have different lifetimes.

I fixed it like so:

fn range_intersect<'a>(mut a: &'a Range<usize>, mut b: &'a Range<usize>) -> Option<Range<usize>>

But then I was thinking, why do I need to annotate this? This could be automatic. In particular, if a fn's output type has the static lifetime, all elided input lifetimes should be able to have the same lifetime (that of the function call). What do people think about implementing this relaxation of the elision rules?


#2

Unrelated note: another fun way to fix the above function without changing the signature:

fn range_intersect(&ref a: &Range<usize>, &ref b: &Range<usize>) -> Option<Range<usize>>

Except this doesn’t work because as @mbrubeck pointed out on IRC, mut ref bindings don’t exist.


#3

I think it would be a breaking change to make all elided input parameters equal in cases like this, since some of them might appear in invariant types, and that would change the meaning of the function signature.

Even for your example, it’s breaking in a lesser way, because range_intersect with elided lifetimes would no longer implement the for<'a, 'b> Fn<(&'a Range<usize>, &'b Range<usize>)> trait.