Description
In which we sneakily define a type that contains itself:
(EDIT: Actually, this one didn't depend on specialization. There was previously a default impl of Tr2
not depending on Tr
, but it wasn't necessary. The second one does seem to depend on it.)
trait Tr {
type X;
}
trait Tr2 {
type Y;
}
struct S<T: ?Sized + Tr> {
x: <<T as Tr>::X as Tr2>::Y,
}
impl<T: Tr> Tr2 for T {
type Y = S<T>;
}
impl<T> Tr for T { type X = T; }
fn func<T>() {
let _: S<T> = panic!();
}
fn main() {
func::<u32>();
}
produces:
error: overflow representing the type
S<u32>
This error comes from trans, and it goes away if either the call to func
or func
's usage of S<T>
is commented out. In other words, func
claims to allow instantiation with any type but actually supports no types. (By adding more specializations it could be made to support only certain types.)
A similar issue is when overflow occurs while determining whether a given specialization applies:
#![feature(specialization)]
trait Tr {
type Other;
}
struct S<T>(T);
impl<T> Tr for T {
default type Other = <S<T> as Tr>::Other;
}
impl Tr for S<S<S<S<u32>>>> {
type Other = u32;
}
fn func<T>() {
let _: <T as Tr>::Other = panic!();
}
fn main() {
func::<u32>();
}
This happens to compile, but if the u32
in main is changed to u64
, I get:
error: overflow evaluating the requirement
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<u64>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> as Tr>::Other
Is this a known consequence of specialization? I haven't seen it discussed. It seems to violate Rust's normal policy of type-safe generics, and I'm not sure what a rule to prevent it upfront would look like (especially considering that the patterns can in some cases be split across multiple crates).