Skip to content

Lifetime inference with stack-boxed trait objects of unboxed closures #19564

@netvl

Description

@netvl

This works:

#![feature(unboxed_closures)]

fn f1(i: i32) -> i32 { i * 2 }

fn main() {
    let mut arr: Vec<&Fn(i32) -> i32> = Vec::new();
    let p1 = &f1; 
    arr.push(p1);
    arr[0].call((1, ));
}

This doesn't, which is surprising:

#![feature(unboxed_closures)]

fn f1(i: i32) -> i32 { i * 2 }

fn main() {
    let mut arr: Vec<&Fn(i32) -> i32> = Vec::new();
    arr.push(&f1);
    arr[0].call((1, ));
}
test.rs:7:15: 7:17 error: borrowed value does not live long enough
test.rs:7     arr.push(&f1);
                        ^~
test.rs:5:11: 9:2 note: reference must be valid for the block at 5:10...
test.rs:5 fn main() {
test.rs:6     let mut arr: Vec<&Fn(i32) -> i32> = Vec::new();
test.rs:7     arr.push(&f1);
test.rs:8     arr[0].call((1, ));
test.rs:9 }
test.rs:7:5: 7:19 note: ...but borrowed value is only valid for the statement at 7:4
test.rs:7     arr.push(&f1);
              ^~~~~~~~~~~~~~
test.rs:7:5: 7:19 help: consider using a `let` binding to increase its lifetime
test.rs:7     arr.push(&f1);
              ^~~~~~~~~~~~~~

The bigger problem is that this does not work as well:

#![feature(unboxed_closures)]

fn main() {
    let mut arr: Vec<&Fn(i32) -> i32> = Vec::new();
    arr.push(&|x| x * 4);
    arr[0].call((1, ));
}
test.rs:5:15: 5:24 error: borrowed value does not live long enough
test.rs:5     arr.push(&|x| x * 4);
                        ^~~~~~~~~
test.rs:3:11: 7:2 note: reference must be valid for the block at 3:10...
test.rs:3 fn main() {
test.rs:4     let mut arr: Vec<&Fn(i32) -> i32> = Vec::new();
test.rs:5     arr.push(&|x| x * 4);
test.rs:6     arr[0].call((1, ));
test.rs:7 }
test.rs:5:5: 5:26 note: ...but borrowed value is only valid for the statement at 5:4
test.rs:5     arr.push(&|x| x * 4);
              ^~~~~~~~~~~~~~~~~~~~~
test.rs:5:5: 5:26 help: consider using a `let` binding to increase its lifetime
test.rs:5     arr.push(&|x| x * 4);
              ^~~~~~~~~~~~~~~~~~~~~

And there is no workaround - I can't bind the closure to a separate variable because a lot of type inference issues arise, most notably is that closure is interpreted as an old closure (and I don't know how to force it to be interpreted as a new one).

Discovered in this SO question.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lifetimesArea: Lifetimes / regions

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions