Skip to content

Lifetime elision works incorrectly with explicit self types in methods #21400

Closed
@netvl

Description

@netvl

Found in this SO question.

This code compiles:

struct Test;

impl Test {
    fn method1(&mut self, arg: &str) -> Result<usize, &str> {
        unreachable!()
    }

    fn method2(self: &mut Test, arg: &str) -> Result<usize, &str> {
        unreachable!()
    }

    fn test(self: &mut Test) -> Result<usize, &str> {
        let s = format!("abcde");
        let data = match self.method1(&*s) {
            Ok(r) => r,
            Err(e) => return Err(e)
        };
        unreachable!()
    }
}

fn main() {
}

But if you change self.method1(&*s) to self.method2(&*s) it will stop compiling:

test7.rs:14:41: 14:42 error: `s` does not live long enough
test7.rs:14         let data = match self.method2(&*s) {
                                                    ^
test7.rs:12:53: 19:6 note: reference must be valid for the anonymous lifetime #1 defined on the block at 12:52...
test7.rs:12     fn test(self: &mut Test) -> Result<usize, &str> {
test7.rs:13         let s = format!("abcde");
test7.rs:14         let data = match self.method2(&*s) {
test7.rs:15             Ok(r) => r,
test7.rs:16             Err(e) => return Err(e)
test7.rs:17         };
            ...
test7.rs:12:53: 19:6 note: ...but borrowed value is only valid for the block at 12:52
test7.rs:12     fn test(self: &mut Test) -> Result<usize, &str> {
test7.rs:13         let s = format!("abcde");
test7.rs:14         let data = match self.method2(&*s) {
test7.rs:15             Ok(r) => r,
test7.rs:16             Err(e) => return Err(e)
test7.rs:17         };
            ...

According to the lifetime elision rules this signature:

fn method2(self: &mut Test, arg: &str) -> Result<usize, &str>

should be equivalent to this one:

fn method2<'a, 'b>(self: &'a mut Test, arg: &'b str) -> Result<usize, &'a str>

However, it seems that currently it is equivalent to this one:

fn method2<'a>(self: &'a mut Test, arg: &'a str) -> Result<usize, &'a str>

which gives exactly the same error as the elided version.

Another funny thing is that if I remove match and write just

let data = self.method2(&*s);

It compiles again.

Metadata

Metadata

Assignees

Labels

A-type-systemArea: Type systemE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.P-mediumMedium priority

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions