Skip to content

Commit fc8765d

Browse files
committed
Auto merge of rust-lang#61708 - dlrobertson:or-patterns-0, r=centril
Initial implementation of or-patterns An incomplete implementation of or-patterns (e.g. `Some(0 | 1)` as a pattern). This patch set aims to implement initial parsing of `or-patterns`. Related to: rust-lang#54883 CC @alexreg @varkor r? @Centril
2 parents bd1da18 + 1870537 commit fc8765d

30 files changed

+241
-51
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# `or_patterns`
2+
3+
The tracking issue for this feature is: [#54883]
4+
5+
[#54883]: https://github.com/rust-lang/rust/issues/54883
6+
7+
------------------------
8+
9+
The `or_pattern` language feature allows `|` to be arbitrarily nested within
10+
a pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern.
11+
12+
## Examples
13+
14+
```rust,ignore
15+
#![feature(or_patterns)]
16+
17+
pub enum Foo {
18+
Bar,
19+
Baz,
20+
Quux,
21+
}
22+
23+
pub fn example(maybe_foo: Option<Foo>) {
24+
match maybe_foo {
25+
Some(Foo::Bar | Foo::Baz) => {
26+
println!("The value contained `Bar` or `Baz`");
27+
}
28+
Some(_) => {
29+
println!("The value did not contain `Bar` or `Baz`");
30+
}
31+
None => {
32+
println!("The value was `None`");
33+
}
34+
}
35+
}
36+
```

src/librustc/cfg/construct.rs

+5
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
140140
self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
141141
}
142142

143+
PatKind::Or(ref pats) => {
144+
let branches: Vec<_> = pats.iter().map(|p| self.pat(p, pred)).collect();
145+
self.add_ast_node(pat.hir_id.local_id, &branches)
146+
}
147+
143148
PatKind::Slice(ref pre, ref vec, ref post) => {
144149
let pre_exit = self.pats_all(pre.iter(), pred);
145150
let vec_exit = self.pats_all(vec.iter(), pre_exit);

src/librustc/hir/intravisit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
709709
visitor.visit_pat(&field.pat)
710710
}
711711
}
712+
PatKind::Or(ref pats) => walk_list!(visitor, visit_pat, pats),
712713
PatKind::Tuple(ref tuple_elements, _) => {
713714
walk_list!(visitor, visit_pat, tuple_elements);
714715
}

src/librustc/hir/lowering.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2669,6 +2669,9 @@ impl<'a> LoweringContext<'a> {
26692669
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
26702670
hir::PatKind::TupleStruct(qpath, pats, ddpos)
26712671
}
2672+
PatKind::Or(ref pats) => {
2673+
hir::PatKind::Or(pats.iter().map(|x| self.lower_pat(x)).collect())
2674+
}
26722675
PatKind::Path(ref qself, ref path) => {
26732676
let qpath = self.lower_qpath(
26742677
p.id,

src/librustc/hir/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,7 @@ impl Pat {
881881
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
882882
s.iter().all(|p| p.walk_(it))
883883
}
884+
PatKind::Or(ref pats) => pats.iter().all(|p| p.walk_(it)),
884885
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
885886
s.walk_(it)
886887
}
@@ -975,6 +976,10 @@ pub enum PatKind {
975976
/// `0 <= position <= subpats.len()`
976977
TupleStruct(QPath, HirVec<P<Pat>>, Option<usize>),
977978

979+
/// An or-pattern `A | B | C`.
980+
/// Invariant: `pats.len() >= 2`.
981+
Or(HirVec<P<Pat>>),
982+
978983
/// A path pattern for an unit struct/variant or a (maybe-associated) constant.
979984
Path(QPath),
980985

src/librustc/hir/print.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,9 @@ impl<'a> State<'a> {
16871687
self.s.space();
16881688
self.s.word("}");
16891689
}
1690+
PatKind::Or(ref pats) => {
1691+
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(&p));
1692+
}
16901693
PatKind::Tuple(ref elts, ddpos) => {
16911694
self.popen();
16921695
if let Some(ddpos) = ddpos {

src/librustc/middle/mem_categorization.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
12901290
}
12911291
}
12921292

1293+
PatKind::Or(ref pats) => {
1294+
for pat in pats {
1295+
self.cat_pattern_(cmt.clone(), &pat, op)?;
1296+
}
1297+
}
1298+
12931299
PatKind::Binding(.., Some(ref subpat)) => {
12941300
self.cat_pattern_(cmt, &subpat, op)?;
12951301
}

src/librustc_mir/build/matches/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
657657
self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
658658
}
659659
}
660+
PatternKind::Or { ref pats } => {
661+
for pat in pats {
662+
self.visit_bindings(&pat, pattern_user_ty.clone(), f);
663+
}
664+
}
660665
}
661666
}
662667
}

