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

Typecheck error in body of async fn reported at point-of-use

Open
bdonlan opened this issue Jun 25, 2020 · 3 comments
Open

Typecheck error in body of async fn reported at point-of-use #73737

bdonlan opened this issue Jun 25, 2020 · 3 comments
Labels
A-async-await AsyncAwait-Triaged C-bug T-compiler

Comments

@bdonlan
Copy link
Contributor

bdonlan commented Jun 25, 2020

I tried this code:

use std::marker::PhantomData;
use std::io;

use tokio; // 0.2.21
use tokio_util; // 0.3.1

use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio_util::codec::{Encoder, Decoder};
use futures::stream::StreamExt;

use bytes::{BytesMut, Bytes};

struct Codec;

struct Message<'a> { _p: PhantomData<&'a u8> }

impl Encoder<Message<'static>> for Codec {
    type Error = io::Error;
    
    fn encode(&mut self, item: Message<'static>, dst: &mut BytesMut) -> Result<(), Self::Error> {
        todo!()
    }
}

impl Decoder for Codec {
    type Item = Message<'static>;
    type Error = io::Error;
    
    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        todo!()
    }
}

async fn forwarder(sock: impl AsyncRead + AsyncWrite + Send + 'static) {
    let sock = Codec.framed(sock);
    let (sink, stream) = sock.split();
    
    stream.map(|msg| msg).forward(sink).await;
}

pub fn assert_send() {
    let s : TcpStream = todo!();
    let _b : Box<dyn Send> = Box::new(forwarder(s));
}

I expected to see this happen: A diagnostic would be issued at the line with the .forward call (or not at all).

Instead, this happened:

error[E0308]: mismatched types
  --> src/lib.rs:44:30
   |
44 |     let _b : Box<dyn Send> = Box::new(forwarder(s));
   |                              ^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected type `std::ops::FnOnce<(std::result::Result<Message<'static>, std::io::Error>,)>`
              found type `std::ops::FnOnce<(std::result::Result<Message<'_>, std::io::Error>,)>`

As you can see, this is reporting a typecheck error occurring in the implementation of forwarder, at the point of use of the async fn (where its implementation should be opaque).

Meta

Tested on the playground with both stable and nightly.

@bdonlan bdonlan added the C-bug label Jun 25, 2020
@jonas-schievink jonas-schievink added the A-async-await label Jun 25, 2020
@bdonlan
Copy link
Contributor Author

bdonlan commented Jun 25, 2020

Adding a coercion to force the stream type to use a Message<'static> fixes this issue, so apart from the diagnostic being issued in the wrong place I would expect the lifetime checker to accept this code:

use std::marker::PhantomData;
use std::io;

use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio_util::codec::{Encoder, Decoder};
use futures::stream::{Stream, StreamExt};

use bytes::BytesMut;

struct Codec;

struct Message<'a> { _p: PhantomData<&'a u8> }

impl Encoder<Message<'static>> for Codec {
    type Error = io::Error;
    
    fn encode(&mut self, item: Message<'static>, dst: &mut BytesMut) -> Result<(), Self::Error> {
        todo!()
    }
}

impl Decoder for Codec {
    type Item = Message<'static>;
    type Error = io::Error;
    
    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        todo!()
    }
}

fn coerce(s: impl Stream<Item=io::Result<Message<'static>>>) -> impl Stream<Item=io::Result<Message<'static>>> { s }

async fn forwarder(sock: impl AsyncRead + AsyncWrite + Send + 'static) {
    let sock = Codec.framed(sock);
    let (sink, stream) = sock.split();
    
    coerce(stream.map(|msg| msg)).forward(sink).await;
}

#[allow(unreachable_code)]
pub fn assert_send() {
    let s : TcpStream = todo!();
    // The diagnostic emitted here should be reported in the body of forwarder itself.
    let _b : Box<dyn Send> = Box::new(forwarder(s));
}

@JohnTitor JohnTitor added the T-compiler label Jun 26, 2020
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jun 30, 2020

This is likely to be a duplicate of #64552

@nikomatsakis nikomatsakis added the AsyncAwait-Triaged label Jun 30, 2020
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jun 30, 2020

Marking as triaged and a likely duplicate of #64552

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await AsyncAwait-Triaged C-bug T-compiler
Projects
None yet
Development

No branches or pull requests

4 participants