Is this a compiler bug that the trait bound is not satisfied but the type does implement the trait?

The compiler seems to result in a wrong result when checking the trait bound for the following example:

use tun::{ TunPacket,TunPacketCodec};
use tokio_util::codec::Encoder;

fn is_satisfy<F:Encoder<TunPacket>>(_:F){}

fn main() {
	let r = TunPacketCodec::new(true, 1500);
	is_satisfy(r);  // #1
}

The compiler complains that

the trait bound TunPacketCodec: Encoder<TunPacket> is not satisfied

However, the trait Encoder<TunPacket> is implemented by TunPacketCodec in its crate

impl Encoder<TunPacket> for TunPacketCodec {
    type Error = io::Error;

    fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
        dst.reserve(item.get_bytes().len() + 4);
        match item {
            TunPacket(proto, bytes) if self.0 => {
                // build the packet information header comprising of 2 u16
                // fields: flags and protocol.
                let mut buf = Vec::<u8>::with_capacity(4);

                // flags is always 0
                buf.write_u16::<NativeEndian>(0).unwrap();
                // write the protocol as network byte order
                buf.write_u16::<NetworkEndian>(proto.into_pi_field()?)
                    .unwrap();

                dst.put_slice(&buf);
                dst.put(bytes);
            }
            TunPacket(_, bytes) => dst.put(bytes),
        }
        Ok(())
    }
}

This error emitted by the compiler is strange. I don't know why. Is this a bug of trait bound check of the compiler?

The dependencies are:

[dependencies]
tokio = {version="1.23.0",features = ["macros","rt-multi-thread","net","io-util","time"]}
tun = { version = "0.5.4", features = ["async"] }
futures = "0.3.25"
tokio-util = {version = "0.7.4",features=["codec"]}

It's never a compiler bug1.

You simply have a version mismatch. tun depends on tokio-util 0.6, while you depend on 0.7. And two semver-incompatible versions of the same crate are considered different crates (because they can't co-exist otherwise), so tokio_util<0.6>::Encoder is not the same trait as tokio_util<0.7>::Encoder.


1Of course it's not literally "never", but basic stuff like this has been tested to death. So it's not reasonable to assume a compiler bug first, instead of questioning your own knowledge.

5 Likes

Arguably, the compiler is partially to blame if the compiler error doesn't properly point out that there are multiple versions of the relevant crate present. Perhaps it could even specifically figure out that an equally named trait of a different version is implemented, and mention that too.

10 Likes

All right, so if the versions of two crates on which the other two crates have a dependency are compatible, then there will be no issue here, right?

Then Cargo's version resolution will choose one single crate. There will never be two semver-compatible versions of the same crate selected in the transitive dependency graph.

2 Likes