15

I'm trying to implement an Octree in Rust. The Octree is generic over a type with a constraint that it should implement a generic trait:

pub trait Generable<U> {
    fn generate_children(&self, data: &U) -> Vec<Option<Self>>;
}

pub enum Octree<T, U>
where
    T: Generable<U>,
{
    Node {
        data: T,
        children: Vec<Box<Octree<T, U>>>,
    },
    Empty,
    Uninitialized,
}

Here is a simplified example reproducing the issue on the Playground

This generates an error:

error[E0392]: parameter `U` is never used
 --> src/main.rs:5:20
  |
5 | pub enum Octree<T, U>
  |                    ^ unused type parameter
  |
  = help: consider removing `U` or using a marker such as `std::marker::PhantomData`

Removing the U from the signature results in "undeclared type name 'U'".

Am I doing something wrong or is it a bug? How to do this properly?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ebvalaim
  • 300
  • 2
  • 13
  • 2
    Looks like a limitation of the compiler, you can probably work around it by playing around with [PhantomData](https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters), adding a "fake" member `PhantomData<*const U>`, while you wait for a more definitive answer. – Matthieu M. Aug 17 '15 at 14:50
  • That helped, thanks. Although it would be nice to be able to use those structures without PhantomData ;) – ebvalaim Aug 17 '15 at 15:05
  • You're welcome :) I'd really like to know if your code is supposed to be rejected or if it's a compiler bug... – Matthieu M. Aug 17 '15 at 15:14
  • I've found an issue on Github that looks similar (https://github.com/rust-lang/rust/issues/26283) and someone there seems to think that it's a limitation of the compiler, but I'm not sure if that's really the same... – ebvalaim Aug 17 '15 at 15:35

1 Answers1

11

I don't believe you want another generic here, you want an associated type:

pub trait Generable {
    type From;
    fn generate_children(&self, data: &Self::From) -> Vec<Option<Self>>
    where
        Self: Sized;
}

pub enum Octree<T>
where
    T: Generable,
{
    Node {
        data: T,
        children: Vec<Box<Octree<T>>>,
    },
    Empty,
    Uninitialized,
}

fn main() {}

As an aside, Vec<Box<Octree<T>>> is probably one level extra of indirection — you can just use Vec<Octree<T>>.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366