Unconstrained type when abstracting over Vec<T> or &[&T]


#1

I’m trying to avoid unnecessary clones in my application by abstracting over owned/borrowed slices and vectors.

i.e.

  • Vec<T>
  • Vec<&T>
  • &[T]
  • &[&T]

So I’m writing an impl for my trait which affects anything which is AsRef<[F]> where F: Foo.

trait Foo {
    fn bar(&self) -> u32;
}

impl Foo for u32 {
    fn bar(&self) -> u32 {
        *self
    }
}

impl<S, F> Foo for S
where
    S: AsRef<[F]>,
    F: Foo,    // <- "unconstrained" type
{
    fn bar(&self) -> u32 {
        self.as_ref().map(|f| f.bar()).sum()
    }
}

The F type parameter is obviously constrained to implement Foo in the where clause, however for some reason the compiler keeps giving me an “Unconstrained Type Error”. Has anyone else ever encountered these sorts of esoteric type errors?

(playpen link)


#2

It is unconstrained since since the structure filling the generic S is free to implement AsRef multiple times.

My attempt to get something working failed. (Trying to make function generic.)
A macro may well be one way. Not tried and daunting trying to think what the code would be.


#3

There would be a second issue here which is the blanket impl can overlap with the u32 impl.

What you can do is impl a function generically that allows abstracting over this:

trait Foo {
    fn bar(&self) -> u32;
}

impl Foo for u32 {
    fn bar(&self) -> u32 {
        *self
    }
}

impl<'a, F> Foo for &'a F
where
    F: Foo,
{
    fn bar(&self) -> u32 {
        (*self).bar()
    }
}

fn call_bar<A: AsRef<[F]>, F: Foo>(f: A) -> u32 {
    f.as_ref().iter().map(|b| b.bar()).sum()
}

fn main() {
    let accepts_vec = call_bar(vec![1, 2, 3]);
    println!("{}", accepts_vec);
    let and_slices = call_bar(&[1u32, 2, 3]);
    println!("{}", and_slices);
    let vec_of_references = call_bar(vec![&1, &2, &3]);
    println!("{}", vec_of_references);
}