Look inside of None-delimited groups when examining types

This commit is contained in:
David Tolnay 2020-05-29 17:58:34 -07:00
parent f7d06cae4c
commit c45a809d5c
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
5 changed files with 21 additions and 12 deletions

View File

@ -5,7 +5,7 @@ use syn::punctuated::{Pair, Punctuated};
use syn::visit::{self, Visit}; use syn::visit::{self, Visit};
use internals::ast::{Container, Data}; use internals::ast::{Container, Data};
use internals::attr; use internals::{attr, ungroup};
use proc_macro2::Span; use proc_macro2::Span;
@ -114,7 +114,7 @@ pub fn with_bound(
} }
impl<'ast> Visit<'ast> for FindTyParams<'ast> { impl<'ast> Visit<'ast> for FindTyParams<'ast> {
fn visit_field(&mut self, field: &'ast syn::Field) { fn visit_field(&mut self, field: &'ast syn::Field) {
if let syn::Type::Path(ty) = &field.ty { if let syn::Type::Path(ty) = ungroup(&field.ty) {
if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() { if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
if self.all_type_params.contains(&t.ident) { if self.all_type_params.contains(&t.ident) {
self.associated_type_usage.push(ty); self.associated_type_usage.push(ty);

View File

@ -8,7 +8,7 @@ use bound;
use dummy; use dummy;
use fragment::{Expr, Fragment, Match, Stmts}; use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant}; use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, Ctxt, Derive}; use internals::{attr, ungroup, Ctxt, Derive};
use pretend; use pretend;
use std::collections::BTreeSet; use std::collections::BTreeSet;
@ -77,7 +77,7 @@ fn precondition(cx: &Ctxt, cont: &Container) {
fn precondition_sized(cx: &Ctxt, cont: &Container) { fn precondition_sized(cx: &Ctxt, cont: &Container) {
if let Data::Struct(_, fields) = &cont.data { if let Data::Struct(_, fields) = &cont.data {
if let Some(last) = fields.last() { if let Some(last) = fields.last() {
if let syn::Type::Slice(_) = *last.ty { if let syn::Type::Slice(_) = ungroup(last.ty) {
cx.error_spanned_by( cx.error_spanned_by(
cont.original, cont.original,
"cannot deserialize a dynamically sized struct", "cannot deserialize a dynamically sized struct",

View File

@ -1,5 +1,5 @@
use internals::symbol::*; use internals::symbol::*;
use internals::Ctxt; use internals::{ungroup, Ctxt};
use proc_macro2::{Group, Span, TokenStream, TokenTree}; use proc_macro2::{Group, Span, TokenStream, TokenTree};
use quote::ToTokens; use quote::ToTokens;
use std::borrow::Cow; use std::borrow::Cow;
@ -1737,7 +1737,7 @@ fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool {
// cow: Cow<'a, str>, // cow: Cow<'a, str>,
// } // }
fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
let path = match ty { let path = match ungroup(ty) {
syn::Type::Path(ty) => &ty.path, syn::Type::Path(ty) => &ty.path,
_ => { _ => {
return false; return false;
@ -1764,7 +1764,7 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
} }
fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
let path = match ty { let path = match ungroup(ty) {
syn::Type::Path(ty) => &ty.path, syn::Type::Path(ty) => &ty.path,
_ => { _ => {
return false; return false;
@ -1811,7 +1811,7 @@ fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
// r: &'a str, // r: &'a str,
// } // }
fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
match ty { match ungroup(ty) {
syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem), syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem),
_ => false, _ => false,
} }
@ -1822,14 +1822,14 @@ fn is_str(ty: &syn::Type) -> bool {
} }
fn is_slice_u8(ty: &syn::Type) -> bool { fn is_slice_u8(ty: &syn::Type) -> bool {
match ty { match ungroup(ty) {
syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"), syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"),
_ => false, _ => false,
} }
} }
fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool {
match ty { match ungroup(ty) {
syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive),
_ => false, _ => false,
} }

View File

@ -1,6 +1,6 @@
use internals::ast::{Container, Data, Field, Style}; use internals::ast::{Container, Data, Field, Style};
use internals::attr::{Identifier, TagType}; use internals::attr::{Identifier, TagType};
use internals::{Ctxt, Derive}; use internals::{ungroup, Ctxt, Derive};
use syn::{Member, Type}; use syn::{Member, Type};
/// Cross-cutting checks that require looking at more than a single attrs /// Cross-cutting checks that require looking at more than a single attrs
@ -396,7 +396,7 @@ fn member_message(member: &Member) -> String {
} }
fn allow_transparent(field: &Field, derive: Derive) -> bool { fn allow_transparent(field: &Field, derive: Derive) -> bool {
if let Type::Path(ty) = field.ty { if let Type::Path(ty) = ungroup(&field.ty) {
if let Some(seg) = ty.path.segments.last() { if let Some(seg) = ty.path.segments.last() {
if seg.ident == "PhantomData" { if seg.ident == "PhantomData" {
return false; return false;

View File

@ -8,8 +8,17 @@ mod case;
mod check; mod check;
mod symbol; mod symbol;
use syn::Type;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Derive { pub enum Derive {
Serialize, Serialize,
Deserialize, Deserialize,
} }
pub fn ungroup(mut ty: &Type) -> &Type {
while let Type::Group(group) = ty {
ty = &group.elem;
}
ty
}