Reputation: 38238
Consider the following code:
pub trait Trait {
type Type;
const CONST: Self::Type;
}
impl<T> Trait for T {
type Type = u8;
const CONST: u8 = 42;
}
My (incorrect?) understanding of Rust is that this code should work and that all Sized
types should now implement Trait
and have an associated type (Type = u8
) and const (CONST = 42
). Unsized types shouldn't implement this trait since impl<T>
implicitly assumes T
to be Sized
.
However, when I try to compile the code I get the error message:
error[E0277]: the size for value values of type `T` cannot be known at compilation time
--> src/main.rs:8:3
|
8 | const CONST: u8 = 42;
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types--sized>
= help: consider adding a `where T: std::marker::Sized` bound
= note: required because of the requirements on the impl of `Trait` for `T`
My questions:
T
isn't Sized
here? Explicitly stating T: Sized
doesn't help.T
isn't Sized
. Why does Rust care whether T
is sized or not here? Nothing depends on it, as far as I can tell (the associated type and const aren't related to T
). Changing the code to T: ?Sized
works, so clearly T
being unsized isn't actually problematic.Upvotes: 5
Views: 905
Reputation: 23647
According to this GitHub issue, this appears to be a known bug that has been around at least since Rust 1.23 (longer, I suspect).
It is not clear what is causing the problem and when/if it will be fixed. There is only a rather vague hypothesis:
I'm not familiar with the compiler internals, but my hypothesis is that associated types and constants depending on a type parameter are not evaluated properly in the constant expression evaluator. In this case, it's associated types that do not reduce well:
const VAL: Self::T = 5;
forces Rust to do some fancy type of computation at compile time in order to type check, but there's a bug in the code for such computations.
There are a few ways to work around the issue:
Specifying a concrete type in the trait:
pub trait Trait {
// type Type; // no longer used
const CONST: u8;
}
Opting T
out of Sized
:
impl<T: ?Sized> Trait for T {
type Type = u8;
const CONST: u8 = 42;
}
Use a function instead of a constant (credit goes to @PeterHall):
pub trait Trait {
type Type;
fn const_val() -> Self::Type;
}
impl<T> Trait for T {
type Type = u8;
fn const_val() -> Self::Type { 42 }
}
Upvotes: 2