Open
Description
The following code causes the latest nightly (2023-05-16) to choke, it can also be seen on the playground.
#![feature(ptr_metadata)]
use core::ptr::Pointee;
struct TypedHandle<E: ?Sized> {
metadata: <E as Pointee>::Metadata,
}
type NodeHandle<T> = TypedHandle<Node<T>>;
struct Node<T> {
element: T,
next: NodeHandle<T>,
prev: NodeHandle<T>,
}
Credits to Chayim Friedman for this reduced example.
And the compiler, much confused it appears, spits out the following error:
error[[E0284]](https://doc.rust-lang.org/nightly/error_codes/E0284.html): type annotations needed
--> src/lib.rs:13:11
|
13 | next: NodeHandle<T>,
| ^^^^^^^^^^^^^ cannot infer type
|
= note: cannot satisfy `<Node<T> as Pointee>::Metadata == _`
note: required because it appears within the type `TypedHandle<Node<T>>`
--> src/lib.rs:5:8
|
5 | struct TypedHandle<E: ?Sized> {
| ^^^^^^^^^^^
= note: only the last field of a struct may have a dynamically sized type
= help: change the field's type to have a statically known size
help: borrowed types always have a statically known size
|
13 | next: &NodeHandle<T>,
| +
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
13 | next: Box<NodeHandle<T>>,
| ++++ +
The compiler accepts the code:
- If the metadata is stored in a
NonNull<E>
inTypedHandle
. - If the
?Sized
bound is removed fromE
inTypedHandle
. - If the
where NodeHandle<T>: Sized
bound is added onNode
.
Given the messages, and the fixes, it appears that the compiler fails to realize that <E as Pointee>::Metadata
is always Sized
, regardless of whether E
is Sized
or not, even though Metadata
is necessarily Sized
since its bounds do not specify ?Sized
. This in turn would lead the compiler to expect that TypedHandle
may be unsized, and thus reject any code where it is not the last field of a struct.