about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-10-19 15:40:07 +0100
committerDan Robertson <dan@dlrobertson.com>2019-08-17 15:05:36 +0000
commit1713ac4bf5c992f40d667c929c1e1ce9c3a51204 (patch)
tree098d9b4e320c88f985b2459ae9ded38081f46cb7
parentac60ca0643feb3452688a9ca97c839c155742915 (diff)
downloadrust-1713ac4bf5c992f40d667c929c1e1ce9c3a51204.tar.gz
rust-1713ac4bf5c992f40d667c929c1e1ce9c3a51204.zip
Initial implementation of or patterns
-rw-r--r--src/librustc/cfg/construct.rs5
-rw-r--r--src/librustc/hir/intravisit.rs1
-rw-r--r--src/librustc/hir/lowering.rs3
-rw-r--r--src/librustc/hir/mod.rs4
-rw-r--r--src/librustc/hir/print.rs6
-rw-r--r--src/librustc/middle/mem_categorization.rs6
-rw-r--r--src/librustc_mir/build/matches/mod.rs6
-rw-r--r--src/librustc_mir/build/matches/simplify.rs4
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs10
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs47
-rw-r--r--src/librustc_typeck/check/_match.rs8
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/libsyntax/ast.rs10
-rw-r--r--src/libsyntax/mut_visit.rs5
-rw-r--r--src/libsyntax/print/pprust.rs33
-rw-r--r--src/libsyntax/visit.rs7
17 files changed, 134 insertions, 26 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 7ada56cfa76..0dad2dda837 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -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);
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 99fe9f1682f..2c6373bdfa4 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -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);
         }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 0f6e834ca26..d2ea485b5db 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -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,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 57fd0be77ec..2ae08568b7f 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -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),
 
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 2fd683ed83c..157b7c07a9b 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -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 {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index a55803e255b..73ca981bbe8 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -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)?;
             }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index d72b0addae9..0dec7ef4f00 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -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);
+                }
+            }
         }
     }
 }
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 3473155a3ea..8d049b53988 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -195,6 +195,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 candidate.match_pairs.push(MatchPair::new(place, subpattern));
                 Ok(())
             }
+
+            PatternKind::Or { .. } => {
+                Err(match_pair)
+            }
         }
     }
 }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 65e92d422b0..ec85daccd47 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -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 { .. } |
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 1833ee30624..ae59244d37f 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -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);
 
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index bebb0719af8..d2a5793e703 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -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) },
         }
     }
 }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 99ae777bb63..2e22fb76675 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -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() {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index fede9e93010..023d22861de 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -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),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 3ae37f734b7..0136c4ff5f9 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -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
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index acafe327640..b67b4619d7f 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -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),
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 8a7009828bc..8dcb7ecf881 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -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);
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 6648347d4ae..ce679a5db63 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -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),