How does Rust know to disallow non static borrows for Sender<T>::send?


#1
struct Foo;
fn main() {
    let (tx, rx)= std::sync::mpsc::channel::<&Foo>();
    let jg = std::thread::spawn(move ||{
        let tx = tx;
        let foo = Foo;
        tx.send(&foo); //How does Rust know that this is illegal?
    });
}

https://is.gd/rQ13Oa

It is easy to see that this can not be legal but how does Rust actually know that this is illegal?

pub fn send(&self, t: T) -> Result<(), SendError<T>> ;

There are no lifetimes and no restrictions on T but Rust still disallows a non static borrow into .send.


#2

The 'static bound gets added by thread::spawn


#3

But how can it be added if there are no restrictions on T inside spawn itself? Also it fails to build without thread::spawn

https://is.gd/NrJc7w

struct Foo;
fn main() {
    let (tx, rx) = std::sync::mpsc::channel::<&Foo>();
    let foo = Foo;
    tx.send(&foo); //How does Rust know that this is illegal?
}

There must be some lifetime inference magic here.


#4

That one builds fine if you put let foo = Foo; one line earlier.

There is a lifetime, but you’re not seeing it and it’s inferred. std::sync::mpsc::channel::<&Foo> actually means std::sync::mpsc::channel::<&'unnamed Foo>. This means your channels must live as long as the references your putting in it.

When you pass your channel to spawn, through the closure the bound F: 'static gets applied to the Sender. This will force the unspecified lifetime to also be static.

Compare with a named lifetime parameter: https://is.gd/4OKqLs