Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: dtolnay/syn
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.0.73
Choose a base ref
...
head repository: dtolnay/syn
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2.0.74
Choose a head ref
  • 6 commits
  • 7 files changed
  • 1 contributor

Commits on Aug 11, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    65ec30d View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    857942e View commit details
  3. Add regression test for issue 1718

        error[E0502]: cannot borrow `generics.params` as mutable because it is also borrowed as immutable
          --> tests/test_iterators.rs:81:25
           |
        77 |       let _ = generics
           |               --------
           |               |
           |  _____________immutable borrow occurs here
           | |
        78 | |         .lifetimes()
           | |____________________- a temporary with access to the immutable borrow is created here ...
        ...
        81 |           .unwrap_or_else(|| {
           |                           ^^ mutable borrow occurs here
        82 |               let lifetime: Lifetime = parse_quote!('a);
        83 |               generics.params.insert(
           |               --------------- second borrow occurs due to use of `generics.params` in closure
        ...
        88 |           });
           |             - ... and the immutable borrow might be used here, when that temporary is dropped and runs the destructor for type `impl Iterator<Item = &LifetimeParam>`
    dtolnay committed Aug 11, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    7dc05a5 View commit details
  4. Expose non-impl-Trait iterator return types

    dtolnay committed Aug 11, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    2955ac5 View commit details
  5. Merge pull request #1719 from dtolnay/iterators

    Expose non-impl-Trait iterator return types
    dtolnay authored Aug 11, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    6cf2344 View commit details
  6. Release 2.0.74

    dtolnay committed Aug 11, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    b15ae28 View commit details
Showing with 246 additions and 197 deletions.
  1. +1 −1 Cargo.toml
  2. +74 −72 src/data.rs
  3. +132 −120 src/generics.rs
  4. +1 −1 src/lib.rs
  5. +16 −0 src/macros.rs
  6. +1 −1 syn.json
  7. +21 −2 tests/test_iterators.rs
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "syn"
version = "2.0.73"
version = "2.0.74"
authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["development-tools::procedural-macro-helpers", "parser-implementations"]
description = "Parser for Rust source code"
146 changes: 74 additions & 72 deletions src/data.rs
Original file line number Diff line number Diff line change
@@ -105,80 +105,45 @@ impl Fields {
}
}

/// Get an iterator over the fields of a struct or variant as [`Member`]s.
/// This iterator can be used to iterate over a named or unnamed struct or
/// variant's fields uniformly.
///
/// # Example
///
/// The following is a simplistic [`Clone`] derive for structs. (A more
/// complete implementation would additionally want to infer trait bounds on
/// the generic type parameters.)
///
/// ```
/// # use quote::quote;
/// #
/// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
/// let ident = &input.ident;
/// let members = input.fields.members();
/// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
/// quote! {
/// impl #impl_generics Clone for #ident #ty_generics #where_clause {
/// fn clone(&self) -> Self {
/// Self {
/// #(#members: self.#members.clone()),*
/// }
/// }
/// }
/// }
/// }
/// ```
///
/// For structs with named fields, it produces an expression like `Self { a:
/// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
/// self.0.clone() }`. And for unit structs, `Self {}`.
pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ {
struct Members<'a> {
fields: punctuated::Iter<'a, Field>,
index: u32,
}

impl<'a> Iterator for Members<'a> {
type Item = Member;

fn next(&mut self) -> Option<Self::Item> {
let field = self.fields.next()?;
let member = match &field.ident {
Some(ident) => Member::Named(ident.clone()),
None => {
#[cfg(all(feature = "parsing", feature = "printing"))]
let span = crate::spanned::Spanned::span(&field.ty);
#[cfg(not(all(feature = "parsing", feature = "printing")))]
let span = proc_macro2::Span::call_site();
Member::Unnamed(Index {
index: self.index,
span,
})
}
};
self.index += 1;
Some(member)
}
}

impl<'a> Clone for Members<'a> {
fn clone(&self) -> Self {
Members {
fields: self.fields.clone(),
index: self.index,
}
return_impl_trait! {
/// Get an iterator over the fields of a struct or variant as [`Member`]s.
/// This iterator can be used to iterate over a named or unnamed struct or
/// variant's fields uniformly.
///
/// # Example
///
/// The following is a simplistic [`Clone`] derive for structs. (A more
/// complete implementation would additionally want to infer trait bounds on
/// the generic type parameters.)
///
/// ```
/// # use quote::quote;
/// #
/// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
/// let ident = &input.ident;
/// let members = input.fields.members();
/// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
/// quote! {
/// impl #impl_generics Clone for #ident #ty_generics #where_clause {
/// fn clone(&self) -> Self {
/// Self {
/// #(#members: self.#members.clone()),*
/// }
/// }
/// }
/// }
/// }
/// ```
///
/// For structs with named fields, it produces an expression like `Self { a:
/// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
/// self.0.clone() }`. And for unit structs, `Self {}`.
pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] {
Members {
fields: self.iter(),
index: 0,
}
}

Members {
fields: self.iter(),
index: 0,
}
}
}

@@ -234,6 +199,43 @@ ast_struct! {
}
}

pub struct Members<'a> {
fields: punctuated::Iter<'a, Field>,
index: u32,
}

impl<'a> Iterator for Members<'a> {
type Item = Member;

fn next(&mut self) -> Option<Self::Item> {
let field = self.fields.next()?;
let member = match &field.ident {
Some(ident) => Member::Named(ident.clone()),
None => {
#[cfg(all(feature = "parsing", feature = "printing"))]
let span = crate::spanned::Spanned::span(&field.ty);
#[cfg(not(all(feature = "parsing", feature = "printing")))]
let span = proc_macro2::Span::call_site();
Member::Unnamed(Index {
index: self.index,
span,
})
}
};
self.index += 1;
Some(member)
}
}

impl<'a> Clone for Members<'a> {
fn clone(&self) -> Self {
Members {
fields: self.fields.clone(),
index: self.index,
}
}
}

#[cfg(feature = "parsing")]
pub(crate) mod parsing {
use crate::attr::Attribute;
Loading