mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
Initial implementation of or patterns
This commit is contained in:
parent
ac60ca0643
commit
1713ac4bf5
@ -140,6 +140,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
|
||||
}
|
||||
|
||||
PatKind::Or(ref pats) => {
|
||||
let branches: Vec<_> = pats.iter().map(|p| self.pat(p, pred)).collect();
|
||||
self.add_ast_node(pat.hir_id.local_id, &branches)
|
||||
}
|
||||
|
||||
PatKind::Slice(ref pre, ref vec, ref post) => {
|
||||
let pre_exit = self.pats_all(pre.iter(), pred);
|
||||
let vec_exit = self.pats_all(vec.iter(), pre_exit);
|
||||
|
@ -709,6 +709,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||
visitor.visit_pat(&field.pat)
|
||||
}
|
||||
}
|
||||
PatKind::Or(ref pats) => walk_list!(visitor, visit_pat, pats),
|
||||
PatKind::Tuple(ref tuple_elements, _) => {
|
||||
walk_list!(visitor, visit_pat, tuple_elements);
|
||||
}
|
||||
|
@ -2669,6 +2669,9 @@ impl<'a> LoweringContext<'a> {
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
hir::PatKind::TupleStruct(qpath, pats, ddpos)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
hir::PatKind::Or(pats.iter().map(|x| self.lower_pat(x)).collect())
|
||||
}
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
|
@ -882,6 +882,7 @@ impl Pat {
|
||||
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||
s.iter().all(|p| p.walk_(it))
|
||||
}
|
||||
PatKind::Or(ref pats) => pats.iter().all(|p| p.walk_(it)),
|
||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
||||
s.walk_(it)
|
||||
}
|
||||
@ -976,6 +977,9 @@ pub enum PatKind {
|
||||
/// `0 <= position <= subpats.len()`
|
||||
TupleStruct(QPath, HirVec<P<Pat>>, Option<usize>),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
Or(Vec<P<Pat>>),
|
||||
|
||||
/// A path pattern for an unit struct/variant or a (maybe-associated) constant.
|
||||
Path(QPath),
|
||||
|
||||
|
@ -4,7 +4,7 @@ use syntax::source_map::{SourceMap, Spanned};
|
||||
use syntax::parse::ParseSess;
|
||||
use syntax::print::pp::{self, Breaks};
|
||||
use syntax::print::pp::Breaks::{Consistent, Inconsistent};
|
||||
use syntax::print::pprust::{self, Comments, PrintState};
|
||||
use syntax::print::pprust::{self, Comments, PrintState, SeparatorSpacing};
|
||||
use syntax::symbol::kw;
|
||||
use syntax::util::parser::{self, AssocOp, Fixity};
|
||||
use syntax_pos::{self, BytePos, FileName};
|
||||
@ -1687,6 +1687,10 @@ impl<'a> State<'a> {
|
||||
self.s.space();
|
||||
self.s.word("}");
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
let spacing = SeparatorSpacing::Both;
|
||||
self.strsep("|", spacing, Inconsistent, &pats[..], |s, p| s.print_pat(&p))?;
|
||||
}
|
||||
PatKind::Tuple(ref elts, ddpos) => {
|
||||
self.popen();
|
||||
if let Some(ddpos) = ddpos {
|
||||
|
@ -1290,6 +1290,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Or(ref pats) => {
|
||||
for pat in pats {
|
||||
self.cat_pattern_(cmt.clone(), &pat, op)?;
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Binding(.., Some(ref subpat)) => {
|
||||
self.cat_pattern_(cmt, &subpat, op)?;
|
||||
}
|
||||
|
@ -657,6 +657,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
|
||||
}
|
||||
}
|
||||
PatternKind::Or { ref pats } => {
|
||||
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
|
||||
for pat in pats {
|
||||
self.visit_bindings(&pat, &pattern_user_ty.clone(), f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +195,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
candidate.match_pairs.push(MatchPair::new(place, subpattern));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Or { .. } => {
|
||||
Err(match_pair)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
PatternKind::AscribeUserType { .. } |
|
||||
PatternKind::Array { .. } |
|
||||
PatternKind::Wild |
|
||||
PatternKind::Or { .. } |
|
||||
PatternKind::Binding { .. } |
|
||||
PatternKind::Leaf { .. } |
|
||||
PatternKind::Deref { .. } => {
|
||||
@ -130,6 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
PatternKind::Slice { .. } |
|
||||
PatternKind::Array { .. } |
|
||||
PatternKind::Wild |
|
||||
PatternKind::Or { .. } |
|
||||
PatternKind::Binding { .. } |
|
||||
PatternKind::AscribeUserType { .. } |
|
||||
PatternKind::Leaf { .. } |
|
||||
|
@ -75,9 +75,6 @@
|
||||
/// D((r_1, p_(i,2), .., p_(i,n)))
|
||||
/// D((r_2, p_(i,2), .., p_(i,n)))
|
||||
///
|
||||
/// Note that the OR-patterns are not always used directly in Rust, but are used to derive
|
||||
/// the exhaustive integer matching rules, so they're written here for posterity.
|
||||
///
|
||||
/// The algorithm for computing `U`
|
||||
/// -------------------------------
|
||||
/// The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
|
||||
@ -1359,6 +1356,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||
Some(vec![Slice(pat_len)])
|
||||
}
|
||||
}
|
||||
PatternKind::Or { .. } => {
|
||||
bug!("support for or-patterns has not been fully implemented yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1884,6 +1884,10 @@ fn specialize<'p, 'a: 'p, 'tcx>(
|
||||
"unexpected ctor {:?} for slice pat", constructor)
|
||||
}
|
||||
}
|
||||
|
||||
PatternKind::Or { .. } => {
|
||||
bug!("support for or-patterns has not been fully implemented yet.");
|
||||
}
|
||||
};
|
||||
debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
|
||||
|
||||
|
@ -175,6 +175,11 @@ pub enum PatternKind<'tcx> {
|
||||
slice: Option<Pattern<'tcx>>,
|
||||
suffix: Vec<Pattern<'tcx>>,
|
||||
},
|
||||
|
||||
/// or-pattern
|
||||
Or {
|
||||
pats: Vec<Pattern<'tcx>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
@ -186,6 +191,18 @@ pub struct PatternRange<'tcx> {
|
||||
|
||||
impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Printing lists is a chore.
|
||||
let mut first = true;
|
||||
let mut start_or_continue = |s| {
|
||||
if first {
|
||||
first = false;
|
||||
""
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
let mut start_or_comma = || start_or_continue(", ");
|
||||
|
||||
match *self.kind {
|
||||
PatternKind::Wild => write!(f, "_"),
|
||||
PatternKind::AscribeUserType { ref subpattern, .. } =>
|
||||
@ -224,9 +241,6 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut first = true;
|
||||
let mut start_or_continue = || if first { first = false; "" } else { ", " };
|
||||
|
||||
if let Some(variant) = variant {
|
||||
write!(f, "{}", variant.ident)?;
|
||||
|
||||
@ -241,12 +255,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
continue;
|
||||
}
|
||||
let name = variant.fields[p.field.index()].ident;
|
||||
write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
|
||||
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
if printed < variant.fields.len() {
|
||||
write!(f, "{}..", start_or_continue())?;
|
||||
write!(f, "{}..", start_or_comma())?;
|
||||
}
|
||||
|
||||
return write!(f, " }}");
|
||||
@ -257,7 +271,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
if num_fields != 0 || variant.is_none() {
|
||||
write!(f, "(")?;
|
||||
for i in 0..num_fields {
|
||||
write!(f, "{}", start_or_continue())?;
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
|
||||
// Common case: the field is where we expect it.
|
||||
if let Some(p) = subpatterns.get(i) {
|
||||
@ -305,14 +319,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
}
|
||||
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
|
||||
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
let mut first = true;
|
||||
let mut start_or_continue = || if first { first = false; "" } else { ", " };
|
||||
write!(f, "[")?;
|
||||
for p in prefix {
|
||||
write!(f, "{}{}", start_or_continue(), p)?;
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
if let Some(ref slice) = *slice {
|
||||
write!(f, "{}", start_or_continue())?;
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
match *slice.kind {
|
||||
PatternKind::Wild => {}
|
||||
_ => write!(f, "{}", slice)?
|
||||
@ -320,10 +332,16 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
write!(f, "..")?;
|
||||
}
|
||||
for p in suffix {
|
||||
write!(f, "{}{}", start_or_continue(), p)?;
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
PatternKind::Or { ref pats } => {
|
||||
for pat in pats {
|
||||
write!(f, "{}{}", start_or_continue(" | "), pat)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -655,6 +673,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
|
||||
self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
|
||||
}
|
||||
|
||||
PatKind::Or(ref pats) => {
|
||||
PatternKind::Or {
|
||||
pats: pats.iter().map(|p| self.lower_pattern(p)).collect(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Pattern {
|
||||
@ -1436,6 +1460,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
||||
slice: slice.fold_with(folder),
|
||||
suffix: suffix.fold_with(folder)
|
||||
},
|
||||
PatternKind::Or { ref pats } => PatternKind::Or { pats: pats.fold_with(folder) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let is_non_ref_pat = match pat.node {
|
||||
PatKind::Struct(..) |
|
||||
PatKind::TupleStruct(..) |
|
||||
PatKind::Or(_) |
|
||||
PatKind::Tuple(..) |
|
||||
PatKind::Box(_) |
|
||||
PatKind::Range(..) |
|
||||
@ -309,6 +310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PatKind::Struct(ref qpath, ref fields, etc) => {
|
||||
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
||||
for pat in pats {
|
||||
self.check_pat_walk(pat, expected, def_bm, false);
|
||||
}
|
||||
expected_ty
|
||||
}
|
||||
PatKind::Tuple(ref elements, ddpos) => {
|
||||
let mut expected_len = elements.len();
|
||||
if ddpos.is_some() {
|
||||
|
@ -4107,6 +4107,9 @@ fn name_from_pat(p: &hir::Pat) -> String {
|
||||
if etc { ", .." } else { "" }
|
||||
)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
|
||||
}
|
||||
PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
|
||||
.collect::<Vec<String>>().join(", ")),
|
||||
PatKind::Box(ref p) => name_from_pat(&**p),
|
||||
|
@ -572,9 +572,10 @@ impl Pat {
|
||||
match &self.node {
|
||||
PatKind::Ident(_, _, Some(p)) => p.walk(it),
|
||||
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
|
||||
PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
|
||||
s.iter().all(|p| p.walk(it))
|
||||
}
|
||||
PatKind::TupleStruct(_, s)
|
||||
| PatKind::Tuple(s)
|
||||
| PatKind::Slice(s)
|
||||
| PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
|
||||
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
|
||||
PatKind::Wild
|
||||
| PatKind::Rest
|
||||
@ -648,6 +649,9 @@ pub enum PatKind {
|
||||
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
|
||||
TupleStruct(Path, Vec<P<Pat>>),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
Or(Vec<P<Pat>>),
|
||||
|
||||
/// A possibly qualified path pattern.
|
||||
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
|
||||
/// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can
|
||||
|
@ -1050,7 +1050,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
||||
vis.visit_span(span);
|
||||
};
|
||||
}
|
||||
PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Box(inner) => vis.visit_pat(inner),
|
||||
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
|
||||
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
|
||||
@ -1058,7 +1057,9 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
||||
vis.visit_expr(e2);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Tuple(elems)
|
||||
| PatKind::Slice(elems)
|
||||
| PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Paren(inner) => vis.visit_pat(inner),
|
||||
PatKind::Mac(mac) => vis.visit_mac(mac),
|
||||
}
|
||||
|
@ -431,23 +431,48 @@ impl std::ops::DerefMut for State<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SeparatorSpacing {
|
||||
After,
|
||||
Both,
|
||||
}
|
||||
|
||||
pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefMut {
|
||||
fn comments(&mut self) -> &mut Option<Comments<'a>>;
|
||||
fn print_ident(&mut self, ident: ast::Ident);
|
||||
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
|
||||
|
||||
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
|
||||
fn strsep<T, F>(
|
||||
&mut self,
|
||||
sep: &'static str,
|
||||
spacing: SeparatorSpacing,
|
||||
b: Breaks,
|
||||
elts: &[T],
|
||||
mut op: F
|
||||
) -> io::Result<()>
|
||||
where F: FnMut(&mut Self, &T),
|
||||
{
|
||||
self.rbox(0, b);
|
||||
let mut first = true;
|
||||
for elt in elts {
|
||||
if first { first = false; } else { self.word_space(","); }
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
if let SeparatorSpacing::Both = spacing {
|
||||
self.writer().space();
|
||||
}
|
||||
self.word_space(sep);
|
||||
}
|
||||
op(self, elt);
|
||||
}
|
||||
self.end();
|
||||
}
|
||||
|
||||
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
|
||||
where F: FnMut(&mut Self, &T),
|
||||
{
|
||||
self.strsep(",", SeparatorSpacing::After, b, elts, op)
|
||||
}
|
||||
|
||||
fn maybe_print_comment(&mut self, pos: BytePos) {
|
||||
while let Some(ref cmnt) = self.next_comment() {
|
||||
if cmnt.pos < pos {
|
||||
@ -2353,6 +2378,10 @@ impl<'a> State<'a> {
|
||||
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
let spacing = SeparatorSpacing::Both;
|
||||
self.strsep("|", spacing, Inconsistent, &pats[..], |s, p| s.print_pat(p))?;
|
||||
}
|
||||
PatKind::Path(None, ref path) => {
|
||||
self.print_path(path, true, 0);
|
||||
}
|
||||
|
@ -447,9 +447,6 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
||||
visitor.visit_pat(&field.pat)
|
||||
}
|
||||
}
|
||||
PatKind::Tuple(ref elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
PatKind::Box(ref subpattern) |
|
||||
PatKind::Ref(ref subpattern, _) |
|
||||
PatKind::Paren(ref subpattern) => {
|
||||
@ -465,7 +462,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
||||
visitor.visit_expr(upper_bound);
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest => {},
|
||||
PatKind::Slice(ref elems) => {
|
||||
PatKind::Tuple(ref elems) => {
|
||||
| PatKind::Slice(ref elems)
|
||||
| PatKind::Or(ref elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
PatKind::Mac(ref mac) => visitor.visit_mac(mac),
|
||||
|
Loading…
Reference in New Issue
Block a user