Skip to content

Type inference/resolution error in the presence of Pointee::Metadata in recursive data-structure #111821

Open
@matthieu-m

Description

@matthieu-m

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> in TypedHandle.
  • If the ?Sized bound is removed from E in TypedHandle.
  • If the where NodeHandle<T>: Sized bound is added on Node.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-inferenceArea: Type inferenceC-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.fixed-by-next-solverFixed by the next-generation trait solver, `-Znext-solver`.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions