Skip to main content

pin_init_internal/
init.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use proc_macro2::{Span, TokenStream};
4use quote::{format_ident, quote, quote_spanned, ToTokens, TokenStreamExt};
5use syn::{
6    braced, parenthesized,
7    parse::{End, Parse},
8    parse_quote,
9    punctuated::{Pair, Punctuated},
10    spanned::Spanned,
11    token, Attribute, Block, Expr, ExprCall, ExprPath, Ident, Index, LitInt, Member, Path, Token,
12    Type,
13};
14
15use crate::{
16    diagnostics::{DiagCtxt, ErrorGuaranteed},
17    util::*,
18};
19
20pub(crate) struct Initializer<Kind = InitExprKind> {
21    attrs: Vec<InitializerAttribute>,
22    this: Option<This>,
23    kind: Kind,
24    error: Option<(Token![?], Type)>,
25}
26
27pub(crate) struct InitExprStruct {
28    path: Path,
29    brace_token: token::Brace,
30    fields: Punctuated<InitializerField, Token![,]>,
31    rest: Option<(Token![..], Expr)>,
32}
33
34pub(crate) struct InitExprTuple {
35    path: Path,
36    paren_token: token::Paren,
37    fields: Punctuated<InitTupleField, Token![,]>,
38}
39
40pub(crate) enum InitExprKind {
41    Struct(InitExprStruct),
42    Tuple(InitExprTuple),
43}
44
45struct InitTupleField {
46    attrs: Vec<Attribute>,
47    /// `<-` is not valid in constructor syntax; it is parsed anyway so that it can be rejected
48    /// with a proper diagnostic instead of a parse error.
49    left_arrow_token: Option<Token![<-]>,
50    value: Expr,
51}
52
53impl InitExprTuple {
54    fn normalize(self) -> InitExprStruct {
55        let InitExprTuple {
56            path,
57            paren_token,
58            fields,
59        } = self;
60        InitExprStruct {
61            path,
62            brace_token: token::Brace {
63                span: paren_token.span,
64            },
65            fields: fields
66                .into_pairs()
67                .enumerate()
68                .map(|(index, pair)| {
69                    let (field, comma) = pair.into_tuple();
70                    let span = field.value.span();
71                    let field = InitializerField {
72                        attrs: field.attrs,
73                        kind: InitializerKind::Value {
74                            member: Member::Unnamed(Index {
75                                index: index.try_into().unwrap(),
76                                span,
77                            }),
78                            value: Some((Token![:](span), field.value)),
79                        },
80                    };
81                    Pair::new(field, comma)
82                })
83                .collect(),
84            rest: None,
85        }
86    }
87
88    fn validate(&self, dcx: &mut DiagCtxt) -> Result<(), ErrorGuaranteed> {
89        let mut result = Ok(());
90        for field in &self.fields {
91            if let Some(left_arrow_token) = &field.left_arrow_token {
92                result = Err(dcx.error(
93                    left_arrow_token,
94                    "`<-` is not supported in tuple constructor syntax; name the fields by index \
95                     instead, e.g. `Type { 0 <- initializer, 1: value }`",
96                ));
97            }
98        }
99        result
100    }
101}
102
103struct This {
104    _and_token: Token![&],
105    ident: Ident,
106    _in_token: Token![in],
107}
108
109struct InitializerField {
110    attrs: Vec<Attribute>,
111    kind: InitializerKind,
112}
113
114enum InitializerKind {
115    Value {
116        member: Member,
117        value: Option<(Token![:], Expr)>,
118    },
119    Init {
120        member: Member,
121        _left_arrow_token: Token![<-],
122        value: Expr,
123    },
124    Code {
125        _underscore_token: Token![_],
126        _colon_token: Token![:],
127        block: Block,
128    },
129}
130
131impl InitializerKind {
132    fn member(&self) -> Option<&Member> {
133        match self {
134            Self::Value { member, .. } | Self::Init { member, .. } => Some(member),
135            Self::Code { .. } => None,
136        }
137    }
138}
139
140enum InitializerAttribute {
141    DefaultError(DefaultErrorAttribute),
142}
143
144struct DefaultErrorAttribute {
145    ty: Box<Type>,
146}
147
148pub(crate) fn expand_with_cfg(
149    initializer: Initializer,
150    default_error: Option<&'static str>,
151    pinned: bool,
152    dcx: &mut DiagCtxt,
153) -> Result<TokenStream, ErrorGuaranteed> {
154    let initializer = match initializer.kind {
155        InitExprKind::Tuple(expr) => {
156            expr.validate(dcx)?;
157
158            let mut initializer = Initializer {
159                attrs: initializer.attrs,
160                this: initializer.this,
161                kind: expr,
162                error: initializer.error,
163            };
164
165            // Removing a tuple field renumbers every field after it, which cannot be expressed with
166            // a `cfg` attribute on the initializer of a single field. Therefore, resolve tuple
167            // field cfgs before continuing. Struct expression syntax uses explicit numbers, so
168            // there is no need to pre-expand them and we only need to emit their cfgs on generated
169            // code.
170            for (field_idx, field) in initializer.kind.fields.iter_mut().enumerate() {
171                let cfg = field.attrs.extract_cfg_attrs();
172
173                if cfg.is_empty() {
174                    continue;
175                }
176
177                let true_initializer = initializer.to_token_stream();
178                initializer.kind.fields = initializer
179                    .kind
180                    .fields
181                    .into_pairs()
182                    .enumerate()
183                    .filter(|&(index, _)| index != field_idx)
184                    .map(|(_, pair)| pair)
185                    .collect();
186
187                let false_initializer = &initializer;
188
189                let macro_name = if pinned {
190                    quote!(::pin_init::pin_init)
191                } else {
192                    quote!(::pin_init::init)
193                };
194
195                // Resolve one field at a time until we've got no more tuple field cfgs.
196                //
197                // This is linear time because macro invocations with false cfg will not be
198                // expanded.
199                return Ok(quote! {
200                    {
201                        // Use `{}` delimiter here so semicolon is not required, otherwise the
202                        // expression becomes unit type.
203                        #[cfg(all(#(#cfg,)*))]
204                        #macro_name! { #true_initializer }
205
206                        #[cfg(not(all(#(#cfg,)*)))]
207                        #macro_name! { #false_initializer }
208                    }
209                });
210            }
211
212            // No cfgs left, we can normalize the initializer to the struct kind.
213            Initializer {
214                attrs: initializer.attrs,
215                this: initializer.this,
216                kind: initializer.kind.normalize(),
217                error: initializer.error,
218            }
219        }
220
221        InitExprKind::Struct(expr) => Initializer {
222            attrs: initializer.attrs,
223            this: initializer.this,
224            kind: expr,
225            error: initializer.error,
226        },
227    };
228
229    expand(initializer, default_error, pinned, dcx)
230}
231
232fn expand(
233    Initializer {
234        attrs,
235        this,
236        kind:
237            InitExprStruct {
238                path,
239                brace_token,
240                fields,
241                rest,
242            },
243        error,
244    }: Initializer<InitExprStruct>,
245    default_error: Option<&'static str>,
246    pinned: bool,
247    dcx: &mut DiagCtxt,
248) -> Result<TokenStream, ErrorGuaranteed> {
249    let error = error.map_or_else(
250        || {
251            if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
252                #[expect(irrefutable_let_patterns)]
253                if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
254                    Some(ty.clone())
255                } else {
256                    acc
257                }
258            }) {
259                default_error
260            } else if let Some(default_error) = default_error {
261                syn::parse_str(default_error).unwrap()
262            } else {
263                dcx.error(
264                    brace_token.span.close(),
265                    "expected `? <type>` after initializer",
266                );
267                parse_quote!(::core::convert::Infallible)
268            }
269        },
270        |(_, err)| Box::new(err),
271    );
272    let (has_data_trait, get_data, init_from_closure) = if pinned {
273        (
274            format_ident!("HasPinData"),
275            format_ident!("__pin_data"),
276            format_ident!("pin_init_from_closure"),
277        )
278    } else {
279        (
280            format_ident!("HasInitData"),
281            format_ident!("__init_data"),
282            format_ident!("init_from_closure"),
283        )
284    };
285    let init_kind = get_init_kind(rest, dcx);
286    let zeroable_check = match init_kind {
287        InitKind::Normal => quote!(),
288        InitKind::Zeroing => quote_spanned! { Span::mixed_site() =>
289            // The user specified `..Zeroable::zeroed()` at the end of the list of fields.
290            // Therefore we check if the struct implements `Zeroable` and then zero the memory.
291            // This allows us to also remove the check that all fields are present (since we
292            // already set the memory to zero and that is a valid bit pattern).
293            fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
294            where T: ::pin_init::Zeroable
295            {}
296            // Ensure that the struct is indeed `Zeroable`.
297            assert_zeroable(slot);
298            // SAFETY: The type implements `Zeroable` by the check above.
299            unsafe { ::core::ptr::write_bytes(slot, 0, 1) };
300        },
301    };
302    let this = match this {
303        None => quote!(),
304        Some(This { ident, .. }) => quote_spanned! { Span::mixed_site() =>
305            // Create the `this` so it can be referenced by the user inside of the
306            // expressions creating the individual fields.
307            let #ident = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };
308        },
309    };
310    // `mixed_site` ensures that the data is not accessible to the user-controlled code.
311    let init_fields = init_fields(&fields, pinned);
312    let field_check = make_field_check(&fields, init_kind, &path);
313    Ok(quote_spanned! { Span::mixed_site() => {
314        // Get the data about fields from the supplied type.
315        // SAFETY: TODO
316        let data = unsafe {
317            use ::pin_init::__internal::#has_data_trait;
318            // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit
319            // generics (which need to be present with that syntax).
320            #path::#get_data()
321        };
322        // Ensure that `data` really is of type `data` and help with type inference:
323        let init = data.__make_closure::<_, #error>(
324            move |slot| {
325                #zeroable_check
326                #this
327                #init_fields
328                #field_check
329                // SAFETY: we are the `init!` macro that is allowed to call this.
330                Ok(unsafe { ::pin_init::__internal::InitOk::new() })
331            }
332        );
333        let init = move |slot| -> ::core::result::Result<(), #error> {
334            init(slot).map(|__InitOk| ())
335        };
336        // SAFETY: TODO
337        unsafe { ::pin_init::#init_from_closure::<_, #error>(init) }
338    }})
339}
340
341enum InitKind {
342    Normal,
343    Zeroing,
344}
345
346fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKind {
347    let Some((dotdot, expr)) = rest else {
348        return InitKind::Normal;
349    };
350    match &expr {
351        Expr::Call(ExprCall { func, args, .. }) if args.is_empty() => match &**func {
352            Expr::Path(ExprPath {
353                attrs,
354                qself: None,
355                path:
356                    Path {
357                        leading_colon: None,
358                        segments,
359                    },
360            }) if attrs.is_empty()
361                && segments.len() == 2
362                && segments[0].ident == "Zeroable"
363                && segments[0].arguments.is_none()
364                && segments[1].ident == "init_zeroed"
365                && segments[1].arguments.is_none() =>
366            {
367                return InitKind::Zeroing;
368            }
369            _ => {}
370        },
371        _ => {}
372    }
373    dcx.error(
374        dotdot.span().join(expr.span()).unwrap_or(expr.span()),
375        "expected nothing or `..Zeroable::init_zeroed()`.",
376    );
377    InitKind::Normal
378}
379
380/// Generate the code that initializes the fields of the struct using the initializers in `field`.
381fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -> TokenStream {
382    let mut guards = vec![];
383    let mut guard_attrs = vec![];
384    let mut res = TokenStream::new();
385    for InitializerField { attrs, kind } in fields {
386        let cfgs = {
387            let mut cfgs = attrs.clone();
388            cfgs.retain(|attr| attr.path().is_ident("cfg"));
389            cfgs
390        };
391
392        let member = match kind {
393            InitializerKind::Value { member, .. } => member,
394            InitializerKind::Init { member, .. } => member,
395            InitializerKind::Code { block, .. } => {
396                let stmt = &block.stmts;
397                res.extend(quote! {
398                    #(#attrs)*
399                    {
400                        #(#stmt)*
401                    }
402                });
403                continue;
404            }
405        };
406        let ident = member.as_ident();
407        let span = Span::mixed_site().located_at(ident.span());
408
409        let slot = if pinned {
410            quote_spanned! { span =>
411                // SAFETY:
412                // - `slot` is valid and properly aligned.
413                // - `make_field_check` checks that `&raw mut (*slot).#member` is properly aligned.
414                // - `make_field_check` prevents `#member` from being used twice, therefore
415                //   `(*slot).#member` is exclusively accessed and has not been initialized.
416                (unsafe { data.#ident(slot) })
417            }
418        } else {
419            quote_spanned! { span =>
420                // For `init!()` macro, everything is unpinned.
421                // SAFETY:
422                // - `&raw mut (*slot).#member` is valid.
423                // - `make_field_check` checks that `&raw mut (*slot).#member` is properly aligned.
424                // - `make_field_check` prevents `#member` from being used twice, therefore
425                //   `(*slot).#member` is exclusively accessed and has not been initialized.
426                (unsafe {
427                    ::pin_init::__internal::Slot::<::pin_init::__internal::Unpinned, _>::new(
428                        &raw mut (*slot).#member
429                    )
430                })
431            }
432        };
433
434        // `mixed_site` ensures that the guard is not accessible to the user-controlled code.
435        let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
436        let full_span = kind.span();
437
438        let init = match kind {
439            InitializerKind::Value { value, .. } => {
440                let value = value
441                    .as_ref()
442                    .map(|(_, value)| quote!(#value))
443                    .unwrap_or_else(|| quote!(#member));
444
445                quote_spanned! { full_span =>
446                    #(#attrs)*
447                    let mut #guard = #slot.write(#value);
448                }
449            }
450            InitializerKind::Init { value, .. } => {
451                quote_spanned! { full_span =>
452                    #(#attrs)*
453                    let mut #guard = #slot.init(#value)?;
454                }
455            }
456            InitializerKind::Code { .. } => unreachable!(),
457        };
458
459        // A tuple field has no name that could be bound here (the `_0` identifiers are considered
460        // implementation detail and not user-facing).
461        let binding = match member {
462            Member::Named(ident) => quote_spanned! { span =>
463                #(#cfgs)*
464                // Allow `non_snake_case` since the same warning is going to be reported for the
465                // struct field.
466                #[allow(unused_variables, non_snake_case)]
467                let #ident = #guard.let_binding();
468            },
469            Member::Unnamed(_) => quote!(),
470        };
471
472        res.extend(quote! {
473            #init
474
475            #binding
476        });
477
478        guards.push(guard);
479        guard_attrs.push(cfgs);
480    }
481    quote! {
482        #res
483        // If execution reaches this point, all fields have been initialized. Therefore we can now
484        // dismiss the guards by forgetting them.
485        #(
486            #(#guard_attrs)*
487            ::core::mem::forget(#guards);
488        )*
489    }
490}
491
492/// Generate the check for ensuring that every field has been initialized and aligned.
493fn make_field_check(
494    fields: &Punctuated<InitializerField, Token![,]>,
495    init_kind: InitKind,
496    path: &Path,
497) -> TokenStream {
498    let field_attrs: Vec<_> = fields
499        .iter()
500        .filter_map(|f| f.kind.member().map(|_| &f.attrs))
501        .collect();
502    let field_name: Vec<_> = fields.iter().filter_map(|f| f.kind.member()).collect();
503    let zeroing_trailer = match init_kind {
504        InitKind::Normal => None,
505        InitKind::Zeroing => Some(quote! {
506            ..::core::mem::zeroed()
507        }),
508    };
509    quote_spanned! { Span::mixed_site() =>
510        #[allow(unreachable_code)]
511        // We use unreachable code to perform field checks. They're still checked by the compiler.
512        // SAFETY: this code is never executed.
513        let _ = || unsafe {
514            // Create references to ensure that the initialized field is properly aligned.
515            // Unaligned fields will cause the compiler to emit E0793. We do not support
516            // unaligned fields since `Init::__init` requires an aligned pointer; the call to
517            // `ptr::write` for value-initialization case has the same requirement.
518            #(
519                #(#field_attrs)*
520                let _ = &(*slot).#field_name;
521            )*
522
523            // If the zeroing trailer is not present, this checks that all fields have been
524            // mentioned exactly once. If the zeroing trailer is present, all missing fields will be
525            // zeroed, so this checks that all fields have been mentioned at most once. The use of
526            // struct initializer will still generate very natural error messages for any misuse.
527            ::core::ptr::write(slot, #path {
528                #(
529                    #(#field_attrs)*
530                    #field_name: loop {},
531                )*
532                #zeroing_trailer
533            })
534        };
535    }
536}
537
538impl InitExprStruct {
539    fn parse_with_path(path: Path, input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
540        let content;
541        let brace_token = braced!(content in input);
542        let mut fields = Punctuated::new();
543        loop {
544            let lh = content.lookahead1();
545            if lh.peek(End) || lh.peek(Token![..]) {
546                break;
547            } else if lh.peek(Ident) || lh.peek(LitInt) || lh.peek(Token![_]) || lh.peek(Token![#])
548            {
549                fields.push_value(content.parse()?);
550                let lh = content.lookahead1();
551                if lh.peek(End) {
552                    break;
553                } else if lh.peek(Token![,]) {
554                    fields.push_punct(content.parse()?);
555                } else {
556                    return Err(lh.error());
557                }
558            } else {
559                return Err(lh.error());
560            }
561        }
562        let rest = content
563            .peek(Token![..])
564            .then(|| Ok::<_, syn::Error>((content.parse()?, content.parse()?)))
565            .transpose()?;
566        Ok(Self {
567            path,
568            brace_token,
569            fields,
570            rest,
571        })
572    }
573}
574
575impl InitExprTuple {
576    fn parse_with_path(path: Path, input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
577        let content;
578        let paren_token = parenthesized!(content in input);
579        let mut fields = Punctuated::new();
580        while !content.is_empty() {
581            fields.push_value(InitTupleField {
582                attrs: content.call(Attribute::parse_outer)?,
583                left_arrow_token: content.parse()?,
584                value: content.parse()?,
585            });
586            if content.is_empty() {
587                break;
588            }
589            fields.push_punct(content.parse()?);
590        }
591        Ok(InitExprTuple {
592            path,
593            paren_token,
594            fields,
595        })
596    }
597}
598
599impl Parse for Initializer {
600    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
601        let attrs = input.call(Attribute::parse_outer)?;
602        let this = input.peek(Token![&]).then(|| input.parse()).transpose()?;
603        let path = input.parse()?;
604        let kind = if input.peek(token::Brace) {
605            InitExprKind::Struct(InitExprStruct::parse_with_path(path, input)?)
606        } else if input.peek(token::Paren) {
607            InitExprKind::Tuple(InitExprTuple::parse_with_path(path, input)?)
608        } else {
609            return Err(input.error("expected curly braces or parentheses"));
610        };
611        let error = input
612            .peek(Token![?])
613            .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?)))
614            .transpose()?;
615        let attrs = attrs
616            .into_iter()
617            .map(|a| {
618                if a.path().is_ident("default_error") {
619                    a.parse_args::<DefaultErrorAttribute>()
620                        .map(InitializerAttribute::DefaultError)
621                } else {
622                    Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
623                }
624            })
625            .collect::<Result<Vec<_>, _>>()?;
626        Ok(Self {
627            attrs,
628            this,
629            kind,
630            error,
631        })
632    }
633}
634
635impl Parse for DefaultErrorAttribute {
636    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
637        Ok(Self { ty: input.parse()? })
638    }
639}
640
641impl Parse for This {
642    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
643        Ok(Self {
644            _and_token: input.parse()?,
645            ident: input.parse()?,
646            _in_token: input.parse()?,
647        })
648    }
649}
650
651impl Parse for InitializerField {
652    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
653        let attrs = input.call(Attribute::parse_outer)?;
654        Ok(Self {
655            attrs,
656            kind: input.parse()?,
657        })
658    }
659}
660
661impl Parse for InitializerKind {
662    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
663        let lh = input.lookahead1();
664        let member = if lh.peek(Token![_]) {
665            return Ok(Self::Code {
666                _underscore_token: input.parse()?,
667                _colon_token: input.parse()?,
668                block: input.parse()?,
669            });
670        } else if lh.peek(Ident) || lh.peek(LitInt) {
671            input.parse::<Member>()?
672        } else {
673            return Err(lh.error());
674        };
675
676        let lh = input.lookahead1();
677        if lh.peek(Token![<-]) {
678            Ok(Self::Init {
679                member,
680                _left_arrow_token: input.parse()?,
681                value: input.parse()?,
682            })
683        } else if lh.peek(Token![:]) {
684            Ok(Self::Value {
685                member,
686                value: Some((input.parse()?, input.parse()?)),
687            })
688        } else if matches!(member, Member::Named(_)) && (lh.peek(Token![,]) || lh.peek(End)) {
689            // Short-hand syntax, available for named fields only.
690            Ok(Self::Value {
691                member,
692                value: None,
693            })
694        } else {
695            Err(lh.error())
696        }
697    }
698}
699
700impl<Kind: ToTokens> ToTokens for Initializer<Kind> {
701    fn to_tokens(&self, tokens: &mut TokenStream) {
702        let Self {
703            attrs,
704            this,
705            kind,
706            error,
707        } = self;
708        tokens.append_all(attrs);
709        this.to_tokens(tokens);
710        kind.to_tokens(tokens);
711        if let Some((question, ty)) = error {
712            question.to_tokens(tokens);
713            ty.to_tokens(tokens);
714        }
715    }
716}
717
718impl ToTokens for InitExprKind {
719    fn to_tokens(&self, tokens: &mut TokenStream) {
720        match self {
721            Self::Struct(init) => init.to_tokens(tokens),
722            Self::Tuple(init) => init.to_tokens(tokens),
723        }
724    }
725}
726
727impl ToTokens for InitExprStruct {
728    fn to_tokens(&self, tokens: &mut TokenStream) {
729        let Self {
730            path,
731            brace_token,
732            fields,
733            rest,
734        } = self;
735        path.to_tokens(tokens);
736        brace_token.surround(tokens, |tokens| {
737            fields.to_tokens(tokens);
738            if let Some((dotdot, expr)) = rest {
739                dotdot.to_tokens(tokens);
740                expr.to_tokens(tokens);
741            }
742        });
743    }
744}
745
746impl ToTokens for InitExprTuple {
747    fn to_tokens(&self, tokens: &mut TokenStream) {
748        let Self {
749            path,
750            paren_token,
751            fields,
752        } = self;
753        path.to_tokens(tokens);
754        paren_token.surround(tokens, |tokens| fields.to_tokens(tokens));
755    }
756}
757
758impl ToTokens for InitTupleField {
759    fn to_tokens(&self, tokens: &mut TokenStream) {
760        let Self {
761            attrs,
762            left_arrow_token,
763            value,
764        } = self;
765        tokens.append_all(attrs);
766        left_arrow_token.to_tokens(tokens);
767        value.to_tokens(tokens);
768    }
769}
770
771impl ToTokens for InitializerAttribute {
772    fn to_tokens(&self, tokens: &mut TokenStream) {
773        match self {
774            Self::DefaultError(DefaultErrorAttribute { ty }) => {
775                quote!(#[default_error(#ty)]).to_tokens(tokens);
776            }
777        }
778    }
779}
780
781impl ToTokens for This {
782    fn to_tokens(&self, tokens: &mut TokenStream) {
783        let Self {
784            _and_token,
785            ident,
786            _in_token,
787        } = self;
788        _and_token.to_tokens(tokens);
789        ident.to_tokens(tokens);
790        _in_token.to_tokens(tokens);
791    }
792}
793
794impl ToTokens for InitializerField {
795    fn to_tokens(&self, tokens: &mut TokenStream) {
796        let Self { attrs, kind } = self;
797        tokens.append_all(attrs);
798        kind.to_tokens(tokens);
799    }
800}
801
802impl ToTokens for InitializerKind {
803    fn to_tokens(&self, tokens: &mut TokenStream) {
804        match self {
805            Self::Value { member, value } => {
806                member.to_tokens(tokens);
807                if let Some((colon, expr)) = value {
808                    colon.to_tokens(tokens);
809                    expr.to_tokens(tokens);
810                }
811            }
812            Self::Init {
813                member,
814                _left_arrow_token,
815                value,
816            } => {
817                member.to_tokens(tokens);
818                _left_arrow_token.to_tokens(tokens);
819                value.to_tokens(tokens);
820            }
821            Self::Code {
822                _underscore_token,
823                _colon_token,
824                block,
825            } => {
826                _underscore_token.to_tokens(tokens);
827                _colon_token.to_tokens(tokens);
828                block.to_tokens(tokens);
829            }
830        }
831    }
832}