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

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>>);

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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