From c4f67e679ffa26ce4077aa70ed07257448342eac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 27 Nov 2022 17:23:25 -0800 Subject: [PATCH 1/2] Add ui test of duplicate generics in remote derive --- test_suite/tests/ui/remote/double_generic.rs | 17 ++++++ .../tests/ui/remote/double_generic.stderr | 52 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 test_suite/tests/ui/remote/double_generic.rs create mode 100644 test_suite/tests/ui/remote/double_generic.stderr diff --git a/test_suite/tests/ui/remote/double_generic.rs b/test_suite/tests/ui/remote/double_generic.rs new file mode 100644 index 00000000..0e286a91 --- /dev/null +++ b/test_suite/tests/ui/remote/double_generic.rs @@ -0,0 +1,17 @@ +use serde_derive::{Deserialize, Serialize}; + +mod remote { + pub struct Struct { + pub t: T, + pub u: U, + } +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructGeneric")] +struct StructDef { + t: u8, + u: U, +} + +fn main() {} diff --git a/test_suite/tests/ui/remote/double_generic.stderr b/test_suite/tests/ui/remote/double_generic.stderr new file mode 100644 index 00000000..1a65f100 --- /dev/null +++ b/test_suite/tests/ui/remote/double_generic.stderr @@ -0,0 +1,52 @@ +error: expected one of `:`, `@`, or `|`, found `>` + --> tests/ui/remote/double_generic.rs:12:19 + | +12 | struct StructDef { + | ^ expected one of `:`, `@`, or `|` + +error: expected one of `!`, `)`, `,`, or `::`, found `<` + --> tests/ui/remote/double_generic.rs:12:17 + | +11 | #[serde(remote = "remote::StructGeneric")] + | - + | | + | expected one of `!`, `)`, `,`, or `::` + | help: missing `,` +12 | struct StructDef { + | ^ unexpected token + +error: proc-macro derive produced unparseable tokens + --> tests/ui/remote/double_generic.rs:10:10 + | +10 | #[derive(Serialize, Deserialize)] + | ^^^^^^^^^ + +error: expected one of `!`, `+`, `,`, `::`, or `>`, found `<` + --> tests/ui/remote/double_generic.rs:12:17 + | +10 | #[derive(Serialize, Deserialize)] + | ----------- + | | + | while parsing this item list starting here + | the item list ends here +11 | #[serde(remote = "remote::StructGeneric")] + | - expected one of `!`, `+`, `,`, `::`, or `>` +12 | struct StructDef { + | ^ unexpected token + | +help: you might have meant to end the type parameters here + | +11 | #[serde(remote = "remote::StructGeneric">)] + | + + +error: proc-macro derive produced unparseable tokens + --> tests/ui/remote/double_generic.rs:10:21 + | +10 | #[derive(Serialize, Deserialize)] + | ^^^^^^^^^^^ + +error[E0412]: cannot find type `StructGeneric` in module `remote` + --> tests/ui/remote/double_generic.rs:11:18 + | +11 | #[serde(remote = "remote::StructGeneric")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `remote` From 50354c2d0bb623ff6bb57ba573c6ef3fd4180df6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 27 Nov 2022 17:45:26 -0800 Subject: [PATCH 2/2] Improve error message on remote derive duplicate generics --- serde_derive/Cargo.toml | 2 +- serde_derive/src/internals/check.rs | 23 +++++++++ serde_derive_internals/Cargo.toml | 2 +- .../tests/ui/remote/double_generic.stderr | 51 +------------------ 4 files changed, 27 insertions(+), 51 deletions(-) diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 3db34807..1164ed7f 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -24,7 +24,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = "1.0.90" +syn = "1.0.104" [dev-dependencies] serde = { version = "1.0", path = "../serde" } diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index 0e2484a7..eb1297aa 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -6,6 +6,7 @@ use syn::{Member, Type}; /// Cross-cutting checks that require looking at more than a single attrs /// object. Simpler checks should happen when parsing and building the attrs. pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { + check_remote_generic(cx, cont); check_getter(cx, cont); check_flatten(cx, cont); check_identifier(cx, cont); @@ -16,6 +17,28 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_from_and_try_from(cx, cont); } +/// Remote derive definition type must have either all of the generics of the +/// remote type: +/// +/// #[serde(remote = "Generic")] +/// struct Generic {…} +/// +/// or none of them, i.e. defining impls for one concrete instantiation of the +/// remote type only: +/// +/// #[serde(remote = "Generic")] +/// struct ConcreteDef {…} +/// +fn check_remote_generic(cx: &Ctxt, cont: &Container) { + if let Some(remote) = cont.attrs.remote() { + let local_has_generic = !cont.generics.params.is_empty(); + let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); + if local_has_generic && remote_has_generic { + cx.error_spanned_by(remote, "remove generic parameters from this path"); + } + } +} + /// Getters are only allowed inside structs (not enums) with the `remote` /// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { diff --git a/serde_derive_internals/Cargo.toml b/serde_derive_internals/Cargo.toml index f84a3f52..ee22aa1f 100644 --- a/serde_derive_internals/Cargo.toml +++ b/serde_derive_internals/Cargo.toml @@ -17,7 +17,7 @@ path = "lib.rs" [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0.90", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } +syn = { version = "1.0.104", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/test_suite/tests/ui/remote/double_generic.stderr b/test_suite/tests/ui/remote/double_generic.stderr index 1a65f100..4188b44a 100644 --- a/test_suite/tests/ui/remote/double_generic.stderr +++ b/test_suite/tests/ui/remote/double_generic.stderr @@ -1,52 +1,5 @@ -error: expected one of `:`, `@`, or `|`, found `>` - --> tests/ui/remote/double_generic.rs:12:19 - | -12 | struct StructDef { - | ^ expected one of `:`, `@`, or `|` - -error: expected one of `!`, `)`, `,`, or `::`, found `<` - --> tests/ui/remote/double_generic.rs:12:17 - | -11 | #[serde(remote = "remote::StructGeneric")] - | - - | | - | expected one of `!`, `)`, `,`, or `::` - | help: missing `,` -12 | struct StructDef { - | ^ unexpected token - -error: proc-macro derive produced unparseable tokens - --> tests/ui/remote/double_generic.rs:10:10 - | -10 | #[derive(Serialize, Deserialize)] - | ^^^^^^^^^ - -error: expected one of `!`, `+`, `,`, `::`, or `>`, found `<` - --> tests/ui/remote/double_generic.rs:12:17 - | -10 | #[derive(Serialize, Deserialize)] - | ----------- - | | - | while parsing this item list starting here - | the item list ends here -11 | #[serde(remote = "remote::StructGeneric")] - | - expected one of `!`, `+`, `,`, `::`, or `>` -12 | struct StructDef { - | ^ unexpected token - | -help: you might have meant to end the type parameters here - | -11 | #[serde(remote = "remote::StructGeneric">)] - | + - -error: proc-macro derive produced unparseable tokens - --> tests/ui/remote/double_generic.rs:10:21 - | -10 | #[derive(Serialize, Deserialize)] - | ^^^^^^^^^^^ - -error[E0412]: cannot find type `StructGeneric` in module `remote` +error: remove generic parameters from this path --> tests/ui/remote/double_generic.rs:11:18 | 11 | #[serde(remote = "remote::StructGeneric")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `remote` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^