1use crate::attr::Attribute;
2use crate::expr::Member;
3use crate::ident::Ident;
4use crate::path::{Path, QSelf};
5use crate::punctuated::Punctuated;
6use crate::token;
7use crate::ty::Type;
8use proc_macro2::TokenStream;
9
10pub use crate::expr::{
11    ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
12    ExprRange as PatRange,
13};
14
15ast_enum_of_structs! {
16    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
25    #[non_exhaustive]
26    pub enum Pat {
27        Const(PatConst),
29
30        Ident(PatIdent),
32
33        Lit(PatLit),
35
36        Macro(PatMacro),
38
39        Or(PatOr),
41
42        Paren(PatParen),
44
45        Path(PatPath),
53
54        Range(PatRange),
56
57        Reference(PatReference),
59
60        Rest(PatRest),
62
63        Slice(PatSlice),
65
66        Struct(PatStruct),
68
69        Tuple(PatTuple),
71
72        TupleStruct(PatTupleStruct),
74
75        Type(PatType),
77
78        Verbatim(TokenStream),
80
81        Wild(PatWild),
83
84        }
102}
103
104ast_struct! {
105    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
110    pub struct PatIdent {
111        pub attrs: Vec<Attribute>,
112        pub by_ref: Option<Token![ref]>,
113        pub mutability: Option<Token![mut]>,
114        pub ident: Ident,
115        pub subpat: Option<(Token![@], Box<Pat>)>,
116    }
117}
118
119ast_struct! {
120    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
122    pub struct PatOr {
123        pub attrs: Vec<Attribute>,
124        pub leading_vert: Option<Token![|]>,
125        pub cases: Punctuated<Pat, Token![|]>,
126    }
127}
128
129ast_struct! {
130    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
132    pub struct PatParen {
133        pub attrs: Vec<Attribute>,
134        pub paren_token: token::Paren,
135        pub pat: Box<Pat>,
136    }
137}
138
139ast_struct! {
140    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
142    pub struct PatReference {
143        pub attrs: Vec<Attribute>,
144        pub and_token: Token![&],
145        pub mutability: Option<Token![mut]>,
146        pub pat: Box<Pat>,
147    }
148}
149
150ast_struct! {
151    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
153    pub struct PatRest {
154        pub attrs: Vec<Attribute>,
155        pub dot2_token: Token![..],
156    }
157}
158
159ast_struct! {
160    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
162    pub struct PatSlice {
163        pub attrs: Vec<Attribute>,
164        pub bracket_token: token::Bracket,
165        pub elems: Punctuated<Pat, Token![,]>,
166    }
167}
168
169ast_struct! {
170    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
172    pub struct PatStruct {
173        pub attrs: Vec<Attribute>,
174        pub qself: Option<QSelf>,
175        pub path: Path,
176        pub brace_token: token::Brace,
177        pub fields: Punctuated<FieldPat, Token![,]>,
178        pub rest: Option<PatRest>,
179    }
180}
181
182ast_struct! {
183    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
185    pub struct PatTuple {
186        pub attrs: Vec<Attribute>,
187        pub paren_token: token::Paren,
188        pub elems: Punctuated<Pat, Token![,]>,
189    }
190}
191
192ast_struct! {
193    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
195    pub struct PatTupleStruct {
196        pub attrs: Vec<Attribute>,
197        pub qself: Option<QSelf>,
198        pub path: Path,
199        pub paren_token: token::Paren,
200        pub elems: Punctuated<Pat, Token![,]>,
201    }
202}
203
204ast_struct! {
205    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
207    pub struct PatType {
208        pub attrs: Vec<Attribute>,
209        pub pat: Box<Pat>,
210        pub colon_token: Token![:],
211        pub ty: Box<Type>,
212    }
213}
214
215ast_struct! {
216    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
218    pub struct PatWild {
219        pub attrs: Vec<Attribute>,
220        pub underscore_token: Token![_],
221    }
222}
223
224ast_struct! {
225    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
230    pub struct FieldPat {
231        pub attrs: Vec<Attribute>,
232        pub member: Member,
233        pub colon_token: Option<Token![:]>,
234        pub pat: Box<Pat>,
235    }
236}
237
238#[cfg(feature = "parsing")]
239pub(crate) mod parsing {
240    use crate::attr::Attribute;
241    use crate::error::{self, Result};
242    use crate::expr::{
243        Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits,
244    };
245    use crate::ext::IdentExt as _;
246    use crate::ident::Ident;
247    use crate::lit::Lit;
248    use crate::mac::{self, Macro};
249    use crate::parse::{Parse, ParseBuffer, ParseStream};
250    use crate::pat::{
251        FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
252        PatTuple, PatTupleStruct, PatType, PatWild,
253    };
254    use crate::path::{self, Path, QSelf};
255    use crate::punctuated::Punctuated;
256    use crate::stmt::Block;
257    use crate::token;
258    use crate::verbatim;
259    use proc_macro2::TokenStream;
260
261    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
262    impl Pat {
263        pub fn parse_single(input: ParseStream) -> Result<Self> {
288            let begin = input.fork();
289            let lookahead = input.lookahead1();
290            if lookahead.peek(Ident)
291                && (input.peek2(Token![::])
292                    || input.peek2(Token![!])
293                    || input.peek2(token::Brace)
294                    || input.peek2(token::Paren)
295                    || input.peek2(Token![..]))
296                || input.peek(Token![self]) && input.peek2(Token![::])
297                || lookahead.peek(Token![::])
298                || lookahead.peek(Token![<])
299                || input.peek(Token![Self])
300                || input.peek(Token![super])
301                || input.peek(Token![crate])
302            {
303                pat_path_or_macro_or_struct_or_range(input)
304            } else if lookahead.peek(Token![_]) {
305                input.call(pat_wild).map(Pat::Wild)
306            } else if input.peek(Token![box]) {
307                pat_box(begin, input)
308            } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])
309            {
310                pat_lit_or_range(input)
311            } else if lookahead.peek(Token![ref])
312                || lookahead.peek(Token![mut])
313                || input.peek(Token![self])
314                || input.peek(Ident)
315            {
316                input.call(pat_ident).map(Pat::Ident)
317            } else if lookahead.peek(Token![&]) {
318                input.call(pat_reference).map(Pat::Reference)
319            } else if lookahead.peek(token::Paren) {
320                input.call(pat_paren_or_tuple)
321            } else if lookahead.peek(token::Bracket) {
322                input.call(pat_slice).map(Pat::Slice)
323            } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
324                pat_range_half_open(input)
325            } else if lookahead.peek(Token![const]) {
326                input.call(pat_const).map(Pat::Verbatim)
327            } else {
328                Err(lookahead.error())
329            }
330        }
331
332        pub fn parse_multi(input: ParseStream) -> Result<Self> {
334            multi_pat_impl(input, None)
335        }
336
337        pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> {
380            let leading_vert: Option<Token![|]> = input.parse()?;
381            multi_pat_impl(input, leading_vert)
382        }
383    }
384
385    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
386    impl Parse for PatType {
387        fn parse(input: ParseStream) -> Result<Self> {
388            Ok(PatType {
389                attrs: Vec::new(),
390                pat: Box::new(Pat::parse_single(input)?),
391                colon_token: input.parse()?,
392                ty: input.parse()?,
393            })
394        }
395    }
396
397    fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> {
398        let mut pat = Pat::parse_single(input)?;
399        if leading_vert.is_some()
400            || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
401        {
402            let mut cases = Punctuated::new();
403            cases.push_value(pat);
404            while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) {
405                let punct = input.parse()?;
406                cases.push_punct(punct);
407                let pat = Pat::parse_single(input)?;
408                cases.push_value(pat);
409            }
410            pat = Pat::Or(PatOr {
411                attrs: Vec::new(),
412                leading_vert,
413                cases,
414            });
415        }
416        Ok(pat)
417    }
418
419    fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
420        let expr_style = true;
421        let (qself, path) = path::parsing::qpath(input, expr_style)?;
422
423        if qself.is_none()
424            && input.peek(Token![!])
425            && !input.peek(Token![!=])
426            && path.is_mod_style()
427        {
428            let bang_token: Token![!] = input.parse()?;
429            let (delimiter, tokens) = mac::parse_delimiter(input)?;
430            return Ok(Pat::Macro(ExprMacro {
431                attrs: Vec::new(),
432                mac: Macro {
433                    path,
434                    bang_token,
435                    delimiter,
436                    tokens,
437                },
438            }));
439        }
440
441        if input.peek(token::Brace) {
442            pat_struct(input, qself, path).map(Pat::Struct)
443        } else if input.peek(token::Paren) {
444            pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
445        } else if input.peek(Token![..]) {
446            pat_range(input, qself, path)
447        } else {
448            Ok(Pat::Path(ExprPath {
449                attrs: Vec::new(),
450                qself,
451                path,
452            }))
453        }
454    }
455
456    fn pat_wild(input: ParseStream) -> Result<PatWild> {
457        Ok(PatWild {
458            attrs: Vec::new(),
459            underscore_token: input.parse()?,
460        })
461    }
462
463    fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> {
464        input.parse::<Token![box]>()?;
465        Pat::parse_single(input)?;
466        Ok(Pat::Verbatim(verbatim::between(&begin, input)))
467    }
468
469    fn pat_ident(input: ParseStream) -> Result<PatIdent> {
470        Ok(PatIdent {
471            attrs: Vec::new(),
472            by_ref: input.parse()?,
473            mutability: input.parse()?,
474            ident: {
475                if input.peek(Token![self]) {
476                    input.call(Ident::parse_any)?
477                } else {
478                    input.parse()?
479                }
480            },
481            subpat: {
482                if input.peek(Token![@]) {
483                    let at_token: Token![@] = input.parse()?;
484                    let subpat = Pat::parse_single(input)?;
485                    Some((at_token, Box::new(subpat)))
486                } else {
487                    None
488                }
489            },
490        })
491    }
492
493    fn pat_tuple_struct(
494        input: ParseStream,
495        qself: Option<QSelf>,
496        path: Path,
497    ) -> Result<PatTupleStruct> {
498        let content;
499        let paren_token = parenthesized!(content in input);
500
501        let mut elems = Punctuated::new();
502        while !content.is_empty() {
503            let value = Pat::parse_multi_with_leading_vert(&content)?;
504            elems.push_value(value);
505            if content.is_empty() {
506                break;
507            }
508            let punct = content.parse()?;
509            elems.push_punct(punct);
510        }
511
512        Ok(PatTupleStruct {
513            attrs: Vec::new(),
514            qself,
515            path,
516            paren_token,
517            elems,
518        })
519    }
520
521    fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
522        let content;
523        let brace_token = braced!(content in input);
524
525        let mut fields = Punctuated::new();
526        let mut rest = None;
527        while !content.is_empty() {
528            let attrs = content.call(Attribute::parse_outer)?;
529            if content.peek(Token![..]) {
530                rest = Some(PatRest {
531                    attrs,
532                    dot2_token: content.parse()?,
533                });
534                break;
535            }
536            let mut value = content.call(field_pat)?;
537            value.attrs = attrs;
538            fields.push_value(value);
539            if content.is_empty() {
540                break;
541            }
542            let punct: Token![,] = content.parse()?;
543            fields.push_punct(punct);
544        }
545
546        Ok(PatStruct {
547            attrs: Vec::new(),
548            qself,
549            path,
550            brace_token,
551            fields,
552            rest,
553        })
554    }
555
556    fn field_pat(input: ParseStream) -> Result<FieldPat> {
557        let begin = input.fork();
558        let boxed: Option<Token![box]> = input.parse()?;
559        let by_ref: Option<Token![ref]> = input.parse()?;
560        let mutability: Option<Token![mut]> = input.parse()?;
561
562        let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
563            input.parse().map(Member::Named)
564        } else {
565            input.parse()
566        }?;
567
568        if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
569            || !member.is_named()
570        {
571            return Ok(FieldPat {
572                attrs: Vec::new(),
573                member,
574                colon_token: Some(input.parse()?),
575                pat: Box::new(Pat::parse_multi_with_leading_vert(input)?),
576            });
577        }
578
579        let ident = match member {
580            Member::Named(ident) => ident,
581            Member::Unnamed(_) => unreachable!(),
582        };
583
584        let pat = if boxed.is_some() {
585            Pat::Verbatim(verbatim::between(&begin, input))
586        } else {
587            Pat::Ident(PatIdent {
588                attrs: Vec::new(),
589                by_ref,
590                mutability,
591                ident: ident.clone(),
592                subpat: None,
593            })
594        };
595
596        Ok(FieldPat {
597            attrs: Vec::new(),
598            member: Member::Named(ident),
599            colon_token: None,
600            pat: Box::new(pat),
601        })
602    }
603
604    fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> {
605        let limits = RangeLimits::parse_obsolete(input)?;
606        let end = input.call(pat_range_bound)?;
607        if let (RangeLimits::Closed(_), None) = (&limits, &end) {
608            return Err(input.error("expected range upper bound"));
609        }
610        Ok(Pat::Range(ExprRange {
611            attrs: Vec::new(),
612            start: Some(Box::new(Expr::Path(ExprPath {
613                attrs: Vec::new(),
614                qself,
615                path,
616            }))),
617            limits,
618            end: end.map(PatRangeBound::into_expr),
619        }))
620    }
621
622    fn pat_range_half_open(input: ParseStream) -> Result<Pat> {
623        let limits: RangeLimits = input.parse()?;
624        let end = input.call(pat_range_bound)?;
625        if end.is_some() {
626            Ok(Pat::Range(ExprRange {
627                attrs: Vec::new(),
628                start: None,
629                limits,
630                end: end.map(PatRangeBound::into_expr),
631            }))
632        } else {
633            match limits {
634                RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
635                    attrs: Vec::new(),
636                    dot2_token,
637                })),
638                RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
639            }
640        }
641    }
642
643    fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> {
644        let content;
645        let paren_token = parenthesized!(content in input);
646
647        let mut elems = Punctuated::new();
648        while !content.is_empty() {
649            let value = Pat::parse_multi_with_leading_vert(&content)?;
650            if content.is_empty() {
651                if elems.is_empty() && !matches!(value, Pat::Rest(_)) {
652                    return Ok(Pat::Paren(PatParen {
653                        attrs: Vec::new(),
654                        paren_token,
655                        pat: Box::new(value),
656                    }));
657                }
658                elems.push_value(value);
659                break;
660            }
661            elems.push_value(value);
662            let punct = content.parse()?;
663            elems.push_punct(punct);
664        }
665
666        Ok(Pat::Tuple(PatTuple {
667            attrs: Vec::new(),
668            paren_token,
669            elems,
670        }))
671    }
672
673    fn pat_reference(input: ParseStream) -> Result<PatReference> {
674        Ok(PatReference {
675            attrs: Vec::new(),
676            and_token: input.parse()?,
677            mutability: input.parse()?,
678            pat: Box::new(Pat::parse_single(input)?),
679        })
680    }
681
682    fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
683        let start = input.call(pat_range_bound)?.unwrap();
684        if input.peek(Token![..]) {
685            let limits = RangeLimits::parse_obsolete(input)?;
686            let end = input.call(pat_range_bound)?;
687            if let (RangeLimits::Closed(_), None) = (&limits, &end) {
688                return Err(input.error("expected range upper bound"));
689            }
690            Ok(Pat::Range(ExprRange {
691                attrs: Vec::new(),
692                start: Some(start.into_expr()),
693                limits,
694                end: end.map(PatRangeBound::into_expr),
695            }))
696        } else {
697            Ok(start.into_pat())
698        }
699    }
700
701    enum PatRangeBound {
703        Const(ExprConst),
704        Lit(ExprLit),
705        Path(ExprPath),
706    }
707
708    impl PatRangeBound {
709        fn into_expr(self) -> Box<Expr> {
710            Box::new(match self {
711                PatRangeBound::Const(pat) => Expr::Const(pat),
712                PatRangeBound::Lit(pat) => Expr::Lit(pat),
713                PatRangeBound::Path(pat) => Expr::Path(pat),
714            })
715        }
716
717        fn into_pat(self) -> Pat {
718            match self {
719                PatRangeBound::Const(pat) => Pat::Const(pat),
720                PatRangeBound::Lit(pat) => Pat::Lit(pat),
721                PatRangeBound::Path(pat) => Pat::Path(pat),
722            }
723        }
724    }
725
726    fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> {
727        if input.is_empty()
728            || input.peek(Token![|])
729            || input.peek(Token![=])
730            || input.peek(Token![:]) && !input.peek(Token![::])
731            || input.peek(Token![,])
732            || input.peek(Token![;])
733            || input.peek(Token![if])
734        {
735            return Ok(None);
736        }
737
738        let lookahead = input.lookahead1();
739        let expr = if lookahead.peek(Lit) {
740            PatRangeBound::Lit(input.parse()?)
741        } else if lookahead.peek(Ident)
742            || lookahead.peek(Token![::])
743            || lookahead.peek(Token![<])
744            || lookahead.peek(Token![self])
745            || lookahead.peek(Token![Self])
746            || lookahead.peek(Token![super])
747            || lookahead.peek(Token![crate])
748        {
749            PatRangeBound::Path(input.parse()?)
750        } else if lookahead.peek(Token![const]) {
751            PatRangeBound::Const(input.parse()?)
752        } else {
753            return Err(lookahead.error());
754        };
755
756        Ok(Some(expr))
757    }
758
759    fn pat_slice(input: ParseStream) -> Result<PatSlice> {
760        let content;
761        let bracket_token = bracketed!(content in input);
762
763        let mut elems = Punctuated::new();
764        while !content.is_empty() {
765            let value = Pat::parse_multi_with_leading_vert(&content)?;
766            match value {
767                Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => {
768                    let (start, end) = match pat.limits {
769                        RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]),
770                        RangeLimits::Closed(dot_dot_eq) => {
771                            (dot_dot_eq.spans[0], dot_dot_eq.spans[2])
772                        }
773                    };
774                    let msg = "range pattern is not allowed unparenthesized inside slice pattern";
775                    return Err(error::new2(start, end, msg));
776                }
777                _ => {}
778            }
779            elems.push_value(value);
780            if content.is_empty() {
781                break;
782            }
783            let punct = content.parse()?;
784            elems.push_punct(punct);
785        }
786
787        Ok(PatSlice {
788            attrs: Vec::new(),
789            bracket_token,
790            elems,
791        })
792    }
793
794    fn pat_const(input: ParseStream) -> Result<TokenStream> {
795        let begin = input.fork();
796        input.parse::<Token![const]>()?;
797
798        let content;
799        braced!(content in input);
800        content.call(Attribute::parse_inner)?;
801        content.call(Block::parse_within)?;
802
803        Ok(verbatim::between(&begin, input))
804    }
805}
806
807#[cfg(feature = "printing")]
808mod printing {
809    use crate::attr::FilterAttrs;
810    use crate::pat::{
811        FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
812        PatTuple, PatTupleStruct, PatType, PatWild,
813    };
814    use crate::path;
815    use crate::path::printing::PathStyle;
816    use proc_macro2::TokenStream;
817    use quote::{ToTokens, TokenStreamExt};
818
819    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
820    impl ToTokens for PatIdent {
821        fn to_tokens(&self, tokens: &mut TokenStream) {
822            tokens.append_all(self.attrs.outer());
823            self.by_ref.to_tokens(tokens);
824            self.mutability.to_tokens(tokens);
825            self.ident.to_tokens(tokens);
826            if let Some((at_token, subpat)) = &self.subpat {
827                at_token.to_tokens(tokens);
828                subpat.to_tokens(tokens);
829            }
830        }
831    }
832
833    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
834    impl ToTokens for PatOr {
835        fn to_tokens(&self, tokens: &mut TokenStream) {
836            tokens.append_all(self.attrs.outer());
837            self.leading_vert.to_tokens(tokens);
838            self.cases.to_tokens(tokens);
839        }
840    }
841
842    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
843    impl ToTokens for PatParen {
844        fn to_tokens(&self, tokens: &mut TokenStream) {
845            tokens.append_all(self.attrs.outer());
846            self.paren_token.surround(tokens, |tokens| {
847                self.pat.to_tokens(tokens);
848            });
849        }
850    }
851
852    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
853    impl ToTokens for PatReference {
854        fn to_tokens(&self, tokens: &mut TokenStream) {
855            tokens.append_all(self.attrs.outer());
856            self.and_token.to_tokens(tokens);
857            self.mutability.to_tokens(tokens);
858            self.pat.to_tokens(tokens);
859        }
860    }
861
862    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
863    impl ToTokens for PatRest {
864        fn to_tokens(&self, tokens: &mut TokenStream) {
865            tokens.append_all(self.attrs.outer());
866            self.dot2_token.to_tokens(tokens);
867        }
868    }
869
870    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
871    impl ToTokens for PatSlice {
872        fn to_tokens(&self, tokens: &mut TokenStream) {
873            tokens.append_all(self.attrs.outer());
874            self.bracket_token.surround(tokens, |tokens| {
875                self.elems.to_tokens(tokens);
876            });
877        }
878    }
879
880    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
881    impl ToTokens for PatStruct {
882        fn to_tokens(&self, tokens: &mut TokenStream) {
883            tokens.append_all(self.attrs.outer());
884            path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
885            self.brace_token.surround(tokens, |tokens| {
886                self.fields.to_tokens(tokens);
887                if !self.fields.empty_or_trailing() && self.rest.is_some() {
889                    <Token![,]>::default().to_tokens(tokens);
890                }
891                self.rest.to_tokens(tokens);
892            });
893        }
894    }
895
896    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
897    impl ToTokens for PatTuple {
898        fn to_tokens(&self, tokens: &mut TokenStream) {
899            tokens.append_all(self.attrs.outer());
900            self.paren_token.surround(tokens, |tokens| {
901                self.elems.to_tokens(tokens);
902                if self.elems.len() == 1
906                    && !self.elems.trailing_punct()
907                    && !matches!(self.elems[0], Pat::Rest { .. })
908                {
909                    <Token![,]>::default().to_tokens(tokens);
910                }
911            });
912        }
913    }
914
915    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
916    impl ToTokens for PatTupleStruct {
917        fn to_tokens(&self, tokens: &mut TokenStream) {
918            tokens.append_all(self.attrs.outer());
919            path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
920            self.paren_token.surround(tokens, |tokens| {
921                self.elems.to_tokens(tokens);
922            });
923        }
924    }
925
926    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
927    impl ToTokens for PatType {
928        fn to_tokens(&self, tokens: &mut TokenStream) {
929            tokens.append_all(self.attrs.outer());
930            self.pat.to_tokens(tokens);
931            self.colon_token.to_tokens(tokens);
932            self.ty.to_tokens(tokens);
933        }
934    }
935
936    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
937    impl ToTokens for PatWild {
938        fn to_tokens(&self, tokens: &mut TokenStream) {
939            tokens.append_all(self.attrs.outer());
940            self.underscore_token.to_tokens(tokens);
941        }
942    }
943
944    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
945    impl ToTokens for FieldPat {
946        fn to_tokens(&self, tokens: &mut TokenStream) {
947            tokens.append_all(self.attrs.outer());
948            if let Some(colon_token) = &self.colon_token {
949                self.member.to_tokens(tokens);
950                colon_token.to_tokens(tokens);
951            }
952            self.pat.to_tokens(tokens);
953        }
954    }
955}