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

Borrowing issue with impl Trait leads to unergonomic verbosity #37790

Open
Boscop opened this Issue Nov 15, 2016 · 2 comments

Comments

Projects
None yet
4 participants
@Boscop
Copy link

Boscop commented Nov 15, 2016

#![feature(conservative_impl_trait)]

struct A {
    v: Vec<usize>
}
impl A {
	fn foo<'a>(&'a self) -> impl Iterator<Item=usize> + 'a {
		(0..self.v.len()).map(move |i| self.v[i])
	}
}

fn bar() -> A {
    A { v: vec![] }
}

fn baz() -> Vec<usize> {
    /* doesn't work:
    bar().foo().collect::<Vec<_>>()
    */
    
    /* also doesn't work:
    let x = bar();
    x.foo().collect::<Vec<_>>()
    */
    
    // you have to do this:
    let x = bar();
    let x = x.foo();
    x.collect::<Vec<_>>()
}

fn main() {}
error: borrowed value does not live long enough
  --> <anon>:18:5
   |
18 |     bar().foo().collect::<Vec<_>>()
   |     ^^^^^ temporary value created here
...
30 | }
   | - temporary value dropped before borrower
   |
   = note: values in a scope are dropped in the opposite order they are created

error: aborting due to previous error

Here on rust playground

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Nov 15, 2016

The destructors for temporaries in tail expressions run when the containing block ends. The intent is to make braces "transparent". We need good examples for that.

@jimblandy

This comment has been minimized.

Copy link
Contributor

jimblandy commented Feb 7, 2017

I think this is the same problem that we discussed in the user forum a while back.

I believe the error message is incorrect. It is simply not true that the temporary value bar() is dropped before its borrower bar().foo(). If "values in a scope are dropped in the opposite order they are created", then since bar().foo() is necessarily created after bar(), the temporary holding bar().foo() should be dropped before the temporary holding bar(). So the ordering of the drops ought to be fine.

The actual motivation for the error is that, for types that implement Drop, Rust doesn't consider it sufficient for borrowers to be dropped before the values they borrow. The lifetime of the latter must be strictly larger than that of the former. Rust considers the two temporaries holding bar() and bar().foo() to have identical lifetimes, hence the error.

Note that if you change the types to be things without Drop impls, the temporaries' lifetimes are no problem:

struct S(i32);
struct T<'a>(&'a S);

// Uncomment this impl, and the program fails to compile.
// impl<'a> Drop for T<'a> { fn drop(&mut self) { } }

fn foo() -> S { S(42) }

impl S {
    fn bar(&self) -> T { T(self) }
}

impl<'a> T<'a> {
    fn get(&self) -> i32 { (self.0).0 }
}

fn main() {
    let _x = foo().bar().get();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment