Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"cannot infer an appropriate lifetime for automatic coercion" in struct initializer #13405

Closed
stepancheg opened this issue Apr 8, 2014 · 10 comments · Fixed by #17721
Closed
Labels
E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@stepancheg
Copy link
Contributor

Code:

struct Foo<'a> {
    i: &'a bool,
    j: Option<&'a int>,
}

impl<'a> Foo<'a> {
    fn bar(&mut self, j: &int) {
        let child = Foo {
            i: self.i,
            j: Some(j)
        };
    }
}

and error is:

/home/vagrant/tmp2.rs:9:16: 9:22 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
/home/vagrant/tmp2.rs:9             i: self.i,
                                       ^~~~~~
/home/vagrant/tmp2.rs:7:32: 12:6 note: first, the lifetime cannot outlive the lifetime &'a  as defined on the block at 7:31...
/home/vagrant/tmp2.rs:7     fn bar(&mut self, j: &int) {
/home/vagrant/tmp2.rs:8         let child = Foo {
/home/vagrant/tmp2.rs:9             i: self.i,
/home/vagrant/tmp2.rs:10             j: Some(j)
/home/vagrant/tmp2.rs:11         };
/home/vagrant/tmp2.rs:12     }
/home/vagrant/tmp2.rs:9:16: 9:22 note: ...so that reference does not outlive borrowed content
/home/vagrant/tmp2.rs:9             i: self.i,
                                       ^~~~~~
/home/vagrant/tmp2.rs:7:32: 12:6 note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the block at 7:31...
/home/vagrant/tmp2.rs:7     fn bar(&mut self, j: &int) {
/home/vagrant/tmp2.rs:8         let child = Foo {
/home/vagrant/tmp2.rs:9             i: self.i,
/home/vagrant/tmp2.rs:10             j: Some(j)
/home/vagrant/tmp2.rs:11         };
/home/vagrant/tmp2.rs:12     }
/home/vagrant/tmp2.rs:10:16: 10:23 note: ...so that expression is assignable (expected `std::option::Option<&int>` but found `std::option::Option<&int>`)
/home/vagrant/tmp2.rs:10             j: Some(j)
                                        ^~~~~~~
error: aborting due to previous error
@eddyb
Copy link
Member

eddyb commented Apr 8, 2014

Struct literal fields don't seem to do any coercion (we should at least consider reborrows).
cc @nikomatsakis

@dmski
Copy link
Contributor

dmski commented Apr 8, 2014

It seems to me that it doesn't compile correctly: the return value contains a reference of unnamed lifetime (parameter j: &int), which isn't considered the same as the lifetime of a struct being returned.

This compiles for me:

struct Foo<'a> {
    i: &'a bool,
    j: Option<&'a int>,
}

impl<'a> Foo<'a> {
    fn bar(&mut self, j: &'a int) {
        let child = Foo {
            i: self.i,
            j: Some(j)
        };
    }
}

as does this:

struct Foo<'a> {
    i: &'a bool,
    j: Option<&'a int>,
}

impl<'a> Foo<'a> {
    fn bar<'b>(&'b mut self, j: &'b int) {
        let child = Foo {
            i: self.i,
            j: Some(j)
        };
    }
}

Am i missing something? What would you expect to happen here? Or is this issue about unclear error message?

@stepancheg
Copy link
Contributor Author

@dmski function returns nothing.

@dmski
Copy link
Contributor

dmski commented Apr 8, 2014

Ah, sorry, should've read more carefully, disregard me.

@nikomatsakis
Copy link
Contributor

This error is caused by the intersection of various things, among them the coercion rules and #3598, but I tend to agree it should work. @eddyb's diagnosis could be correct, though I thought we were applying the coercion rules for struct literals. Investigation needed.

@eddyb
Copy link
Member

eddyb commented Apr 15, 2014

@nikomatsakis something I've figured since: if typeck sees a &T, it eagerly propagates the type, including its initial lifetime, and lifetime inference doesn't have as much wiggle room.
I don't know of any "known lifetimes" requirement in early type-checking (unlike "known types") so I would erase almost every lifetime before we do actual lifetime inference.

@nikomatsakis
Copy link
Contributor

On Tue, Apr 15, 2014 at 04:40:27AM -0700, Eduard Burtescu wrote:

@nikomatsakis something I've figured since: if typeck knows the lifetime of a &T, it eagerly propagates it, and lifetime inference doesn't have as much wiggle room.

Yes, this is the subtyping rules. The reborrowing coercion usually
addresses this in practice. I'm actually planning to revamp the
coercion code in the near term to make it more predictable, I will
take a look at this case too while I'm at it. It will require a bit
of an RFC I think.

@eddyb
Copy link
Member

eddyb commented Apr 15, 2014

The reborrowing coercion can't do anything for Option<&'a T> (because it's invariant wrt 'a), the reborrow has to happen earlier (that's where lifetime inference would fit in).

@nikomatsakis
Copy link
Contributor

@eddyb yes, I was referring to a coercion on the other field. of course fixing variance might help too. that turns out to be a bit trickier than I initially thought.

@ghost
Copy link

ghost commented Oct 1, 2014

This is working now but needs a test case.

@alexcrichton alexcrichton added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Oct 1, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants