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

Multiple impls or where clauses satisfying Ty: Deserialize<'_> found #2418

Closed
ddorstijn opened this issue Mar 25, 2023 · 3 comments
Closed
Labels

Comments

@ddorstijn
Copy link

I have an issue where a struct field is a trait. I tried to use a generic implementation. But now I get an error when using derive, as seen below.

error[E0283]: type annotations needed: cannot satisfy `Ty: Deserialize<'_>`
 --> src\test.rs:7:12
  |
7 | pub struct BatchParameter<Ty: Type> {
  |            ^^^^^^^^^^^^^^^^^^^^^^^^
  |
note: multiple `impl`s or `where` clauses satisfying `Ty: Deserialize<'_>` found
 --> src\test.rs:6:35
  |
6 | #[derive(Debug, Clone, PartialEq, Deserialize)]
  |                                   ^^^^^^^^^^^
7 | pub struct BatchParameter<Ty: Type> {
  |                               ^^^^
note: required for `test::BatchParameter<Ty>` to implement `Deserialize<'de>`
 --> src\test.rs:6:35
  |
6 | #[derive(Debug, Clone, PartialEq, Deserialize)]
  |                                   ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
7 | pub struct BatchParameter<Ty: Type> {
  |            ^^^^^^^^^^^^^^^^^^^^^^^^
  = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

use serde::{de::DeserializeOwned, Deserialize};

pub trait SchemaItem: DeserializeOwned {}
pub trait Type: DeserializeOwned {}

#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct BatchParameter<Ty: Type> {
    pub name: String,
    pub data_type: Ty,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct Batch<Ty: Type> {
    pub description: String,
    pub parameters: Vec<BatchParameter<Ty>>,
}

impl<Ty: Type> SchemaItem for Batch<Ty> {}

#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct Domain<Ty: Type> {
    pub description: String,
    pub data_type: Ty,
    pub default: Option<String>,
}

impl<Ty: Type> SchemaItem for Domain<Ty> {}

If I remove the derive and implement it manually it seems to be fixed (although I haven't tried it when it's fully implemented).

use serde::{de::DeserializeOwned, Deserialize};

pub trait SchemaItem: DeserializeOwned {}
pub trait Type: DeserializeOwned {}

#[derive(Debug, Clone, PartialEq)]
pub struct BatchParameter<Ty: Type> {
    pub name: String,
    pub data_type: Ty,
}

impl<'de, Ty: Type> Deserialize<'de> for BatchParameter<Ty> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de> {
        todo!()
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Batch<Ty: Type> {
    pub description: String,
    pub parameters: Vec<BatchParameter<Ty>>,
}

impl<'de, Ty: Type> Deserialize<'de> for Batch<Ty> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de> {
        todo!()
    }
}

impl<Ty: Type> SchemaItem for Batch<Ty> {}

#[derive(Debug, Clone, PartialEq)]
pub struct Domain<Ty: Type> {
    pub description: String,
    pub data_type: Ty,
    pub default: Option<String>,
}

impl<'de, Ty: Type> Deserialize<'de> for Domain<Ty> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de> {
        todo!()
    }
}

impl<Ty: Type> SchemaItem for Domain<Ty> {}

Is this a bug or am I overseeing something?

@oli-obk
Copy link
Member

oli-obk commented Mar 27, 2023

you can try using cargo expand to see the expanded version of the derives. If you manually copy that expanded version into your code (and remove the derive), do you get a more helpful error message?

I'm assuming this is related to your Type trait, considering the diagnostic points to the Type bound specifically.

@dtolnay
Copy link
Member

dtolnay commented Mar 27, 2023

This is a longstanding rustc bug (rust-lang/rust#34979).

As recommended in https://rust-lang.github.io/api-guidelines/future-proofing.html#c-struct-bounds, you should never write struct BatchParameter<Ty: Type> particularly with a DeserializeOwned bound implied by that bound. You should write struct BatchParameter<Ty>. Then the code compiles.

philippecamacho added a commit to EspressoSystems/hotshot-primitives that referenced this issue May 24, 2023
@tyilo
Copy link

tyilo commented Jun 28, 2023

I have the same issue.

Starting with this code everything works:

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct A<'a>(&'a [u8]);

#[derive(Debug, Serialize, Deserialize)]
struct B;

trait DataInner: {}
impl<'a> DataInner for A<'a> {}
impl DataInner for B {}

#[derive(Debug, Serialize, Deserialize)]
struct Data<T: DataInner> {
    header: u8,
    inner: T,
}

// C is unrelated to Data/DataInner and so Data<C> should not be a valid type.
#[derive(Debug, Serialize, Deserialize)]
struct C;

Now, I want to enforce that all implementers of the DataInner trait you must also implement Serialize and Deserialize:

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct A<'a>(&'a [u8]);

#[derive(Debug, Serialize, Deserialize)]
struct B;

trait DataInner<'a>: Serialize + Deserialize<'a> {}
impl<'a> DataInner<'a> for A<'a> {}
impl<'a> DataInner<'a> for B {}

#[derive(Debug, Serialize, Deserialize)]
struct Data<'a, T: DataInner<'a>> {
    header: u8,
    inner: &'a T,
}

// C is unrelated to Data/DataInner and so Data<C> should not be a valid type.
#[derive(Debug, Serialize, Deserialize)]
struct C;

This fails to compile with the error:

error[E0283]: type annotations needed: cannot satisfy `T: Deserialize<'a>`
  --> src/main.rs:20:20
   |
20 | struct Data<'a, T: DataInner<'a>> {
   |                    ^^^^^^^^^^^^^
   |
note: multiple `impl`s or `where` clauses satisfying `T: Deserialize<'a>` found
  --> src/main.rs:19:28
   |
19 | #[derive(Debug, Serialize, Deserialize)]
   |                            ^^^^^^^^^^^
20 | struct Data<'a, T: DataInner<'a>> {
   |                    ^^^^^^^^^^^^^
note: required by a bound in `DataInner`
  --> src/main.rs:15:34
   |
15 | trait DataInner<'a>: Serialize + Deserialize<'a> {}
   |                                  ^^^^^^^^^^^^^^^ required by this bound in `DataInner`
   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0283`.
error: could not compile `playground` (bin "playground") due to 3 previous errors

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

4 participants