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

Unexplained lifetime error in closure type #11740

Closed
nikomatsakis opened this issue Jan 23, 2014 · 9 comments
Closed

Unexplained lifetime error in closure type #11740

nikomatsakis opened this issue Jan 23, 2014 · 9 comments
Labels
A-lifetimes Area: lifetime related E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@nikomatsakis
Copy link
Contributor

In the following test, removing the type annotation from attr produces lifetime errors:

#[feature(managed_boxes)];

use std::cast;
use std::unstable::raw::Box;

struct Attr {
    name: ~str,
    value: ~str,
}

struct Element {
    attrs: ~[@mut Attr],
}

impl Element {
    pub unsafe fn get_attr<'a>(&'a self, name: &str) {
        self.attrs.iter().find(|attr| { // To remove error: |attr: & & 'a @mut Attr| {
                let attr: ***Box<Attr> = cast::transmute(attr);
                true
        });
    }
}

pub fn main() {
    let element = Element {
        attrs: ~[],
    };
    let _ = unsafe { element.get_attr("foo") };
}

Error message:

Running /home/nmatsakis/versioned/rust-1/build/i686-unknown-linux-gnu/stage2/bin/rustc:
/home/nmatsakis/tmp/foo.rs:17:9: 17:27 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
/home/nmatsakis/tmp/foo.rs:17         self.attrs.iter().find(|attr| { // |attr: & & 'a @Attr| {
                                      ^~~~~~~~~~~~~~~~~~
/home/nmatsakis/tmp/foo.rs:17:9: 17:19 note: first, the lifetime cannot outlive the expression at 17:8...
/home/nmatsakis/tmp/foo.rs:17         self.attrs.iter().find(|attr| { // |attr: & & 'a @Attr| {
                                      ^~~~~~~~~~
/home/nmatsakis/tmp/foo.rs:17:9: 17:19 note: ...so that automatically reference is valid at the time of borrow
/home/nmatsakis/tmp/foo.rs:17         self.attrs.iter().find(|attr| { // |attr: & & 'a @Attr| {
                                      ^~~~~~~~~~
/home/nmatsakis/tmp/foo.rs:17:9: 17:27 note: but, the lifetime must be valid for the method call at 17:8...
/home/nmatsakis/tmp/foo.rs:17         self.attrs.iter().find(|attr| { // |attr: & & 'a @Attr| {
                                      ^~~~~~~~~~~~~~~~~~
/home/nmatsakis/tmp/foo.rs:17:9: 17:19 note: ...so that method receiver is valid for the method call
/home/nmatsakis/tmp/foo.rs:17         self.attrs.iter().find(|attr| { // |attr: & & 'a @Attr| {
                                      ^~~~~~~~~~
error: aborting due to previous error
task 'rustc' failed at 'explicit failure', /home/nmatsakis/versioned/rust-1/src/libsyntax/diagnostic.rs:75
task '<main>' failed at 'explicit failure', /home/nmatsakis/versioned/rust-1/src/librustc/lib.rs:448
@huonw
Copy link
Member

huonw commented Feb 1, 2014

A more minimal example:

struct Element {
    attrs: ~[()],
}

impl Element {
    pub unsafe fn get_attr<'a>(&'a self, name: &str) {
        self.attrs.iter().find(|attr| {
                let attr: () = std::cast::transmute(attr);
                true
        });
    }
}

pub fn main() {}

Another slightly peculiar thing: changing the () in ~[()] or the () in let attr: () sometime changes the error message to a slightly different form:

11740.rs:7:9: 7:27 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
11740.rs:7         self.attrs.iter().find(|attr| {
                   ^~~~~~~~~~~~~~~~~~
11740.rs:7:39: 10:10 note: first, the lifetime cannot outlive an anonymous lifetime defined on the block at 7:38...
11740.rs:7         self.attrs.iter().find(|attr| {
11740.rs:8                 let attr: () = std::cast::transmute(attr);
11740.rs:9                 true
11740.rs:10         });
11740.rs:8:53: 8:57 note: ...so that the pointer does not outlive the data it points at
11740.rs:8                 let attr: () = std::cast::transmute(attr);
                                                               ^~~~
11740.rs:7:9: 7:19 note: but, the lifetime must be valid for the expression at 7:8...
11740.rs:7         self.attrs.iter().find(|attr| {
                   ^~~~~~~~~~
11740.rs:7:9: 7:19 note: ...so that automatically reference is valid at the time of borrow
11740.rs:7         self.attrs.iter().find(|attr| {

@yuchen99
Copy link

yuchen99 commented Jun 3, 2014

Is this same case?

let it = range(100, 999).collect::<Vec<int>>();
    println!("{}",
        it.move_iter().flat_map(|x| range(x,999).collect::<Vec<int>>()
                                                .iter()
                                                .map(|j| j * x))
                    .filter(|x| x.to_str() == x.to_str().as_slice().chars().rev().collect::<String>())
                    .max_by(|x|x.to_int())
        );

@huonw
Copy link
Member

huonw commented Jun 3, 2014

@yuchen99 no, I think that is a legitimate error. The map closure is capturing x by reference, and so is restricted to the scope in which x is defined, that is, the flat_map call. Hence, it is not possible to return an iterator object that includes a closure with a reference to it (unboxed closures will make this possible). For that specific instance, you can use range_step, something like

use std::iter;
it.move_iter().flat_map(|x| iter::range_step(x * x, 999 * x, x)).filter(...

Also, you don't need the .collect::<Vec<int>> call, something like range(x, 999).map(|j| j * x) has the same semantics but is significantly faster.

Lastly, saying "is not useful" doesn't help us help you :) In any case, you should ask a question like that on StackOverflow, not on an unrelated issue.

@yuchen99
Copy link

yuchen99 commented Jun 3, 2014

@huonw I'm sorry to say that.
You are right .Thanks for help

@aturon aturon mentioned this issue Oct 16, 2014
47 tasks
@frewsxcv
Copy link
Member

I attempted to update this to work with the latest rust:

struct Element {
    attrs: Box<[()]>,
}

impl Element {
    pub unsafe fn get_attr<'a>(&'a self, name: &str) {
        self.attrs.iter().find(|attr| {
                let attr: () = std::mem::transmute(attr);
                true
        });
    }
}

pub fn main() {}

but upon compiling, get this error:

hi.rs:8:32: 8:51 error: transmute called on types with different sizes: &&() (64 bits) to () (0 bits)
hi.rs:8                 let attr: () = std::mem::transmute(attr);
                                       ^~~~~~~~~~~~~~~~~~~

@remram44
Copy link
Contributor

@frewsxcv this builds (changed Box<()> line 8):

struct Element {
    attrs: Box<[()]>,
}

impl Element {
    pub unsafe fn get_attr<'a>(&'a self, name: &str) {
        self.attrs.iter().find(|attr| { // or |attr: &&()|
                let attr: Box<()> = std::mem::transmute(attr);
                true
        });
    }
}

pub fn main() {}

@steveklabnik
Copy link
Member

Triage: @remram44 's example still builds today. So it would seem maybe this is fixed? It's getting harder and harder to remember the old syntaxes, and how to most properly map them over...

@oli-obk
Copy link
Contributor

oli-obk commented May 2, 2017

I can confirm that the error is gone:

struct Attr {
    name: String,
    value: String,
}

struct Element {
    attrs: Vec<Box<Attr>>,
}

impl Element {
    pub unsafe fn get_attr<'a>(&'a self, name: &str) {
        self.attrs
            .iter()
            .find(|attr| {
                      // To remove error: |attr: & & 'a Box<Attr>| {
                      let attr: &&Box<Attr> = std::mem::transmute(attr);
                      true
                  });
    }
}

pub fn main() {
    let element = Element { attrs: Vec::new() };
    let _ = unsafe { element.get_attr("foo") };
}

@nikomatsakis
Copy link
Contributor Author

Do we want to add a regression test, or should we just close?

@frewsxcv frewsxcv added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label May 3, 2017
MaloJaffre added a commit to MaloJaffre/rust that referenced this issue Jun 18, 2017
Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this issue Jun 18, 2017
frewsxcv added a commit to frewsxcv/rust that referenced this issue Jun 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: lifetime related 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

No branches or pull requests

7 participants