Compiler bug, or my bug?

I can't decide if this is a compiler bug, a bug in async_trait, or a bug on my part. Based on my reading of the docs on supertraits, I think that this should work correctly, and that I've uncovered a compiler bug, but I want to be sure before I create a reduced test case and submit a bug report.

Basically, I have super and sub traits similar to the following:

use crate::error;
use async_trait::async_trait;
use std::{cmp::Ordering, result::Result};

#[async_trait]
pub trait AsyncFallibleOrdTrait<T>: Send + Sync {
    async fn try_cmp(
        &self,
        other: &dyn AsyncFallibleOrdTrait<T>,
    ) -> Result<Ordering, error::Error<T>>;
}

#[async_trait]
pub trait KeyTrait<T>: AsyncFallibleOrdTrait<T> {}

(heavily reduced from the original code, I can put it all on GitHub if anyone wants it).

I think that based on the docs I should be able to use trait objects that implement KeyTrait anywhere AsyncFallibleOrdTrait is expected. The problem is that doesn't seem to be happening. I have code that is similar to the following:

// original is passed in from elsewhere, trying to reduce code here.
// original: Arc<dyn DBSKeyTrait<T>>;
let k: &dyn KeyTrait<T> = &*Arc::<dyn KeyTrait<T>>::as_ptr(&original);
let order: Ordering = key.try_cmp(k).await?;

Since original is known to implement KeyTrait, and since AsyncFallibleOrdTrait, I thought that this would work, but instead I get an error like the following:

error[E0308]: mismatched types
  --> vec_blob_store/src/vec_store.rs:46:47
   |
46 |             let order: Ordering = key.try_cmp(k).await?;
   |                                               ^ expected trait `AsyncFallibleOrdTrait`, found trait `KeyTrait`
   |
   = note: expected reference `&dyn AsyncFallibleOrdTrait<T>`
              found reference `&dyn KeyTrait<T>`

So is this a genuine error in the compiler, or an error in my understanding of how trait objects work?

I think this is just how (currently!) trait objects work: you can't automatically upcast them, you need to use an explicit method call to do that. There's however work in progress to support this, see Tracking issue for trait upcasting coercion · Issue #65991 · rust-lang/rust · GitHub

5 Likes

Note that questions like this are probably better suited for users.rust-lang.org.

1 Like

This trait design seems a bit questionable in general. I wouldn’t know how to implement it sensibly, there’s not much the callee/implementor can do with the trait object other.

Ah, so option #4, Here There Be Sharp Pointy Edges! :wink:

Thank you for the explanation, now I just need to figure out how I'm going to handle the situation.

Normally I would agree with you, but the real question was whether or not I'd turned up a compiler bug. The docs seem to imply that this should work, and I wanted to know if I should report some kind of compiler/documentation error or not (in addition to the obvious 'how do I fix this hole I'm now in' question).

There's actually quite a bit more going on in the code, including more trait bounds. I was trying to reduce the code as much as possible, so that everyone could read it quickly. If you're really interested in the code, I can put it up on GitHub so you can poke at it. That said, this code is highly experimental at this stage, and will likely change rapidly over time. I like the idea of trait objects due to the flexibility it gives me, but they're proving to be more of a headache at this point than I care to deal with.

Admitted it's probably not as clear as other cases of people using the wrong forum. But the question "is this a problem with my code, with crate xyz or with the compiler, please help me understand" is generally more of a URLO question than an IRLO topic. And once you know it's a compiler bug, it's generally a topic for the issue tracker instead of IRLO. So really, not too close to the usual focus of IRLO at least in my opinion, but I can understand your decision and appreciate the fact that you seem to have given this some though and didn't just post here by mistake :slight_smile:

5 Likes