# Bounds when deriving on PhantomData

**URL:** <https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149>\
**Category:** libs\
**Created:** [February 16, 2022, 1:28am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149 "2022-02-16T01:28:08Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![PO8](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/po8/32/5588_2.png) [@PO8](https://internals.rust-lang.org/u/PO8)\
**Post date:** [February 16, 2022, 1:28am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/1 "2022-02-16T01:28:08Z")

</div>

Having read [#[derive] sometimes uses incorrect bounds · Issue #26925 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/issues/26925), I agree that in general getting proper type bounds for `#[derive(...)]` is a can of worms. There's one special case I'm thinking about posting an issue for, though: `PhantomData<T>`. This type is already treated "specially"; I think that given its strong guarantee that `T` plays no role in any usage of the type things like this

```rust
use std::marker::PhantomData;
#[derive(Default)]
struct S<T>(PhantomData<T>);

```

should produce an implementation of `Default` with no bounds on `T` like this

```rust
impl<T> Default for S<T> {
    fn default() -> Self {
        Self(PhantomData)
    }
}

```

Presumably this would require modifying the derive macro to treat `PhantomData` specially. I don't know how difficult that would be.

Thoughts? Is this a good idea? Is it worth doing?

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [February 16, 2022, 1:44am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/2 "2022-02-16T01:44:58Z")

</div>

It cannot be done AFAIK because the macro cannot resolve the name.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 16, 2022, 2:07am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/3 "2022-02-16T02:07:06Z")

</div>

> [@PO8](#):
>
> Presumably this would require modifying the derive macro to treat `PhantomData` specially.

The macros right now _don't look at the field types at all_.

The only things the std derives do is bound the list of generic type parameters.

(That's intentional, because that way changing the field types can't change the bounds. Though it's often not what people want, in more complicated situations.)

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [February 16, 2022, 9:42am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/4 "2022-02-16T09:42:22Z")

</div>

I wonder to what extent we could get the trait system to solve this? What if `#[derive(Default)]` on a struct had an implicit bound of `FieldType: Default` for every field? Then, this would have a bound of `PhantomData<T>: Default`, which in turn doesn't actually need `T: Default`. Similarly, `Option<T>: Default` doesn't need `T: Default`. But `[T; 4]: Default` would require `T: Default`.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [February 16, 2022, 10:02am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/5 "2022-02-16T10:02:28Z")

</div>

It does not work when the field type is private.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 16, 2022, 10:27am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/6 "2022-02-16T10:27:14Z")

</div>

> [@chrefr](#):
>
> when the field type is private

We could just make that work.

You can already bound on non-exported traits (using some pub-in-a-private-module trick), so bounding on non-exported types would be no big deal.

EDIT: Oh, I think we might have already done that: [https://github.com/rust-lang/rust/pull/90586#issuecomment-977034675](https://github.com/rust-lang/rust/pull/90586#issuecomment-977034675) (I thought it sounded familiar...)

> [@josh](#):
>
> to solve this?

That's a breaking change, because I can do this today: [https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b67320d076991cb7e5732fc2fd7c8212](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b67320d076991cb7e5732fc2fd7c8212)

```rust
#[derive(Default)]
struct Foo<T>(Option<T>);

struct NotDefaultType;

impl Default for Foo<NotDefaultType> {
    fn default() -> Self { Self(Some(NotDefaultType)) }
}

```

So it would need an opt-in of some sort.

(And even in cases where it's not _directly_ breaking, it's potentially scary. Weakening the requirements might be logically incorrect, and that might be really really bad if there's unsafe code that's only sound today _because_ of the current bounds.)

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [February 16, 2022, 11:54am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/7 "2022-02-16T11:54:08Z")

</div>

EventuallyTM I want to write an RFC that would permit arbitrary tokens to be provided as a parameter to derives. The built-in macros could then do `#[derive(Default(where T: Default, Option<U>: Default))]` and similar. It would also work for deriving const impls via `#[derive(Default(const))]`. No reason they couldn't be combined (comma-separated), either.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [May 17, 2022, 11:54am UTC](https://internals.rust-lang.org/t/bounds-when-deriving-on-phantomdata/16149/8 "2022-05-17T11:54:46Z")

</div>

Closed on May 17, 2022, 11:54am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
