Mismatched types error on associated type and trait objects

I was trying to make a brief demo of a HTTP/HTTPS server, and came into a strange compiler error. I will show a simplified version of my code below to illustrate the problem.
First I'd like to create a Listener trait, which will be implemented by stuff like TcpListener or UdpListener. The trait is simple:

trait Listener {
    type Conn;
    fn accept(&self) -> Self::Conn;
}

Next I want to make a TlsListener . Considering a TLS connection should be based on an established TCP connection, it should contain an underlying Listener, like:

struct TlsListener<Ln>
where
    Ln: Listener,
{
    ln: Ln,
}

Now I need to implement Listener trait for it, and that's when error occurs. I will replace the actual accept logic with some test code, and the lines commented with "not ok" will lead to an error:

fn test(_t: Pin<Box<dyn Unpin + 'static>>) {}
fn test_ref(_t: &Pin<Box<dyn Unpin + 'static>>) {}

impl<Ln> Listener for TlsListener<Ln>
where
    Ln: Listener,
    Ln::Conn: Unpin + 'static,
{
    type Conn = ();
    fn accept(&self) {
        // ok
        let conn = self.ln.accept();
        test(Box::pin(conn));

        // not ok
        let conn1 = self.ln.accept();
        test_ref(&Box::pin(conn1));
        
        // ok
        let conn2 = self.ln.accept();
        let boxed_conn2 = Box::new(conn2);
        test_ref(&Pin::new(boxed_conn2));
    }
}

The error log is:

error[E0308]: mismatched types
   --> src/main.rs:94:18
    |
94  |         test_ref(&Box::pin(conn1));
    |         -------- ^^^^^^^^^^^^^^^^ expected `&Pin<Box<dyn Unpin>>`, found `&Pin<Box<<Ln as Listener>::Conn>>`
    |         |
    |         arguments to this function are incorrect
    |
    = note: expected reference `&Pin<Box<(dyn Unpin + 'static)>>`
               found reference `&Pin<Box<<Ln as Listener>::Conn>>`
note: function defined here
   --> src/main.rs:108:4
    |
108 | fn test_ref(_: &Pin<Box<dyn Unpin + 'static>>) {}
    |    ^^^^^^^^ ----------------------------------
help: consider constraining the associated type `<Ln as Listener>::Conn` to `(dyn Unpin + 'static)`
    |
77  |     Ln: Listener<Conn = (dyn Unpin + 'static)>,
    |                 ++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0308`.

I wonder why it won't work after adding a reference, and why it becomes available again once I've seperated the Box and Pin operations.

Some bad order of inference is going on. You can't coerce a &Box<T> or a &Pin<Box<T>> to a &Box<dyn Trait> or &Pin<Box<dyn trait>> because of too much indirection. So the compiler decided you had created a &Pin<Box<AssocType>> before it tried to coerce it.

See also this issue.

This change clues the compiler in that a coercion needs to happen before taking the reference.

        test_ref(&{ Box::pin(conn1) as _});

Or just...

        test_ref(&Pin::new(Box::new(conn1)));
1 Like