Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/pat.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
use crate::attr::Attribute;
4
use crate::expr::Member;
5
use crate::ident::Ident;
6
use crate::path::{Path, QSelf};
7
use crate::punctuated::Punctuated;
8
use crate::token;
9
use crate::ty::Type;
10
use proc_macro2::TokenStream;
11
12
pub use crate::expr::{
13
ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
14
ExprRange as PatRange,
15
};
16
17
ast_enum_of_structs! {
18
/// A pattern in a local binding, function signature, match expression, or
19
/// various other places.
20
///
21
/// # Syntax tree enum
22
///
23
/// This type is a [syntax tree enum].
24
///
25
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
26
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
27
#[non_exhaustive]
28
pub enum Pat {
29
/// A const block: `const { ... }`.
30
Const(PatConst),
31
32
/// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
33
Ident(PatIdent),
34
35
/// A literal pattern: `0`.
36
Lit(PatLit),
37
38
/// A macro in pattern position.
39
Macro(PatMacro),
40
41
/// A pattern that matches any one of a set of cases.
42
Or(PatOr),
43
44
/// A parenthesized pattern: `(A | B)`.
45
Paren(PatParen),
46
47
/// A path pattern like `Color::Red`, optionally qualified with a
48
/// self-type.
49
///
50
/// Unqualified path patterns can legally refer to variants, structs,
51
/// constants or associated constants. Qualified path patterns like
52
/// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to
53
/// associated constants.
54
Path(PatPath),
55
56
/// A range pattern: `1..=2`.
57
Range(PatRange),
58
59
/// A reference pattern: `&mut var`.
60
Reference(PatReference),
61
62
/// The dots in a tuple or slice pattern: `[0, 1, ..]`.
63
Rest(PatRest),
64
65
/// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
66
Slice(PatSlice),
67
68
/// A struct or struct variant pattern: `Variant { x, y, .. }`.
69
Struct(PatStruct),
70
71
/// A tuple pattern: `(a, b)`.
72
Tuple(PatTuple),
73
74
/// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
75
TupleStruct(PatTupleStruct),
76
77
/// A type ascription pattern: `foo: f64`.
78
Type(PatType),
79
80
/// Tokens in pattern position not interpreted by Syn.
81
Verbatim(TokenStream),
82
83
/// A pattern that matches any value: `_`.
84
Wild(PatWild),
85
86
// For testing exhaustiveness in downstream code, use the following idiom:
87
//
88
// match pat {
89
// #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
90
//
91
// Pat::Box(pat) => {...}
92
// Pat::Ident(pat) => {...}
93
// ...
94
// Pat::Wild(pat) => {...}
95
//
96
// _ => { /* some sane fallback */ }
97
// }
98
//
99
// This way we fail your tests but don't break your library when adding
100
// a variant. You will be notified by a test failure when a variant is
101
// added, so that you can add code to handle it, but your library will
102
// continue to compile and work for downstream users in the interim.
103
}
104
}
105
106
ast_struct! {
107
/// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
108
///
109
/// It may also be a unit struct or struct variant (e.g. `None`), or a
110
/// constant; these cannot be distinguished syntactically.
111
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
112
pub struct PatIdent {
113
pub attrs: Vec<Attribute>,
114
pub by_ref: Option<Token![ref]>,
115
pub mutability: Option<Token![mut]>,
116
pub ident: Ident,
117
pub subpat: Option<(Token![@], Box<Pat>)>,
118
}
119
}
120
121
ast_struct! {
122
/// A pattern that matches any one of a set of cases.
123
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
124
pub struct PatOr {
125
pub attrs: Vec<Attribute>,
126
pub leading_vert: Option<Token![|]>,
127
pub cases: Punctuated<Pat, Token![|]>,
128
}
129
}
130
131
ast_struct! {
132
/// A parenthesized pattern: `(A | B)`.
133
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
134
pub struct PatParen {
135
pub attrs: Vec<Attribute>,
136
pub paren_token: token::Paren,
137
pub pat: Box<Pat>,
138
}
139
}
140
141
ast_struct! {
142
/// A reference pattern: `&mut var`.
143
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
144
pub struct PatReference {
145
pub attrs: Vec<Attribute>,
146
pub and_token: Token![&],
147
pub mutability: Option<Token![mut]>,
148
pub pat: Box<Pat>,
149
}
150
}
151
152
ast_struct! {
153
/// The dots in a tuple or slice pattern: `[0, 1, ..]`.
154
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
155
pub struct PatRest {
156
pub attrs: Vec<Attribute>,
157
pub dot2_token: Token![..],
158
}
159
}
160
161
ast_struct! {
162
/// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
163
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
164
pub struct PatSlice {
165
pub attrs: Vec<Attribute>,
166
pub bracket_token: token::Bracket,
167
pub elems: Punctuated<Pat, Token![,]>,
168
}
169
}
170
171
ast_struct! {
172
/// A struct or struct variant pattern: `Variant { x, y, .. }`.
173
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
174
pub struct PatStruct {
175
pub attrs: Vec<Attribute>,
176
pub qself: Option<QSelf>,
177
pub path: Path,
178
pub brace_token: token::Brace,
179
pub fields: Punctuated<FieldPat, Token![,]>,
180
pub rest: Option<PatRest>,
181
}
182
}
183
184
ast_struct! {
185
/// A tuple pattern: `(a, b)`.
186
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
187
pub struct PatTuple {
188
pub attrs: Vec<Attribute>,
189
pub paren_token: token::Paren,
190
pub elems: Punctuated<Pat, Token![,]>,
191
}
192
}
193
194
ast_struct! {
195
/// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
196
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
197
pub struct PatTupleStruct {
198
pub attrs: Vec<Attribute>,
199
pub qself: Option<QSelf>,
200
pub path: Path,
201
pub paren_token: token::Paren,
202
pub elems: Punctuated<Pat, Token![,]>,
203
}
204
}
205
206
ast_struct! {
207
/// A type ascription pattern: `foo: f64`.
208
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
209
pub struct PatType {
210
pub attrs: Vec<Attribute>,
211
pub pat: Box<Pat>,
212
pub colon_token: Token![:],
213
pub ty: Box<Type>,
214
}
215
}
216
217
ast_struct! {
218
/// A pattern that matches any value: `_`.
219
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
220
pub struct PatWild {
221
pub attrs: Vec<Attribute>,
222
pub underscore_token: Token![_],
223
}
224
}
225
226
ast_struct! {
227
/// A single field in a struct pattern.
228
///
229
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
230
/// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
231
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
232
pub struct FieldPat {
233
pub attrs: Vec<Attribute>,
234
pub member: Member,
235
pub colon_token: Option<Token![:]>,
236
pub pat: Box<Pat>,
237
}
238
}
239
240
#[cfg(feature = "parsing")]
241
pub(crate) mod parsing {
242
use crate::attr::Attribute;
243
use crate::error::{self, Result};
244
use crate::expr::{
245
Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits,
246
};
247
use crate::ext::IdentExt as _;
248
use crate::ident::Ident;
249
use crate::lit::Lit;
250
use crate::mac::{self, Macro};
251
use crate::parse::{Parse, ParseBuffer, ParseStream};
252
use crate::pat::{
253
FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
254
PatTuple, PatTupleStruct, PatType, PatWild,
255
};
256
use crate::path::{self, Path, QSelf};
257
use crate::punctuated::Punctuated;
258
use crate::stmt::Block;
259
use crate::token;
260
use crate::verbatim;
261
use proc_macro2::TokenStream;
262
263
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
264
impl Pat {
265
/// Parse a pattern that does _not_ involve `|` at the top level.
266
///
267
/// This parser matches the behavior of the `$:pat_param` macro_rules
268
/// matcher, and on editions prior to Rust 2021, the behavior of
269
/// `$:pat`.
270
///
271
/// In Rust syntax, some examples of where this syntax would occur are
272
/// in the argument pattern of functions and closures. Patterns using
273
/// `|` are not allowed to occur in these positions.
274
///
275
/// ```compile_fail
276
/// fn f(Some(_) | None: Option<T>) {
277
/// let _ = |Some(_) | None: Option<T>| {};
278
/// // ^^^^^^^^^^^^^^^^^^^^^^^^^??? :(
279
/// }
280
/// ```
281
///
282
/// ```console
283
/// error: top-level or-patterns are not allowed in function parameters
284
/// --> src/main.rs:1:6
285
/// |
286
/// 1 | fn f(Some(_) | None: Option<T>) {
287
/// | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)`
288
/// ```
289
pub fn parse_single(input: ParseStream) -> Result<Self> {
290
let begin = input.fork();
291
let lookahead = input.lookahead1();
292
if lookahead.peek(Ident)
293
&& (input.peek2(Token![::])
294
|| input.peek2(Token![!])
295
|| input.peek2(token::Brace)
296
|| input.peek2(token::Paren)
297
|| input.peek2(Token![..]))
298
|| input.peek(Token![self]) && input.peek2(Token![::])
299
|| lookahead.peek(Token![::])
300
|| lookahead.peek(Token![<])
301
|| input.peek(Token![Self])
302
|| input.peek(Token![super])
303
|| input.peek(Token![crate])
304
{
305
pat_path_or_macro_or_struct_or_range(input)
306
} else if lookahead.peek(Token![_]) {
307
input.call(pat_wild).map(Pat::Wild)
308
} else if input.peek(Token![box]) {
309
pat_box(begin, input)
310
} else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])
311
{
312
pat_lit_or_range(input)
313
} else if lookahead.peek(Token![ref])
314
|| lookahead.peek(Token![mut])
315
|| input.peek(Token![self])
316
|| input.peek(Ident)
317
{
318
input.call(pat_ident).map(Pat::Ident)
319
} else if lookahead.peek(Token![&]) {
320
input.call(pat_reference).map(Pat::Reference)
321
} else if lookahead.peek(token::Paren) {
322
input.call(pat_paren_or_tuple)
323
} else if lookahead.peek(token::Bracket) {
324
input.call(pat_slice).map(Pat::Slice)
325
} else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
326
pat_range_half_open(input)
327
} else if lookahead.peek(Token![const]) {
328
input.call(pat_const).map(Pat::Verbatim)
329
} else {
330
Err(lookahead.error())
331
}
332
}
333
334
/// Parse a pattern, possibly involving `|`, but not a leading `|`.
335
pub fn parse_multi(input: ParseStream) -> Result<Self> {
336
multi_pat_impl(input, None)
337
}
338
339
/// Parse a pattern, possibly involving `|`, possibly including a
340
/// leading `|`.
341
///
342
/// This parser matches the behavior of the Rust 2021 edition's `$:pat`
343
/// macro_rules matcher.
344
///
345
/// In Rust syntax, an example of where this syntax would occur is in
346
/// the pattern of a `match` arm, where the language permits an optional
347
/// leading `|`, although it is not idiomatic to write one there in
348
/// handwritten code.
349
///
350
/// ```
351
/// # let wat = None;
352
/// match wat {
353
/// | None | Some(false) => {}
354
/// | Some(true) => {}
355
/// }
356
/// ```
357
///
358
/// The compiler accepts it only to facilitate some situations in
359
/// macro-generated code where a macro author might need to write:
360
///
361
/// ```
362
/// # macro_rules! doc {
363
/// # ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => {
364
/// match $value {
365
/// $(| $conditions1)* $(| $conditions2)* => $then
366
/// }
367
/// # };
368
/// # }
369
/// #
370
/// # doc!(true, (true), (false), {});
371
/// # doc!(true, (), (true, false), {});
372
/// # doc!(true, (true, false), (), {});
373
/// ```
374
///
375
/// Expressing the same thing correctly in the case that either one (but
376
/// not both) of `$conditions1` and `$conditions2` might be empty,
377
/// without leading `|`, is complex.
378
///
379
/// Use [`Pat::parse_multi`] instead if you are not intending to support
380
/// macro-generated macro input.
381
pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> {
382
let leading_vert: Option<Token![|]> = input.parse()?;
383
multi_pat_impl(input, leading_vert)
384
}
385
}
386
387
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
388
impl Parse for PatType {
389
fn parse(input: ParseStream) -> Result<Self> {
390
Ok(PatType {
391
attrs: Vec::new(),
392
pat: Box::new(Pat::parse_single(input)?),
393
colon_token: input.parse()?,
394
ty: input.parse()?,
395
})
396
}
397
}
398
399
fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> {
400
let mut pat = Pat::parse_single(input)?;
401
if leading_vert.is_some()
402
|| input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
403
{
404
let mut cases = Punctuated::new();
405
cases.push_value(pat);
406
while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) {
407
let punct = input.parse()?;
408
cases.push_punct(punct);
409
let pat = Pat::parse_single(input)?;
410
cases.push_value(pat);
411
}
412
pat = Pat::Or(PatOr {
413
attrs: Vec::new(),
414
leading_vert,
415
cases,
416
});
417
}
418
Ok(pat)
419
}
420
421
fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
422
let expr_style = true;
423
let (qself, path) = path::parsing::qpath(input, expr_style)?;
424
425
if qself.is_none()
426
&& input.peek(Token![!])
427
&& !input.peek(Token![!=])
428
&& path.is_mod_style()
429
{
430
let bang_token: Token![!] = input.parse()?;
431
let (delimiter, tokens) = mac::parse_delimiter(input)?;
432
return Ok(Pat::Macro(ExprMacro {
433
attrs: Vec::new(),
434
mac: Macro {
435
path,
436
bang_token,
437
delimiter,
438
tokens,
439
},
440
}));
441
}
442
443
if input.peek(token::Brace) {
444
pat_struct(input, qself, path).map(Pat::Struct)
445
} else if input.peek(token::Paren) {
446
pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
447
} else if input.peek(Token![..]) {
448
pat_range(input, qself, path)
449
} else {
450
Ok(Pat::Path(ExprPath {
451
attrs: Vec::new(),
452
qself,
453
path,
454
}))
455
}
456
}
457
458
fn pat_wild(input: ParseStream) -> Result<PatWild> {
459
Ok(PatWild {
460
attrs: Vec::new(),
461
underscore_token: input.parse()?,
462
})
463
}
464
465
fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> {
466
input.parse::<Token![box]>()?;
467
Pat::parse_single(input)?;
468
Ok(Pat::Verbatim(verbatim::between(&begin, input)))
469
}
470
471
fn pat_ident(input: ParseStream) -> Result<PatIdent> {
472
Ok(PatIdent {
473
attrs: Vec::new(),
474
by_ref: input.parse()?,
475
mutability: input.parse()?,
476
ident: {
477
if input.peek(Token![self]) {
478
input.call(Ident::parse_any)?
479
} else {
480
input.parse()?
481
}
482
},
483
subpat: {
484
if input.peek(Token![@]) {
485
let at_token: Token![@] = input.parse()?;
486
let subpat = Pat::parse_single(input)?;
487
Some((at_token, Box::new(subpat)))
488
} else {
489
None
490
}
491
},
492
})
493
}
494
495
fn pat_tuple_struct(
496
input: ParseStream,
497
qself: Option<QSelf>,
498
path: Path,
499
) -> Result<PatTupleStruct> {
500
let content;
501
let paren_token = parenthesized!(content in input);
502
503
let mut elems = Punctuated::new();
504
while !content.is_empty() {
505
let value = Pat::parse_multi_with_leading_vert(&content)?;
506
elems.push_value(value);
507
if content.is_empty() {
508
break;
509
}
510
let punct = content.parse()?;
511
elems.push_punct(punct);
512
}
513
514
Ok(PatTupleStruct {
515
attrs: Vec::new(),
516
qself,
517
path,
518
paren_token,
519
elems,
520
})
521
}
522
523
fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
524
let content;
525
let brace_token = braced!(content in input);
526
527
let mut fields = Punctuated::new();
528
let mut rest = None;
529
while !content.is_empty() {
530
let attrs = content.call(Attribute::parse_outer)?;
531
if content.peek(Token![..]) {
532
rest = Some(PatRest {
533
attrs,
534
dot2_token: content.parse()?,
535
});
536
break;
537
}
538
let mut value = content.call(field_pat)?;
539
value.attrs = attrs;
540
fields.push_value(value);
541
if content.is_empty() {
542
break;
543
}
544
let punct: Token![,] = content.parse()?;
545
fields.push_punct(punct);
546
}
547
548
Ok(PatStruct {
549
attrs: Vec::new(),
550
qself,
551
path,
552
brace_token,
553
fields,
554
rest,
555
})
556
}
557
558
fn field_pat(input: ParseStream) -> Result<FieldPat> {
559
let begin = input.fork();
560
let boxed: Option<Token![box]> = input.parse()?;
561
let by_ref: Option<Token![ref]> = input.parse()?;
562
let mutability: Option<Token![mut]> = input.parse()?;
563
564
let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
565
input.parse().map(Member::Named)
566
} else {
567
input.parse()
568
}?;
569
570
if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
571
|| !member.is_named()
572
{
573
return Ok(FieldPat {
574
attrs: Vec::new(),
575
member,
576
colon_token: Some(input.parse()?),
577
pat: Box::new(Pat::parse_multi_with_leading_vert(input)?),
578
});
579
}
580
581
let ident = match member {
582
Member::Named(ident) => ident,
583
Member::Unnamed(_) => unreachable!(),
584
};
585
586
let pat = if boxed.is_some() {
587
Pat::Verbatim(verbatim::between(&begin, input))
588
} else {
589
Pat::Ident(PatIdent {
590
attrs: Vec::new(),
591
by_ref,
592
mutability,
593
ident: ident.clone(),
594
subpat: None,
595
})
596
};
597
598
Ok(FieldPat {
599
attrs: Vec::new(),
600
member: Member::Named(ident),
601
colon_token: None,
602
pat: Box::new(pat),
603
})
604
}
605
606
fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> {
607
let limits = RangeLimits::parse_obsolete(input)?;
608
let end = input.call(pat_range_bound)?;
609
if let (RangeLimits::Closed(_), None) = (&limits, &end) {
610
return Err(input.error("expected range upper bound"));
611
}
612
Ok(Pat::Range(ExprRange {
613
attrs: Vec::new(),
614
start: Some(Box::new(Expr::Path(ExprPath {
615
attrs: Vec::new(),
616
qself,
617
path,
618
}))),
619
limits,
620
end: end.map(PatRangeBound::into_expr),
621
}))
622
}
623
624
fn pat_range_half_open(input: ParseStream) -> Result<Pat> {
625
let limits: RangeLimits = input.parse()?;
626
let end = input.call(pat_range_bound)?;
627
if end.is_some() {
628
Ok(Pat::Range(ExprRange {
629
attrs: Vec::new(),
630
start: None,
631
limits,
632
end: end.map(PatRangeBound::into_expr),
633
}))
634
} else {
635
match limits {
636
RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
637
attrs: Vec::new(),
638
dot2_token,
639
})),
640
RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
641
}
642
}
643
}
644
645
fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> {
646
let content;
647
let paren_token = parenthesized!(content in input);
648
649
let mut elems = Punctuated::new();
650
while !content.is_empty() {
651
let value = Pat::parse_multi_with_leading_vert(&content)?;
652
if content.is_empty() {
653
if elems.is_empty() && !matches!(value, Pat::Rest(_)) {
654
return Ok(Pat::Paren(PatParen {
655
attrs: Vec::new(),
656
paren_token,
657
pat: Box::new(value),
658
}));
659
}
660
elems.push_value(value);
661
break;
662
}
663
elems.push_value(value);
664
let punct = content.parse()?;
665
elems.push_punct(punct);
666
}
667
668
Ok(Pat::Tuple(PatTuple {
669
attrs: Vec::new(),
670
paren_token,
671
elems,
672
}))
673
}
674
675
fn pat_reference(input: ParseStream) -> Result<PatReference> {
676
Ok(PatReference {
677
attrs: Vec::new(),
678
and_token: input.parse()?,
679
mutability: input.parse()?,
680
pat: Box::new(Pat::parse_single(input)?),
681
})
682
}
683
684
fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
685
let start = input.call(pat_range_bound)?.unwrap();
686
if input.peek(Token![..]) {
687
let limits = RangeLimits::parse_obsolete(input)?;
688
let end = input.call(pat_range_bound)?;
689
if let (RangeLimits::Closed(_), None) = (&limits, &end) {
690
return Err(input.error("expected range upper bound"));
691
}
692
Ok(Pat::Range(ExprRange {
693
attrs: Vec::new(),
694
start: Some(start.into_expr()),
695
limits,
696
end: end.map(PatRangeBound::into_expr),
697
}))
698
} else {
699
Ok(start.into_pat())
700
}
701
}
702
703
// Patterns that can appear on either side of a range pattern.
704
enum PatRangeBound {
705
Const(ExprConst),
706
Lit(ExprLit),
707
Path(ExprPath),
708
}
709
710
impl PatRangeBound {
711
fn into_expr(self) -> Box<Expr> {
712
Box::new(match self {
713
PatRangeBound::Const(pat) => Expr::Const(pat),
714
PatRangeBound::Lit(pat) => Expr::Lit(pat),
715
PatRangeBound::Path(pat) => Expr::Path(pat),
716
})
717
}
718
719
fn into_pat(self) -> Pat {
720
match self {
721
PatRangeBound::Const(pat) => Pat::Const(pat),
722
PatRangeBound::Lit(pat) => Pat::Lit(pat),
723
PatRangeBound::Path(pat) => Pat::Path(pat),
724
}
725
}
726
}
727
728
fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> {
729
if input.is_empty()
730
|| input.peek(Token![|])
731
|| input.peek(Token![=])
732
|| input.peek(Token![:]) && !input.peek(Token![::])
733
|| input.peek(Token![,])
734
|| input.peek(Token![;])
735
|| input.peek(Token![if])
736
{
737
return Ok(None);
738
}
739
740
let lookahead = input.lookahead1();
741
let expr = if lookahead.peek(Lit) {
742
PatRangeBound::Lit(input.parse()?)
743
} else if lookahead.peek(Ident)
744
|| lookahead.peek(Token![::])
745
|| lookahead.peek(Token![<])
746
|| lookahead.peek(Token![self])
747
|| lookahead.peek(Token![Self])
748
|| lookahead.peek(Token![super])
749
|| lookahead.peek(Token![crate])
750
{
751
PatRangeBound::Path(input.parse()?)
752
} else if lookahead.peek(Token![const]) {
753
PatRangeBound::Const(input.parse()?)
754
} else {
755
return Err(lookahead.error());
756
};
757
758
Ok(Some(expr))
759
}
760
761
fn pat_slice(input: ParseStream) -> Result<PatSlice> {
762
let content;
763
let bracket_token = bracketed!(content in input);
764
765
let mut elems = Punctuated::new();
766
while !content.is_empty() {
767
let value = Pat::parse_multi_with_leading_vert(&content)?;
768
match value {
769
Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => {
770
let (start, end) = match pat.limits {
771
RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]),
772
RangeLimits::Closed(dot_dot_eq) => {
773
(dot_dot_eq.spans[0], dot_dot_eq.spans[2])
774
}
775
};
776
let msg = "range pattern is not allowed unparenthesized inside slice pattern";
777
return Err(error::new2(start, end, msg));
778
}
779
_ => {}
780
}
781
elems.push_value(value);
782
if content.is_empty() {
783
break;
784
}
785
let punct = content.parse()?;
786
elems.push_punct(punct);
787
}
788
789
Ok(PatSlice {
790
attrs: Vec::new(),
791
bracket_token,
792
elems,
793
})
794
}
795
796
fn pat_const(input: ParseStream) -> Result<TokenStream> {
797
let begin = input.fork();
798
input.parse::<Token![const]>()?;
799
800
let content;
801
braced!(content in input);
802
content.call(Attribute::parse_inner)?;
803
content.call(Block::parse_within)?;
804
805
Ok(verbatim::between(&begin, input))
806
}
807
}
808
809
#[cfg(feature = "printing")]
810
mod printing {
811
use crate::attr::FilterAttrs;
812
use crate::pat::{
813
FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
814
PatTuple, PatTupleStruct, PatType, PatWild,
815
};
816
use crate::path;
817
use crate::path::printing::PathStyle;
818
use proc_macro2::TokenStream;
819
use quote::{ToTokens, TokenStreamExt};
820
821
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
822
impl ToTokens for PatIdent {
823
fn to_tokens(&self, tokens: &mut TokenStream) {
824
tokens.append_all(self.attrs.outer());
825
self.by_ref.to_tokens(tokens);
826
self.mutability.to_tokens(tokens);
827
self.ident.to_tokens(tokens);
828
if let Some((at_token, subpat)) = &self.subpat {
829
at_token.to_tokens(tokens);
830
subpat.to_tokens(tokens);
831
}
832
}
833
}
834
835
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
836
impl ToTokens for PatOr {
837
fn to_tokens(&self, tokens: &mut TokenStream) {
838
tokens.append_all(self.attrs.outer());
839
self.leading_vert.to_tokens(tokens);
840
self.cases.to_tokens(tokens);
841
}
842
}
843
844
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
845
impl ToTokens for PatParen {
846
fn to_tokens(&self, tokens: &mut TokenStream) {
847
tokens.append_all(self.attrs.outer());
848
self.paren_token.surround(tokens, |tokens| {
849
self.pat.to_tokens(tokens);
850
});
851
}
852
}
853
854
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
855
impl ToTokens for PatReference {
856
fn to_tokens(&self, tokens: &mut TokenStream) {
857
tokens.append_all(self.attrs.outer());
858
self.and_token.to_tokens(tokens);
859
self.mutability.to_tokens(tokens);
860
self.pat.to_tokens(tokens);
861
}
862
}
863
864
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
865
impl ToTokens for PatRest {
866
fn to_tokens(&self, tokens: &mut TokenStream) {
867
tokens.append_all(self.attrs.outer());
868
self.dot2_token.to_tokens(tokens);
869
}
870
}
871
872
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
873
impl ToTokens for PatSlice {
874
fn to_tokens(&self, tokens: &mut TokenStream) {
875
tokens.append_all(self.attrs.outer());
876
self.bracket_token.surround(tokens, |tokens| {
877
self.elems.to_tokens(tokens);
878
});
879
}
880
}
881
882
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
883
impl ToTokens for PatStruct {
884
fn to_tokens(&self, tokens: &mut TokenStream) {
885
tokens.append_all(self.attrs.outer());
886
path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
887
self.brace_token.surround(tokens, |tokens| {
888
self.fields.to_tokens(tokens);
889
// NOTE: We need a comma before the dot2 token if it is present.
890
if !self.fields.empty_or_trailing() && self.rest.is_some() {
891
<Token![,]>::default().to_tokens(tokens);
892
}
893
self.rest.to_tokens(tokens);
894
});
895
}
896
}
897
898
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
899
impl ToTokens for PatTuple {
900
fn to_tokens(&self, tokens: &mut TokenStream) {
901
tokens.append_all(self.attrs.outer());
902
self.paren_token.surround(tokens, |tokens| {
903
self.elems.to_tokens(tokens);
904
// If there is only one element, a trailing comma is needed to
905
// distinguish PatTuple from PatParen, unless this is `(..)`
906
// which is a tuple pattern even without comma.
907
if self.elems.len() == 1
908
&& !self.elems.trailing_punct()
909
&& !matches!(self.elems[0], Pat::Rest { .. })
910
{
911
<Token![,]>::default().to_tokens(tokens);
912
}
913
});
914
}
915
}
916
917
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
918
impl ToTokens for PatTupleStruct {
919
fn to_tokens(&self, tokens: &mut TokenStream) {
920
tokens.append_all(self.attrs.outer());
921
path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
922
self.paren_token.surround(tokens, |tokens| {
923
self.elems.to_tokens(tokens);
924
});
925
}
926
}
927
928
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
929
impl ToTokens for PatType {
930
fn to_tokens(&self, tokens: &mut TokenStream) {
931
tokens.append_all(self.attrs.outer());
932
self.pat.to_tokens(tokens);
933
self.colon_token.to_tokens(tokens);
934
self.ty.to_tokens(tokens);
935
}
936
}
937
938
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
939
impl ToTokens for PatWild {
940
fn to_tokens(&self, tokens: &mut TokenStream) {
941
tokens.append_all(self.attrs.outer());
942
self.underscore_token.to_tokens(tokens);
943
}
944
}
945
946
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
947
impl ToTokens for FieldPat {
948
fn to_tokens(&self, tokens: &mut TokenStream) {
949
tokens.append_all(self.attrs.outer());
950
if let Some(colon_token) = &self.colon_token {
951
self.member.to_tokens(tokens);
952
colon_token.to_tokens(tokens);
953
}
954
self.pat.to_tokens(tokens);
955
}
956
}
957
}
958
959