英文:
How to best hint at rustc that a recursive data-structure based on Pointee::Metadata is well-formed?
问题
The Rust compiler is encountering an issue with type inference and resolution in the provided code. The error suggests that type annotations are needed, and it points to a situation where it cannot infer the type for next
in the TypedHandle
struct.
This might be related to Rust's restrictions on dynamically sized types in structs. The error message provides some possible solutions, like using NonNull<E>
instead of <E as Pointee>::Metadata
. However, these solutions might impact the code's functionality.
You mentioned that adding a where NodeHandle<T, H>: Sized
bound to Node
resolves the issue but is unwieldy. It's worth noting that Rust's handling of dynamically sized types in structs can sometimes lead to complex situations.
To answer your specific questions:
-
This might not be a known limitation of the compiler but rather a result of how Rust handles dynamically sized types.
-
A better way to solve the problem could depend on the specific requirements of your code. You might want to consider whether the use of dynamically sized types in your design is necessary or if there are alternative approaches that maintain the desired functionality while avoiding the type inference issues.
If you need further assistance or guidance on resolving this issue, feel free to provide more context or ask specific questions.
英文:
The Rust compiler chokes on the following code:
#![feature(ptr_metadata)]
use core::ptr::Pointee;
struct TypedHandle<E: ?Sized, H> {
handle: H,
metadata: <E as Pointee>::Metadata,
}
type NodeHandle<T, H> = TypedHandle<Node<T, H>, H>;
struct Node<T, H> {
element: T,
next: NodeHandle<T, H>,
prev: NodeHandle<T, H>,
}
There seems to be a type inference/type resolution issue, however the notes are all over the place with weirdly seemingly unrelated suggestions:
error[E0284]: type annotations needed
--> src/lib.rs:14:11
|
14 | next: NodeHandle<T, H>,
| ^^^^^^^^^^^^^^^^ cannot infer type
|
= note: cannot satisfy `<Node<T, H> as Pointee>::Metadata == _`
note: required because it appears within the type `TypedHandle<Node<T, H>, H>`
--> src/lib.rs:5:8
|
5 | struct TypedHandle<E: ?Sized, H> {
| ^^^^^^^^^^^
= 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
|
14 | next: &NodeHandle<T, H>,
| +
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
14 | next: Box<NodeHandle<T, H>>,
| ++++ +
Various changes to the code "solve" the error (but break functionality):
- Using
NonNull<E>
instead of<E as Pointee>::Metadata
. This suggests that the recursive nature of the type is not the sole issue. - Removing the
?Sized
bound onE
inTypedHandle
. - Removing one of
next
orprev
. This suggests that the note aboutnext
not being able to be both unsized and non-last field is actually "serious", despite the fact thatTypedHandle
is always sized.
Various changes to the code that do not help:
- Switching
NodeHandle
from type alias to tuple struct. It doesn't help with the error message either.
The only solution I found so far is adding where NodeHandle<T, H>: Sized
bound to Node
, which is quite unwieldy as this bound has to be replicated everywhere afterwards.
- Is this a known limitation of the compiler?
- Is there a better way to solve the problem?
Note: the problem appeared in a custom implementation of LinkedList
as I explore a new allocation API, I worked around it by copy/pasting TypedHandle
into SizedHandle
and removing the ?Sized
bound on E
, which leaves an ugly taste in my mouth, but is easier to fix back than copy/pasted bounds all over the place.
答案1
得分: 1
这是一个每晚的回归问题,由 @lukas-code 在 此 GitHub 评论 中识别的,关于我提出的问题。
在同一评论中,他还建议了一个更轻量级的解决方法:添加一个 _tail: ()
字段,以使编译器认识到类型是有大小的。
特别是,TypedHandle
的定义可以更改为:
struct TypedHandle<E: ?Sized, H> {
handle: H,
metadata: <E as Pointee>::Metadata,
_self_is_always_sized: (),
}
以便解决方法尽可能有限制。
英文:
This is a nightly regression, which @lukas-code identified in this github comment on the I issue raised.
In the very same comment, he also suggests a much more lightweight work-around: adding a _tail: ()
field to make the compiler realize a type is sized.
In particular, the TypedHandle
definition can be changed to:
struct TypedHandle<E: ?Sized, H> {
handle: H,
metadata: <E as Pointee>::Metadata,
_self_is_always_sized: (),
}
So that the work-around is as scoped as possible.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论