src/librustc_mir/build/matches/simplify.rs

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
195195
candidate.match_pairs.push(MatchPair::new(place, subpattern));
196196
Ok(())
197197
}
198+
199+
PatternKind::Or { .. } => {
200+
Err(match_pair)
201+
}
198202
}
199203
}
200204
}

src/librustc_mir/build/matches/test.rs

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8787
PatternKind::AscribeUserType { .. } |
8888
PatternKind::Array { .. } |
8989
PatternKind::Wild |
90+
PatternKind::Or { .. } |
9091
PatternKind::Binding { .. } |
9192
PatternKind::Leaf { .. } |
9293
PatternKind::Deref { .. } => {
@@ -130,6 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
130131
PatternKind::Slice { .. } |
131132
PatternKind::Array { .. } |
132133
PatternKind::Wild |
134+
PatternKind::Or { .. } |
133135
PatternKind::Binding { .. } |
134136
PatternKind::AscribeUserType { .. } |
135137
PatternKind::Leaf { .. } |

src/librustc_mir/hair/pattern/_match.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
13591359
Some(vec![Slice(pat_len)])
13601360
}
13611361
}
1362+
PatternKind::Or { .. } => {
1363+
bug!("support for or-patterns has not been fully implemented yet.");
1364+
}
13621365
}
13631366
}
13641367

@@ -1884,6 +1887,10 @@ fn specialize<'p, 'a: 'p, 'tcx>(
18841887
"unexpected ctor {:?} for slice pat", constructor)
18851888
}
18861889
}
1890+
1891+
PatternKind::Or { .. } => {
1892+
bug!("support for or-patterns has not been fully implemented yet.");
1893+
}
18871894
};
18881895
debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
18891896

src/librustc_mir/hair/pattern/mod.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ pub enum PatternKind<'tcx> {
175175
slice: Option<Pattern<'tcx>>,
176176
suffix: Vec<Pattern<'tcx>>,
177177
},
178+
179+
/// An or-pattern, e.g. `p | q`.
180+
/// Invariant: `pats.len() >= 2`.
181+
Or {
182+
pats: Vec<Pattern<'tcx>>,
183+
},
178184
}
179185

180186
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -186,6 +192,18 @@ pub struct PatternRange<'tcx> {
186192

187193
impl<'tcx> fmt::Display for Pattern<'tcx> {
188194
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195+
// Printing lists is a chore.
196+
let mut first = true;
197+
let mut start_or_continue = |s| {
198+
if first {
199+
first = false;
200+
""
201+
} else {
202+
s
203+
}
204+
};
205+
let mut start_or_comma = || start_or_continue(", ");
206+
189207
match *self.kind {
190208
PatternKind::Wild => write!(f, "_"),
191209
PatternKind::AscribeUserType { ref subpattern, .. } =>
@@ -224,9 +242,6 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
224242
}
225243
};
226244

227-
let mut first = true;
228-
let mut start_or_continue = || if first { first = false; "" } else { ", " };
229-
230245
if let Some(variant) = variant {
231246
write!(f, "{}", variant.ident)?;
232247

@@ -241,12 +256,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
241256
continue;
242257
}
243258
let name = variant.fields[p.field.index()].ident;
244-
write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
259+
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
245260
printed += 1;
246261
}
247262

248263
if printed < variant.fields.len() {
249-
write!(f, "{}..", start_or_continue())?;
264+
write!(f, "{}..", start_or_comma())?;
250265
}
251266

252267
return write!(f, " }}");
@@ -257,7 +272,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
257272
if num_fields != 0 || variant.is_none() {
258273
write!(f, "(")?;
259274
for i in 0..num_fields {
260-
write!(f, "{}", start_or_continue())?;
275+
write!(f, "{}", start_or_comma())?;
261276

262277
// Common case: the field is where we expect it.
263278
if let Some(p) = subpatterns.get(i) {
@@ -305,25 +320,29 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
305320
}
306321
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
307322
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
308-
let mut first = true;
309-
let mut start_or_continue = || if first { first = false; "" } else { ", " };
310323
write!(f, "[")?;
311324
for p in prefix {
312-
write!(f, "{}{}", start_or_continue(), p)?;
325+
write!(f, "{}{}", start_or_comma(), p)?;
313326
}
314327
if let Some(ref slice) = *slice {
315-
write!(f, "{}", start_or_continue())?;
328+
write!(f, "{}", start_or_comma())?;
316329
match *slice.kind {
317330
PatternKind::Wild => {}
318331
_ => write!(f, "{}", slice)?
319332
}
320333
write!(f, "..")?;
321334
}
322335
for p in suffix {
323-
write!(f, "{}{}", start_or_continue(), p)?;
336+
write!(f, "{}{}", start_or_comma(), p)?;
324337
}
325338
write!(f, "]")
326339
}
340+
PatternKind::Or { ref pats } => {
341+
for pat in pats {
342+
write!(f, "{}{}", start_or_continue(" | "), pat)?;
343+
}
344+
Ok(())
345+
}
327346
}
328347
}
329348
}
@@ -655,6 +674,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
655674

