Given the following traits and implementations:
trait Wrapper<Type> {
type Inner : Wrapped<Type>;
fn bind<B, F>(self, f: F) -> <B as Wrapped<Type>>::Outer
where B: Wrapped<Type>, F: Fn(Self::Inner) -> <B as Wrapped<Type>>::Outer;
}
trait Wrapped<Type> {
type Outer : Wrapper<Type>;
}
struct Opt;
impl<T> Wrapped<Opt> for T {
type Outer = Option<T>;
}
impl<T> Wrapper<Opt> for Option<T> {
type Inner = T;
fn bind<B, F>(self, f: F) -> <B as Wrapped<Opt>>::Outer
where B: Wrapped<Opt>, F: Fn(Self::Inner) -> <B as Wrapped<Opt>>::Outer {
match self {
Some(a) => f(a),
None => None, // *** fails to compile
}
}
}
It's obvious to a human that the type <B as Wrapped<Opt>>::Outer
must always be Option<B>
, but rustc
can't seem to figure this out:
src/main.rs:47:21: 47:25 error: mismatched types:
expected `<B as Wrapped<Opt>>::Outer`,
found `core::option::Option<_>`
(expected associated type,
found enum `core::option::Option`) [E0308]
src/main.rs:47 None => None,
^~~~
Is there any way to convince it that this is safe? I'd even settle for an unsafe
solution, but mem::transmute
is also not allowed since it can't prove that the types are the same size and aligned (even though there's only one real type involved and not even any newtype wrappers that could mess up alignment).
This is most likely a bug (either this one or that one, I'm not sure). Until it's fixed, I can only think of doing some custom unsafe trickery. Here's a transmute function that does the size equality checks at runtime.
unsafe fn runtime_transmute<T, U>(t: T) -> U {
assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>());
std::ptr::read(&t as *const _ as *const _)
}
now you can replace your None
value with
unsafe { runtime_transmute(None::<T>) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With