Search code examples
genericsrusttraitsbounds

Why do I need to add trait bounds on impl blocks if I've already added them to another impl block?


I have the following code:

use std::ops::Div;
use std::ops::Mul;

#[derive(Debug)]
struct Foo<T> {
    bar: T,
}

impl<T> Foo<T>
where
    T: Div<Output = T> + Copy,
{
    fn new(bar: T) -> Foo<T> {
        let baz = Foo::baz(bar);
        Foo { bar: bar / baz }
    }
    fn baz(bar: T) -> T {
        unimplemented!();
    }
}

impl<T> Mul for Foo<T>
where
    T: Mul<Output = T>,
{
    type Output = Foo<T>;

    fn mul(self, other: Foo<T>) -> Foo<T> {
        Foo::new(self.bar * other.bar)
    }
}

However, the compiler complains:

error[E0277]: cannot divide `T` by `T`
  --> src/main.rs:29:9
   |
29 |         Foo::new(self.bar * other.bar)
   |         ^^^^^^^^ no implementation for `T / T`
   |
   = help: the trait `std::ops::Div` is not implemented for `T`
   = help: consider adding a `where T: std::ops::Div` bound
note: required by `<Foo<T>>::new`
  --> src/main.rs:13:5
   |
13 |     fn new(bar: T) -> Foo<T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
  --> src/main.rs:29:9
   |
29 |         Foo::new(self.bar * other.bar)
   |         ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
   |
   = help: consider adding a `where T: std::marker::Copy` bound
note: required by `<Foo<T>>::new`
  --> src/main.rs:13:5
   |
13 |     fn new(bar: T) -> Foo<T> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^

This can be fixed with this modification:

impl<T> Mul for Foo<T>
where
    T: Mul<Output = T> + Div<Output = T> + Copy,

Why do I need to add Div<Output = T> and Copy to Mul for Foo<T>? Shouldn't Foo<T> already satisfy the bounds because of:

impl<T> Foo<T>
where
    T: Div<Output = T> + Copy,

Solution

  • Each impl block is completely distinct from each other, including their trait bounds — the fact that one impl block has a constraint means nothing to the others.

    In this case, your impl block for the trait Mul doesn't really need the Div trait, as it could construct the Foo directly:

    impl<T> Mul for Foo<T>
    where
        T: Mul<Output = T>,
    {
        type Output = Foo<T>;
    
        fn mul(self, other: Foo<T>) -> Foo<T> {
            Foo { bar: self.bar * other.bar }
        }
    }
    

    It is only because you have chosen to call Foo::new (which has the Div and Copy requirements) that your original version of Mul will not compile. This is conceptually the same problem as this plain function which also doesn't need Copy or Div:

    fn x<T>(a: T) -> Foo<T> {
        Foo::new(a)
    }
    

    Note that I've said "impl block", not "inherent impl block" or "trait impl block". You can have multiple inherent impl blocks with different bounds:

    impl<T> Vec<T> {
        pub fn new() -> Vec<T> { /* ... */ }
    }
    
    impl<T> Vec<T>
    where
        T: Clone,
    {
        pub fn resize(&mut self, new_len: usize, value: T) { /* ... */ }
    }
    

    This allows a type to have functions that only apply when certain conditions are met.

    See also: