From 5d1403461c5da80e2e0f0ed59e920e74d9ee2262 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 6 Sep 2023 15:31:16 -0700 Subject: [PATCH 1/4] add failing test --- test_suite/tests/test_annotations.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index fa314cbca..f4801002f 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -2380,6 +2380,30 @@ fn test_partially_untagged_enum_desugared() { ); } +#[test] +fn test_partially_untagged_simple_enum() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(tag = "tag")] + enum Data { + A, + #[serde(untagged)] + Var(u32), + } + + let data = Data::A; + assert_tokens( + &data, + &[ + Token::Map { len: None }, + Token::Str("t"), + Token::Str("A"), + Token::Str("b"), + Token::I32(0), + Token::MapEnd, + ], + ); +} + #[test] fn test_flatten_option() { #[derive(Serialize, Deserialize, PartialEq, Debug)] From 09993a904a7d2346955899feaa8b43668a3fb667 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 6 Sep 2023 15:25:05 -0700 Subject: [PATCH 2/4] Fix for "cannot infer type" from Deserialize derive macro with simple variants and untagged variants --- serde_derive/src/de.rs | 10 +++++++++- test_suite/tests/test_annotations.rs | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index ee8a23766..4c39b7ca1 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1737,7 +1737,6 @@ fn deserialize_untagged_enum_after( quote!(__deserializer), )) }); - let attempts = first_attempt.into_iter().chain(attempts); // TODO this message could be better by saving the errors from the failed // attempts. The heuristic used by TOML was to count the number of fields // processed before an error, and use the error that happened after the @@ -1750,10 +1749,19 @@ fn deserialize_untagged_enum_after( ); let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); + // This may be infallible so we need to provide the error type. + let first_attempt = first_attempt.map(|expr| { + quote! { + if let _serde::__private::Result::<_, __D::Error>::Ok(__ok) = #expr { + return _serde::__private::Ok(__ok); + } + } + }); quote_block! { let __content = <_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer)?; let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content); + #first_attempt #( if let _serde::__private::Ok(__ok) = #attempts { return _serde::__private::Ok(__ok); diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index f4801002f..eeb3ec0d4 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -2383,7 +2383,7 @@ fn test_partially_untagged_enum_desugared() { #[test] fn test_partially_untagged_simple_enum() { #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(tag = "tag")] + #[serde(tag = "t")] enum Data { A, #[serde(untagged)] @@ -2391,7 +2391,8 @@ fn test_partially_untagged_simple_enum() { } let data = Data::A; - assert_tokens( + + assert_de_tokens( &data, &[ Token::Map { len: None }, From 8da2058e2a18f7a986c758129c4c199ad4353ad3 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Thu, 7 Sep 2023 17:19:27 -0700 Subject: [PATCH 3/4] fix deserialization of untagged variants within internally or adjacently tagged enums --- serde_derive/src/de.rs | 8 ++++-- test_suite/tests/test_annotations.rs | 40 +++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 4c39b7ca1..c6b2cfff2 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1749,10 +1749,14 @@ fn deserialize_untagged_enum_after( ); let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); - // This may be infallible so we need to provide the error type. + // Ignore any error associated with non-untagged deserialization so that we + // can fall through to the untagged variants. This may be infallible so we + // need to provide the error type. let first_attempt = first_attempt.map(|expr| { quote! { - if let _serde::__private::Result::<_, __D::Error>::Ok(__ok) = #expr { + if let _serde::__private::Result::<_, __D::Error>::Ok(__ok) = (|| { + #expr + })() { return _serde::__private::Ok(__ok); } } diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index eeb3ec0d4..9c4eabbb9 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -2381,11 +2381,12 @@ fn test_partially_untagged_enum_desugared() { } #[test] -fn test_partially_untagged_simple_enum() { +fn test_partially_untagged_tagged_enum() { #[derive(Serialize, Deserialize, PartialEq, Debug)] #[serde(tag = "t")] enum Data { A, + B, #[serde(untagged)] Var(u32), } @@ -2398,11 +2399,44 @@ fn test_partially_untagged_simple_enum() { Token::Map { len: None }, Token::Str("t"), Token::Str("A"), - Token::Str("b"), - Token::I32(0), Token::MapEnd, ], ); + + let data = Data::Var(42); + + assert_de_tokens(&data, &[Token::U32(42)]); + + // TODO test error output + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[serde(tag = "t", content = "c")] + enum Data2 { + A(u32), + B, + #[serde(untagged)] + Var(u32), + } + + let data = Data2::A(7); + + assert_de_tokens( + &data, + &[ + Token::Map { len: None }, + Token::Str("t"), + Token::Str("A"), + Token::Str("c"), + Token::U32(7), + Token::MapEnd, + ], + ); + + let data = Data2::Var(42); + + assert_de_tokens(&data, &[Token::U32(42)]); + + // TODO test error output } #[test] From 94fbc3d38838398a8971cb4e4d617b8d42685b0c Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Thu, 7 Sep 2023 22:17:22 -0700 Subject: [PATCH 4/4] fix clippy --- test_suite/tests/test_annotations.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index 9c4eabbb9..90e0a153a 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -2381,7 +2381,7 @@ fn test_partially_untagged_enum_desugared() { } #[test] -fn test_partially_untagged_tagged_enum() { +fn test_partially_untagged_internally_tagged_enum() { #[derive(Serialize, Deserialize, PartialEq, Debug)] #[serde(tag = "t")] enum Data { @@ -2408,17 +2408,20 @@ fn test_partially_untagged_tagged_enum() { assert_de_tokens(&data, &[Token::U32(42)]); // TODO test error output +} +#[test] +fn test_partially_untagged_adjacently_tagged_enum() { #[derive(Serialize, Deserialize, PartialEq, Debug)] #[serde(tag = "t", content = "c")] - enum Data2 { + enum Data { A(u32), B, #[serde(untagged)] Var(u32), } - let data = Data2::A(7); + let data = Data::A(7); assert_de_tokens( &data, @@ -2432,7 +2435,7 @@ fn test_partially_untagged_tagged_enum() { ], ); - let data = Data2::Var(42); + let data = Data::Var(42); assert_de_tokens(&data, &[Token::U32(42)]);