Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unnecessary bound required when deriving recursively #1244

Closed
WiSaGaN opened this issue May 5, 2018 · 1 comment
Closed

Unnecessary bound required when deriving recursively #1244

WiSaGaN opened this issue May 5, 2018 · 1 comment
Labels

Comments

@WiSaGaN
Copy link
Contributor

WiSaGaN commented May 5, 2018

#[macro_use]
extern crate serde;

trait Foo { 
    type FooT;
}

#[derive(Serialize)]
struct Bar<T> { 
    bar: T, 
}

#[derive(Serialize)] 
struct Baz<T: Foo> {
    baz: Bar<T::FooT>,
}

This fails to compile on 1.25.0.

error[E0277]: the trait bound `<T as Foo>::FooT: serde::Serialize` is not satisfied
  --> src/lib.rs:13:10
   |
13 | #[derive(Serialize)]
   |          ^^^^^^^^^ the trait `serde::Serialize` is not implemented for `<T as Foo>::FooT`
   |
   = help: consider adding a `where <T as Foo>::FooT: serde::Serialize` bound
   = note: required because of the requirements on the impl of `serde::Serialize` for `Bar<<T as Foo>::FooT>`
   = note: required by `serde::ser::SerializeStruct::serialize_field`

error: aborting due to previous error

This seems similar to rust-lang/rust#31518, but if we change Serialize to Clone it would work.

@dtolnay
Copy link
Member

dtolnay commented May 5, 2018

Your code would compile if Serde were to infer a bound of <T as Foo>::FooT: Serialize but I believe this would be a breaking change because it is not clear that Bar needs to serialize T::FooT. For example the following currently works without that bound.

type Bar<T> = PhantomData<T>;

#[derive(Serialize)] 
struct Baz<T: Foo> {
    baz: Bar<T::FooT>,
}

but if we change Serialize to Clone it would work.

The derived Clone impl compiles by itself but falls apart when you try to use it. As discussed in rust-lang/rust#26925, with the current derive API it is impossible to tell what the right bounds should be. For example:

trait Foo { 
    type FooT;
}

#[derive(Clone)]
struct Bar<T> { 
    bar: T, 
}

#[derive(Clone)] 
struct Baz<T: Foo> {
    baz: Bar<T::FooT>,
}

fn main() {
    struct S;

    impl Foo for S {
        type FooT = usize;
    }

    // Should be clonable because T::FooT = usize is clonable.
    let baz = Baz::<S> { baz: Bar { bar: 0 } };
    baz.clone();
}
error[E0599]: no method named `clone` found for type `Baz<main::S>` in the current scope
  --> src/main.rs:23:9
   |
11 | struct Baz<T: Foo> {
   | ------------------ method `clone` not found for this
...
23 |     baz.clone();
   |         ^^^^^
   |
   = note: the method `clone` exists but the following trait bounds were not satisfied:
           `Baz<main::S> : std::clone::Clone`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `clone`, perhaps you need to implement it:
           candidate #1: `std::clone::Clone`

As a workaround you could provide the right bound:

#[derive(Serialize)] 
#[serde(bound(serialize = "T::FooT: Serialize"))]
struct Baz<T: Foo> {
    baz: Bar<T::FooT>,
}

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

No branches or pull requests

2 participants