656675
self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
657676
}
677+
678+
PatKind::Or(ref pats) => {
679+
PatternKind::Or {
680+
pats: pats.iter().map(|p| self.lower_pattern(p)).collect(),
681+
}
682+
}
658683
};
659684

660685
Pattern {
@@ -1436,6 +1461,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
14361461
slice: slice.fold_with(folder),
14371462
suffix: suffix.fold_with(folder)
14381463
},
1464+
PatternKind::Or { ref pats } => PatternKind::Or { pats: pats.fold_with(folder) },
14391465
}
14401466
}
14411467
}

src/librustc_typeck/check/_match.rs

+8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5353
let is_non_ref_pat = match pat.node {
5454
PatKind::Struct(..) |
5555
PatKind::TupleStruct(..) |
56+
PatKind::Or(_) |
5657
PatKind::Tuple(..) |
5758
PatKind::Box(_) |
5859
PatKind::Range(..) |
@@ -309,6 +310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
309310
PatKind::Struct(ref qpath, ref fields, etc) => {
310311
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span)
311312
}
313+
PatKind::Or(ref pats) => {
314+
let expected_ty = self.structurally_resolved_type(pat.span, expected);
315+
for pat in pats {
316+
self.check_pat_walk(pat, expected, def_bm, discrim_span);
317+
}
318+
expected_ty
319+
}
312320
PatKind::Tuple(ref elements, ddpos) => {
313321
let mut expected_len = elements.len();
314322
if ddpos.is_some() {

src/librustdoc/clean/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -4107,6 +4107,9 @@ fn name_from_pat(p: &hir::Pat) -> String {
41074107
if etc { ", .." } else { "" }
41084108
)
41094109
}
4110+
PatKind::Or(ref pats) => {
4111+
pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
4112+
}
41104113
PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
41114114
.collect::<Vec<String>>().join(", ")),
41124115
PatKind::Box(ref p) => name_from_pat(&**p),

src/libsyntax/ast.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,10 @@ impl Pat {
572572
match &self.node {
573573
PatKind::Ident(_, _, Some(p)) => p.walk(it),
574574
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
575-
PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
576-
s.iter().all(|p| p.walk(it))
577-
}
575+
PatKind::TupleStruct(_, s)
576+
| PatKind::Tuple(s)
577+
| PatKind::Slice(s)
578+
| PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
578579
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
579580
PatKind::Wild
580581
| PatKind::Rest
@@ -648,6 +649,10 @@ pub enum PatKind {
648649
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
649650
TupleStruct(Path, Vec<P<Pat>>),
650651

652+
/// An or-pattern `A | B | C`.
653+
/// Invariant: `pats.len() >= 2`.
654+
Or(Vec<P<Pat>>),
655+
651656
/// A possibly qualified path pattern.
652657
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
653658
/// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can

src/libsyntax/feature_gate.rs

+5
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ declare_features! (
559559
// Allows `impl Trait` to be used inside type aliases (RFC 2515).
560560
(active, type_alias_impl_trait, "1.38.0", Some(63063), None),
561561

562+
// Allows the use of or-patterns, e.g. `0 | 1`.
563+
(active, or_patterns, "1.38.0", Some(54883), None),
564+
562565
// -------------------------------------------------------------------------
563566
// feature-group-end: actual feature gates
564567
// -------------------------------------------------------------------------
@@ -571,6 +574,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
571574
sym::impl_trait_in_bindings,
572575
sym::generic_associated_types,
573576
sym::const_generics,
577+
sym::or_patterns,
574578
sym::let_chains,
575579
];
576580

@@ -2443,6 +2447,7 @@ pub fn check_crate(krate: &ast::Crate,
24432447
gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental");
24442448
gate_all!(async_closure_spans, async_closure, "async closures are unstable");
24452449
gate_all!(yield_spans, generators, "yield syntax is experimental");
2450+
gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental");
24462451

24472452
let visitor = &mut PostExpansionVisitor {
24482453
context: &ctx,

src/libsyntax/mut_visit.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1050,15 +1050,16 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
10501050
vis.visit_span(span);
10511051
};
10521052
}
1053-
PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
10541053
PatKind::Box(inner) => vis.visit_pat(inner),
10551054
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
10561055
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
10571056
vis.visit_expr(e1);
10581057
vis.visit_expr(e2);
10591058
vis.visit_span(span);
10601059
}
1061-
PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
1060+
PatKind::Tuple(elems)
1061+
| PatKind::Slice(elems)
1062+
| PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
10621063
PatKind::Paren(inner) => vis.visit_pat(inner),
10631064
PatKind::Mac(mac) => vis.visit_mac(mac),
10641065
}

0 commit comments

Comments
 (0)