From 50354c2d0bb623ff6bb57ba573c6ef3fd4180df6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 27 Nov 2022 17:45:26 -0800 Subject: [PATCH] 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 3db348079..1164ed7fd 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 0e2484a79..eb1297aa7 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 f84a3f52d..ee22aa1fe 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 1a65f1009..4188b44a2 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` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^