Use IdentUnraw consistently when comparing Member

This commit is contained in:
David Tolnay 2024-11-04 16:15:35 -05:00
parent 3d23842d35
commit 9116fdb8ea
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
8 changed files with 84 additions and 46 deletions

View file

@ -1,9 +1,9 @@
use crate::attr::{self, Attrs};
use crate::generics::ParamsInScope;
use crate::unraw::{IdentUnraw, MemberUnraw};
use proc_macro2::Span;
use syn::{
Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Index, Member, Result,
Type,
Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Index, Result, Type,
};
pub enum Input<'a> {
@ -35,7 +35,7 @@ pub struct Variant<'a> {
pub struct Field<'a> {
pub original: &'a syn::Field,
pub attrs: Attrs<'a>,
pub member: Member,
pub member: MemberUnraw,
pub ty: &'a Type,
pub contains_generic: bool,
}
@ -136,12 +136,13 @@ impl<'a> Field<'a> {
Ok(Field {
original: node,
attrs: attr::get(&node.attrs)?,
member: node.ident.clone().map(Member::Named).unwrap_or_else(|| {
Member::Unnamed(Index {
member: match &node.ident {
Some(name) => MemberUnraw::Named(IdentUnraw::new(name.clone())),
None => MemberUnraw::Unnamed(Index {
index: i as u32,
span,
})
}),
}),
},
ty: &node.ty,
contains_generic: scope.intersects(&node.ty),
})

View file

@ -1,11 +1,11 @@
use crate::ast::{Enum, Field, Input, Struct};
use crate::attr::Trait;
use crate::generics::InferredBounds;
use crate::span::MemberSpan;
use crate::unraw::MemberUnraw;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use std::collections::BTreeSet as Set;
use syn::{DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type};
use syn::{DeriveInput, GenericArgument, PathArguments, Result, Token, Type};
pub fn derive(input: &DeriveInput) -> TokenStream {
match try_expand(input) {
@ -409,8 +409,8 @@ fn impl_enum(input: Enum) -> TokenStream {
}
None => {
let only_field = match &variant.fields[0].member {
Member::Named(ident) => ident.clone(),
Member::Unnamed(index) => format_ident!("_{}", index),
MemberUnraw::Named(ident) => ident.to_local(),
MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
};
display_implied_bounds.insert((0, Trait::Display));
quote!(::core::fmt::Display::fmt(#only_field, __formatter))
@ -487,11 +487,11 @@ fn impl_enum(input: Enum) -> TokenStream {
fn fields_pat(fields: &[Field]) -> TokenStream {
let mut members = fields.iter().map(|field| &field.member).peekable();
match members.peek() {
Some(Member::Named(_)) => quote!({ #(#members),* }),
Some(Member::Unnamed(_)) => {
Some(MemberUnraw::Named(_)) => quote!({ #(#members),* }),
Some(MemberUnraw::Unnamed(_)) => {
let vars = members.map(|member| match member {
Member::Unnamed(member) => format_ident!("_{}", member),
Member::Named(_) => unreachable!(),
MemberUnraw::Unnamed(member) => format_ident!("_{}", member),
MemberUnraw::Named(_) => unreachable!(),
});
quote!((#(#vars),*))
}

View file

@ -1,14 +1,14 @@
use crate::ast::Field;
use crate::attr::{Display, Trait};
use crate::scan_expr::scan_expr;
use crate::unraw::IdentUnraw;
use crate::unraw::{IdentUnraw, MemberUnraw};
use proc_macro2::{TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use std::collections::{BTreeSet as Set, HashMap as Map};
use syn::ext::IdentExt;
use syn::parse::discouraged::Speculative;
use syn::parse::{ParseStream, Parser};
use syn::{Expr, Ident, Index, LitStr, Member, Result, Token};
use syn::{Expr, Ident, Index, LitStr, Result, Token};
impl Display<'_> {
// Transform `"error {var}"` to `"error {}", var`.
@ -54,7 +54,7 @@ impl Display<'_> {
'0'..='9' => {
let int = take_int(&mut read);
let member = match int.parse::<u32>() {
Ok(index) => Member::Unnamed(Index { index, span }),
Ok(index) => MemberUnraw::Unnamed(Index { index, span }),
Err(_) => return,
};
if !member_index.contains_key(&member) {
@ -65,7 +65,7 @@ impl Display<'_> {
}
'a'..='z' | 'A'..='Z' | '_' => {
let ident = Ident::new(take_ident(&mut read), span);
Member::Named(ident)
MemberUnraw::Named(IdentUnraw::new(ident))
}
_ => continue,
};
@ -87,10 +87,10 @@ impl Display<'_> {
};
implied_bounds.insert((field, bound));
}
let formatvar = IdentUnraw::new(match &member {
Member::Unnamed(index) => format_ident!("_{}", index),
Member::Named(ident) => ident.clone(),
});
let formatvar = match &member {
MemberUnraw::Unnamed(index) => IdentUnraw::new(format_ident!("_{}", index)),
MemberUnraw::Named(ident) => ident.clone(),
};
out += &formatvar.to_string();
if !named_args.insert(formatvar.clone()) {
// Already specified in the format argument list.

View file

@ -25,7 +25,6 @@ mod fmt;
mod generics;
mod prop;
mod scan_expr;
mod span;
mod unraw;
mod valid;

View file

@ -1,7 +1,7 @@
use crate::ast::{Enum, Field, Struct, Variant};
use crate::span::MemberSpan;
use crate::unraw::MemberUnraw;
use proc_macro2::Span;
use syn::{Member, Type};
use syn::Type;
impl Struct<'_> {
pub(crate) fn from_field(&self) -> Option<&Field> {
@ -101,7 +101,7 @@ fn source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
}
for field in fields {
match &field.member {
Member::Named(ident) if ident == "source" => return Some(field),
MemberUnraw::Named(ident) if ident == "source" => return Some(field),
_ => {}
}
}

View file

@ -1,15 +0,0 @@
use proc_macro2::Span;
use syn::Member;
pub trait MemberSpan {
fn member_span(&self) -> Span;
}
impl MemberSpan for Member {
fn member_span(&self) -> Span {
match self {
Member::Named(ident) => ident.span(),
Member::Unnamed(index) => index.span,
}
}
}

View file

@ -2,12 +2,14 @@ use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};
use syn::ext::IdentExt as _;
use syn::parse::{Parse, ParseStream, Result};
use syn::Index;
#[derive(Clone)]
#[repr(transparent)]
pub(crate) struct IdentUnraw(Ident);
pub struct IdentUnraw(Ident);
impl IdentUnraw {
pub fn new(ident: Ident) -> Self {
@ -42,6 +44,12 @@ impl PartialEq for IdentUnraw {
}
}
impl PartialEq<str> for IdentUnraw {
fn eq(&self, other: &str) -> bool {
self.0 == other
}
}
impl Ord for IdentUnraw {
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&self.0.unraw(), &other.0.unraw())
@ -65,3 +73,47 @@ impl ToTokens for IdentUnraw {
self.0.unraw().to_tokens(tokens);
}
}
pub enum MemberUnraw {
Named(IdentUnraw),
Unnamed(Index),
}
impl MemberUnraw {
pub fn member_span(&self) -> Span {
match self {
MemberUnraw::Named(ident) => ident.0.span(),
MemberUnraw::Unnamed(index) => index.span,
}
}
}
impl Eq for MemberUnraw {}
impl PartialEq for MemberUnraw {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(MemberUnraw::Named(this), MemberUnraw::Named(other)) => this == other,
(MemberUnraw::Unnamed(this), MemberUnraw::Unnamed(other)) => this == other,
_ => false,
}
}
}
impl Hash for MemberUnraw {
fn hash<H: Hasher>(&self, hasher: &mut H) {
match self {
MemberUnraw::Named(ident) => ident.0.unraw().hash(hasher),
MemberUnraw::Unnamed(index) => index.hash(hasher),
}
}
}
impl ToTokens for MemberUnraw {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
MemberUnraw::Named(ident) => ident.to_local().to_tokens(tokens),
MemberUnraw::Unnamed(index) => index.to_tokens(tokens),
}
}
}

View file

@ -1,8 +1,9 @@
use crate::ast::{Enum, Field, Input, Struct, Variant};
use crate::attr::Attrs;
use crate::unraw::MemberUnraw;
use quote::ToTokens;
use std::collections::BTreeSet as Set;
use syn::{Error, GenericArgument, Member, PathArguments, Result, Type};
use syn::{Error, GenericArgument, PathArguments, Result, Type};
impl Input<'_> {
pub(crate) fn validate(&self) -> Result<()> {
@ -204,8 +205,8 @@ fn check_field_attrs(fields: &[Field]) -> Result<()> {
fn same_member(one: &Field, two: &Field) -> bool {
match (&one.member, &two.member) {
(Member::Named(one), Member::Named(two)) => one == two,
(Member::Unnamed(one), Member::Unnamed(two)) => one.index == two.index,
(MemberUnraw::Named(one), MemberUnraw::Named(two)) => one == two,
(MemberUnraw::Unnamed(one), MemberUnraw::Unnamed(two)) => one.index == two.index,
_ => unreachable!(),
}
}