简体   繁体   中英

How to solve “cycle detected when computing the supertrait”?

I have a trait Component with an associated type Msg :

trait Component {
    type Msg;
    fn update(&self, msg: Self::Msg);
}

I modified it to implement a clone:

trait Component: ComponentClone<Self::Msg> {
    type Msg;
    fn update(&self, msg: Self::Msg);
}

pub trait ComponentClone<T> {
    fn clone_box(&self) -> Box<dyn Component<Msg = T>>;
}

impl<T, M> ComponentClone<M> for T
where
    T: 'static + Component<M> + Clone,
{
    fn clone_box(&self) -> Box<dyn Component<M>> {
        Box::new(self.clone())
    }
}

impl<M: 'static> Clone for Box<dyn Component<M>> {
    fn clone(&self) -> Box<dyn Component<M>> {
        self.clone_box()
    }
}

playground

I got an error:

error[E0391]: cycle detected when computing the supertraits of `Component`
 --> src/lib.rs:1:1
  |
1 | trait Component: ComponentClone<Self::Msg> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: ...which again requires computing the supertraits of `Component`, completing the cycle
note: cycle used when collecting item types in top-level module
 --> src/lib.rs:1:1
  |
1 | trait Component: ComponentClone<Self::Msg> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If I try to use generics, everything compiles (but I do get warnings):

trait Component<M>: ComponentClone<M> {
    fn update(&self, msg: M);
}

pub trait ComponentClone<T> {
    fn clone_box(&self) -> Box<dyn Component<T>>;
}

impl<T, M> ComponentClone<M> for T
where
    T: 'static + Component<M> + Clone,
{
    fn clone_box(&self) -> Box<dyn Component<M>> {
        Box::new(self.clone())
    }
}

impl<M: 'static> Clone for Box<dyn Component<M>> {
    fn clone(&self) -> Box<dyn Component<M>> {
        self.clone_box()
    }
}

What's wrong? How to solve this problem?

While the code given contains other errorrs I'll focus on the question in particular situation.

When you have a trait bound which depends on an associated type in the trait being defined, provide a full path (aka UFCS) to the associated type:

trait Component: ComponentClone<<Self as Component>::Msg> {
    //                          ^^^^^^^^^^^^^^^^^^^^^^^^ use a full path to Msg
    type Msg;
    fn update(&self, msg: Self::Msg);
}

pub trait ComponentClone<T> {
    /* snip */
}

Related issue rust-lang/rust#62581 "Cycle computing supertraits" error could be more helpful #62581

Maybe you can get away by moving Msg into an own trait:

pub trait ComponentMsg {
    type Msg;
}

pub trait Component : ComponentClone + ComponentMsg {
    fn update(&self, msg: Self::Msg);
}

pub trait ComponentClone : ComponentMsg {
    fn clone_box(&self) -> Box<dyn Component<Msg=Self::Msg>>;
}

impl<T, M> ComponentClone for T
where
    T: 'static + Component<Msg=M> + Clone,
{
    fn clone_box(&self) -> Box<dyn Component<Msg=M>> {
        Box::new(self.clone())
    }
}

impl<M: 'static> Clone for Box<dyn Component<Msg=M>> {
    fn clone(&self) -> Box<dyn Component<Msg=M>> {
        self.clone_box()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM