From 6405232187e40b69cb884ea8d4106c87d39bc044 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 30 May 2020 23:31:41 -0400 Subject: [PATCH] Handle nested `syn::Type:::Group` Currently, rustc does not pass the exact original TokenStream to proc-macros in several cases. This has many undesirable effects, such as losing correct location information in error message. See rust-lang/rust#43081 for more details In the future, rustc will begin passing the correct TokenStream to proc-macros. As a result, `syn` may wrap a type in one or more `syn::Type::Group`s (if the proc-macro input came from a `macro_rules!` expansion). I've determined that this can cause `oauth1-request-derive` to fail to match a `Type::Path`. This PR should properly handle nested groups, allowing your crate to work with both old and new input. If you have any questions, feel free to ask me. See rust-lang/rust#72622 for more details. --- oauth1-request-derive/src/method_body.rs | 6 ++++- .../tests/compile-fail/typeck.rs | 22 ++++--------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/oauth1-request-derive/src/method_body.rs b/oauth1-request-derive/src/method_body.rs index c2a63a4..94fb1ed 100644 --- a/oauth1-request-derive/src/method_body.rs +++ b/oauth1-request-derive/src/method_body.rs @@ -47,7 +47,11 @@ impl<'a> ToTokens for MethodBody<'a> { } let ty_is_option = f.meta.option.get().map(|v| **v).unwrap_or_else(|| { - if let Type::Path(ref ty_path) = f.ty { + let mut ty = &f.ty; + while let Type::Group(g) = ty { + ty = &g.elem; + } + if let Type::Path(ref ty_path) = ty { let path = &ty_path.path; path.leading_colon.is_none() && path.segments.len() == 1 diff --git a/oauth1-request-derive/tests/compile-fail/typeck.rs b/oauth1-request-derive/tests/compile-fail/typeck.rs index 4f21473..3bd54a0 100644 --- a/oauth1-request-derive/tests/compile-fail/typeck.rs +++ b/oauth1-request-derive/tests/compile-fail/typeck.rs @@ -2,13 +2,8 @@ use std::fmt::{self, Formatter}; #[derive(oauth1_request_derive::Authorize)] //~^ ERROR: mismatched types -//~| expected u8, found () -//~^^^ ERROR: mismatched types -//~| expected (), found u8 -//~^^^^^ ERROR: `()` doesn't implement `std::fmt::Display` -//~^^^^^^ ERROR: the trait bound `(): std::convert::AsRef` is not satisfied -//~^^^^^^^ ERROR: the trait bound `u8: std::convert::AsRef` is not satisfied -// FIXME: move these errors to (1) to (5) respectively +//~| ERROR: `()` doesn't implement `std::fmt::Display` +//~| ERROR: mismatched types struct Test { not_display: (), //^ (3) @@ -20,31 +15,26 @@ struct Test { #[oauth1(fmt = "fmt_arg_not_ref")] //~^ ERROR: mismatched types - //~| expected reference, found () fmt_arg_not_ref: (), #[oauth1(fmt = "fmt_arg_mismatch")] - //^ (1) fmt_arg_mismatch: (), #[oauth1(fmt = "fmt_trait_bound_unsatisfied")] - //^ (4) + //~^ the trait bound `(): std::convert::AsRef` fmt_trait_bound_unsatisfied: (), #[oauth1(fmt = "fmt_ret_mismatch")] //~^ ERROR: mismatched types - //~| expected struct `std::fmt::Error`, found () fmt_ret_mismatch: (), #[oauth1(fmt = "NOT_FN")] //~^ ERROR: mismatched types - //~| expected fn pointer, found () fmt_not_fn: (), #[oauth1(option = "true")] option_not_option: u8, //~^ ERROR: mismatched types - //~| expected enum `std::option::Option`, found u8 #[oauth1(skip_if = "skip_if_too_many_args")] //~^ ERROR: mismatched types @@ -53,25 +43,21 @@ struct Test { #[oauth1(skip_if = "skip_if_arg_not_ref")] //~^ ERROR: mismatched types - //~| expected reference, found u8 skip_if_arg_not_ref: u8, #[oauth1(skip_if = "skip_if_arg_mismatch")] - //^ (2) skip_if_arg_mismatch: u8, #[oauth1(skip_if = "skip_if_trait_bound_unsatisfied")] - //- (5) + //~^ ERROR: the trait bound `u8: std::convert::AsRef` skip_if_trait_bound_unsatisfied: u8, #[oauth1(skip_if = "skip_if_ret_mismatch")] //~^ ERROR: mismatched types - //~| expected bool, found enum `std::option::Option` skip_if_ret_mismatch: u8, #[oauth1(skip_if = "NOT_FN")] //~^ ERROR: mismatched types - //~| expected fn pointer, found () skip_if_not_fn: u8, }