Lifetime elision with only the return type elided


#1

I am surprised that the following code compiles, because the return type of new has the lifetime elided (while the input variable are explicit).

struct Lexer;

struct LexerIter<'a> {
    lexer: &'a Lexer,
}

impl<'a> LexerIter<'a> {
    pub fn new(lexer: &'a Lexer) -> LexerIter {
        LexerIter {
            lexer: lexer,
        }
    }
}

fn main() { }

I don’t see why this should compile. The naive equivalent (adding lifetime parameters) would have me go pub fn new<'b>(lexer: &'a Lexer) -> LexerIter<'b>, which is a type error. Am I missing something, or what is this strange case?


#2

This is a bit subtle, but, fn new(_: &Lexer) is not “elision” or at least not the same kind as that found in the return type.

Instead, missing lifetimes in argument types get substituted with anonymous (late-bound) lifetime parameters, so these are all equivalent:

fn foo(_: &i32) -> R {...}
fn foo<'a>(_: &'a i32) -> R {...}
fn foo<'b>(_: &'b i32) -> R {...}

The return type lifetime elision, however, looks for more or less (self is a bit special) one lifetime in the argument types, and uses that lifetime in all locations where a lifetime is missing. That is, R above can have any number of lifetime parameters and they all get the same lifetime from the reference to i32.


#3

Thanks for elaborating! I had completely missed that it could be only partway explicit in where a parameter is used. It allows us to write Rust that is extra confusing:

fn pos<'x>(&'x self) -> &usize;

#4

I wouldn’t say that’s particularly confusing. Since the lifetime needs to be bound to an input (unless explicitly 'static) there’s really only one lifetime it could be here.