Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Library for writing const-compatible phantom types with explicit variance and autotrait behavior #21

Closed
@dtolnay

Description

@dtolnay

When writing data structures using unsafe code or otherwise unused type parameters, library authors often reach for PhantomData<T> without adequate consideration.

pub struct IterEmpty<T>(PhantomData<T>);

impl<T> Iterator for IterEmpty<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

You might have missed it (as the standard library did too) that PhantomData<T> is not the right phantom type here. For the empty iterator the phantom type should be Send and Sync regardless of whether T is Send and Sync, as no T ever exists.

The canonical covariant-always-Send-and-Sync type in the standard library is fn() -> T so a library author who realizes PhantomData<T> is not right would write:

pub struct IterEmpty<T>(PhantomData<fn() -> T>);

This is still a bad choice because function pointers can't exist under the conservative const fn feature gate.

impl<T> IterEmpty<T> {
    pub const fn new() -> Self {
        IterEmpty(PhantomData)
    }
}
error: function pointers in const fn are unstable
   --> src/libcore/iter/sources.rs:277:15
    |
277 |     IterEmpty(PhantomData)
    |               ^^^^^^^^^^^

There are hacks; the next step would be

pub struct IterEmpty<T>(PhantomData<PhantomFnWorkaround<T>>);
struct PhantomFnWorkaround<T>(fn() -> T);

and this is ideal in all ways except that it is:

  • nasty to read,
  • nasty to write,
  • nasty to remember,
  • nasty to review.

I want a library for emitting correct const-compatible phantom types (like the last correct solution above) that puts variance and autotrait behavior front and center for readers and reviewers.

pub struct IterEmpty<T>(phantom_data![T, Covariant + AlwaysSendSync]);

It should support any combination of {Covariant, Contravariant, Invariant} × {AlwaysSendSync, NeverSendSync, InheritSendSync}.

Syntax alternative:

#[phantom(Covariant, AlwaysSendSync)]
pub struct IterEmpty<T>(PhantomData);
// expands to
pub struct IterEmpty<T>(PhantomData<$the_crate::CovariantAlwaysSendSync<T>>);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions