Skip to content

Commit

Permalink
Merge pull request #352 from dtolnay/member
Browse files Browse the repository at this point in the history
Use IdentUnraw consistently when comparing Member
  • Loading branch information
dtolnay authored Nov 4, 2024
2 parents 3d23842 + e015360 commit 6683511
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 55 deletions.
15 changes: 8 additions & 7 deletions impl/src/ast.rs
Original file line number Diff line number Diff line change
@@ -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> {
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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),
})
Expand Down
32 changes: 16 additions & 16 deletions impl/src/expand.rs
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -75,7 +75,7 @@ fn impl_struct(input: Struct) -> TokenStream {
error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static));
}
let asref = if type_is_option(source_field.ty) {
Some(quote_spanned!(source.member_span()=> .as_ref()?))
Some(quote_spanned!(source.span()=> .as_ref()?))
} else {
None
};
Expand Down Expand Up @@ -103,13 +103,13 @@ fn impl_struct(input: Struct) -> TokenStream {
let body = if let Some(source_field) = input.source_field() {
let source = &source_field.member;
let source_provide = if type_is_option(source_field.ty) {
quote_spanned! {source.member_span()=>
quote_spanned! {source.span()=>
if let ::core::option::Option::Some(source) = &self.#source {
source.thiserror_provide(#request);
}
}
} else {
quote_spanned! {source.member_span()=>
quote_spanned! {source.span()=>
self.#source.thiserror_provide(#request);
}
};
Expand Down Expand Up @@ -252,7 +252,7 @@ fn impl_enum(input: Enum) -> TokenStream {
error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static));
}
let asref = if type_is_option(source_field.ty) {
Some(quote_spanned!(source.member_span()=> .as_ref()?))
Some(quote_spanned!(source.span()=> .as_ref()?))
} else {
None
};
Expand Down Expand Up @@ -294,13 +294,13 @@ fn impl_enum(input: Enum) -> TokenStream {
let source = &source_field.member;
let varsource = quote!(source);
let source_provide = if type_is_option(source_field.ty) {
quote_spanned! {source.member_span()=>
quote_spanned! {source.span()=>
if let ::core::option::Option::Some(source) = #varsource {
source.thiserror_provide(#request);
}
}
} else {
quote_spanned! {source.member_span()=>
quote_spanned! {source.span()=>
#varsource.thiserror_provide(#request);
}
};
Expand Down Expand Up @@ -333,13 +333,13 @@ fn impl_enum(input: Enum) -> TokenStream {
let backtrace = &backtrace_field.member;
let varsource = quote!(source);
let source_provide = if type_is_option(source_field.ty) {
quote_spanned! {backtrace.member_span()=>
quote_spanned! {backtrace.span()=>
if let ::core::option::Option::Some(source) = #varsource {
source.thiserror_provide(#request);
}
}
} else {
quote_spanned! {backtrace.member_span()=>
quote_spanned! {backtrace.span()=>
#varsource.thiserror_provide(#request);
}
};
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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),*))
}
Expand Down
16 changes: 8 additions & 8 deletions impl/src/fmt.rs
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down Expand Up @@ -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) {
Expand All @@ -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,
};
Expand All @@ -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.
Expand Down
1 change: 0 additions & 1 deletion impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ mod fmt;
mod generics;
mod prop;
mod scan_expr;
mod span;
mod unraw;
mod valid;

Expand Down
8 changes: 4 additions & 4 deletions impl/src/prop.rs
Original file line number Diff line number Diff line change
@@ -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> {
Expand Down Expand Up @@ -79,7 +79,7 @@ impl Field<'_> {
} else if let Some(from_attr) = &self.attrs.from {
from_attr.path().get_ident().unwrap().span()
} else {
self.member.member_span()
self.member.span()
}
}
}
Expand All @@ -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),
_ => {}
}
}
Expand Down
15 changes: 0 additions & 15 deletions impl/src/span.rs

This file was deleted.

54 changes: 53 additions & 1 deletion impl/src/unraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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())
Expand All @@ -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 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),
}
}
}
7 changes: 4 additions & 3 deletions impl/src/valid.rs
Original file line number Diff line number Diff line change
@@ -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<()> {
Expand Down Expand Up @@ -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!(),
}
}
Expand Down

0 comments on commit 6683511

Please sign in to comment.