Type doesn't seem to match itself

Here's an isolated testcase which doesn't compile and I can't see why: Rust Playground

The type variable is set to be TheEvent, so it should be the same. Moreover, the error goes away if one seemingly unrelated restriction is relaxed (see top)

After fixing the syntax errors for the "working" version, I get the same error playground.

1 Like

Sorry, forgot to roll back some test changes: Rust Playground

After looking at it a little more, I'm not entirely sure why the code doesn't compile. However I noticed that it is a little weird.
CanSubscribe has AsyncEventMachine as a supertrait. So every struct that implements CanSubscribe also implements AsyncEventMachine. The definition of AsyncEventMachine::new_subscription specifies that Self: CanSubscribe. This means, that the method new_subscription in the supertrait is only available for types implementing CanSubscribe.
I think it would be better to put new_subscription into CanSubscriber as the Self: CanSubscribe bound is then explicit, and you can still access the functionality offered by AsyncEventMachine as it's a supertrait.

pub trait CanSubscribe<Producer: AsyncEventMachine>: AsyncEventMachine {
    fn new_subscription(&self) -> ();

pub struct SimpleTokioMachine<TheEvent> {
	pair_out_sender: TheEvent,

pub trait AsyncEventMachine {
	type InEvent;

impl<TheEvent> AsyncEventMachine for SimpleTokioMachine<TheEvent> {
    type InEvent = TheEvent;

impl<TheEvent, Producer: AsyncEventMachine> CanSubscribe<Producer> for SimpleTokioMachine<TheEvent> {
	fn new_subscription(&self) -> ()
	    // These two types should be the same, as InEvent=TheEvent
	    let ev: &<SimpleTokioMachine<TheEvent> as AsyncEventMachine>::InEvent = &self.pair_out_sender;


1 Like

It's outside the testcase, but I want AsyncEventMachine to implement event transport, once in new_subscription, and implement event conversion only for every CanSubscribe. So I don't see a way to do this without a generic trait method.

I'm not quite sure I understand what you mean. If you want to have the new_subscription method be generic instead of the trait, that is possible like so.

My guess is that, because rustc prefers to use where clauses for trait resolution, it is somehow looking through CanSubscribe<Producers> to the AsyncEventMachine supertrait instead of consulting the implementation currently being defined, and then fails to normalize.

Perhaps this illustrates my guess better than English.

See Issue 24066 and the various issues it links to.

1 Like

Here's a possible workaround for &self methods.

I'm also wondering if this is yet another manifestation of the various guises of the projection-and-normalization family of bugs…?

1 Like

It's certainly related, or at least a shortcoming around handling cycles in normalization and/or trait resolution... I also tried threading the associated type through ala IntoIterator:

pub trait CanSubscribe<Producer: AsyncEventMachine>
    Self: AsyncEventMachine<InEvent = <Self as CanSubscribe<Producer>>::CsEvent>
    type CsEvent;

However, that still results in a normalization failure on its own when using

let ev: &<Self as CanSubscribe<Producer>>::CsEvent = &self.pair_out_sender;

And attempting to add this

	fn new_subscription<Producer: AsyncEventMachine>(&self) -> ()
		Self: CanSubscribe<Producer, CsEvent=Self::InEvent>,


error[E0391]: cycle detected when computing the bounds for type parameter `Self`

Which is probably a valid complaint in the general case, but we're really just trying to get the compiler to see a type equivalence indirectly.

Writing that out gave me a couple other ideas for work-arounds though.

1 Like

The first idea was to move the associated type into a separate trait that was a supertrait for the other two. But it still failed to normalize.

The second idea was to put the problematic method in its own trait, where the bounds were on the trait not the method. That also still failed to normalize.

These two are less ambiguously normalization bugs IMO.

1 Like

This is Issue 38071 more directly.


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.