]> git.lizzy.rs Git - rust.git/commitdiff
Implement multiple patterns with `|` in `if let` and `while let`
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 24 Feb 2018 00:12:35 +0000 (03:12 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 24 Feb 2018 00:12:35 +0000 (03:12 +0300)
12 files changed:
src/librustc/hir/lowering.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/dump_visitor.rs
src/libsyntax/ast.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/run-pass/rfc-2175-or-if-while-let/basic.rs [new file with mode: 0644]
src/test/ui/feature-gate-if_while_or_patterns.rs [new file with mode: 0644]
src/test/ui/feature-gate-if_while_or_patterns.stderr [new file with mode: 0644]

index e3af285053805e68c768e80a5ff92431eb4d6589..89ed47ea194fb7e51859e9748946561b024046d6 100644 (file)
@@ -2956,7 +2956,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
 
             // Desugar ExprIfLet
             // From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
-            ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
+            ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
                 // to:
                 //
                 //   match <sub_expr> {
@@ -2970,8 +2970,8 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 {
                     let body = self.lower_block(body, false);
                     let body_expr = P(self.expr_block(body, ThinVec::new()));
-                    let pat = self.lower_pat(pat);
-                    arms.push(self.arm(hir_vec![pat], body_expr));
+                    let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+                    arms.push(self.arm(pats, body_expr));
                 }
 
                 // _ => [<else_opt>|()]
@@ -3000,7 +3000,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
 
             // Desugar ExprWhileLet
             // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
-            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
+            ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
                 // to:
                 //
                 //   [opt_ident]: loop {
@@ -3021,8 +3021,8 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 // `<pat> => <body>`
                 let pat_arm = {
                     let body_expr = P(self.expr_block(body, ThinVec::new()));
-                    let pat = self.lower_pat(pat);
-                    self.arm(hir_vec![pat], body_expr)
+                    let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+                    self.arm(pats, body_expr)
                 };
 
                 // `_ => break`
index e6b9150fa3aec0d1e52c2d95fdd102704750e2a9..e4e9ee58330cc58b775692491e72a68164b0b412 100644 (file)
@@ -59,6 +59,7 @@
 use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
 use syntax::parse::token;
+use syntax::ptr::P;
 
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use errors::{DiagnosticBuilder, DiagnosticId};
@@ -2329,17 +2330,17 @@ fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
 
     // check that all of the arms in an or-pattern have exactly the
     // same set of bindings, with the same binding modes for each.
-    fn check_consistent_bindings(&mut self, arm: &Arm) {
-        if arm.pats.is_empty() {
+    fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
+        if pats.is_empty() {
             return;
         }
 
         let mut missing_vars = FxHashMap();
         let mut inconsistent_vars = FxHashMap();
-        for (i, p) in arm.pats.iter().enumerate() {
+        for (i, p) in pats.iter().enumerate() {
             let map_i = self.binding_mode_map(&p);
 
-            for (j, q) in arm.pats.iter().enumerate() {
+            for (j, q) in pats.iter().enumerate() {
                 if i == j {
                     continue;
                 }
@@ -2404,9 +2405,8 @@ fn resolve_arm(&mut self, arm: &Arm) {
             self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
         }
 
-        // This has to happen *after* we determine which
-        // pat_idents are variants
-        self.check_consistent_bindings(arm);
+        // This has to happen *after* we determine which pat_idents are variants
+        self.check_consistent_bindings(&arm.pats);
 
         walk_list!(self, visit_expr, &arm.guard);
         self.visit_expr(&arm.body);
@@ -2490,7 +2490,9 @@ fn fresh_binding(&mut self,
                         &ident.node.name.as_str())
                 );
             }
-            Some(..) if pat_src == PatternSource::Match => {
+            Some(..) if pat_src == PatternSource::Match ||
+                        pat_src == PatternSource::IfLet ||
+                        pat_src == PatternSource::WhileLet => {
                 // `Variant1(a) | Variant2(a)`, ok
                 // Reuse definition from the first `a`.
                 def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node];
@@ -3480,11 +3482,16 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
+            ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
                 self.visit_expr(subexpression);
 
                 self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap());
+                let mut bindings_list = FxHashMap();
+                for pat in pats {
+                    self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list);
+                }
+                // This has to happen *after* we determine which pat_idents are variants
+                self.check_consistent_bindings(pats);
                 self.visit_block(if_block);
                 self.ribs[ValueNS].pop();
 
@@ -3500,11 +3507,16 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                 });
             }
 
-            ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
+            ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => {
                 self.with_resolved_label(label, expr.id, |this| {
                     this.visit_expr(subexpression);
                     this.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                    this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
+                    let mut bindings_list = FxHashMap();
+                    for pat in pats {
+                        this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list);
+                    }
+                    // This has to happen *after* we determine which pat_idents are variants
+                    this.check_consistent_bindings(pats);
                     this.visit_block(block);
                     this.ribs[ValueNS].pop();
                 });
index bf82b0774238bf4879273b5c9df5c94d4ba6dea4..6e98604101345a6796fd526a08955020ee430ea8 100644 (file)
@@ -1031,6 +1031,81 @@ fn process_pat(&mut self, p: &'l ast::Pat) {
         }
     }
 
+    fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) {
+        let mut collector = PathCollector::new();
+        for pattern in pats {
+            // collect paths from the arm's patterns
+            collector.visit_pat(&pattern);
+            self.visit_pat(&pattern);
+        }
+
+        // process collected paths
+        for (id, i, sp, immut) in collector.collected_idents {
+            match self.save_ctxt.get_path_def(id) {
+                HirDef::Local(id) => {
+                    let mut value = if immut == ast::Mutability::Immutable {
+                        self.span.snippet(sp).to_string()
+                    } else {
+                        "<mutable>".to_string()
+                    };
+                    let hir_id = self.tcx.hir.node_to_hir_id(id);
+                    let typ = self.save_ctxt
+                        .tables
+                        .node_id_to_type_opt(hir_id)
+                        .map(|t| t.to_string())
+                        .unwrap_or(String::new());
+                    value.push_str(": ");
+                    value.push_str(&typ);
+
+                    if !self.span.filter_generated(Some(sp), sp) {
+                        let qualname = format!("{}${}", i.to_string(), id);
+                        let id = ::id_from_node_id(id, &self.save_ctxt);
+                        let span = self.span_from_span(sp);
+
+                        self.dumper.dump_def(
+                            &Access {
+                                public: false,
+                                reachable: false,
+                            },
+                            Def {
+                                kind: DefKind::Local,
+                                id,
+                                span,
+                                name: i.to_string(),
+                                qualname,
+                                value: typ,
+                                parent: None,
+                                children: vec![],
+                                decl_id: None,
+                                docs: String::new(),
+                                sig: None,
+                                attributes: vec![],
+                            },
+                        );
+                    }
+                }
+                HirDef::StructCtor(..) |
+                HirDef::VariantCtor(..) |
+                HirDef::Const(..) |
+                HirDef::AssociatedConst(..) |
+                HirDef::Struct(..) |
+                HirDef::Variant(..) |
+                HirDef::TyAlias(..) |
+                HirDef::AssociatedTy(..) |
+                HirDef::SelfTy(..) => {
+                    self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
+                }
+                def => error!(
+                    "unexpected definition kind when processing collected idents: {:?}",
+                    def
+                ),
+            }
+        }
+
+        for (id, ref path) in collector.collected_paths {
+            self.process_path(id, path);
+        }
+    }
 
     fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
         // The local could declare multiple new vars, we must walk the
@@ -1622,17 +1697,21 @@ fn visit_expr(&mut self, ex: &'l ast::Expr) {
                     v.nest_scope(ex.id, |v| v.visit_expr(body))
                 });
             }
-            ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
-            ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
+            ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
                 let value = self.span.snippet(subexpression.span);
                 self.process_var_decl(pattern, value);
                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
                 self.visit_expr(subexpression);
                 visit::walk_block(self, block);
             }
-            ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
-                let value = self.span.snippet(subexpression.span);
-                self.process_var_decl(pattern, value);
+            ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
+                self.process_var_decl_multi(pats);
+                debug!("for loop, walk sub-expr: {:?}", subexpression.node);
+                self.visit_expr(subexpression);
+                visit::walk_block(self, block);
+            }
+            ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
+                self.process_var_decl_multi(pats);
                 self.visit_expr(subexpression);
                 visit::walk_block(self, block);
                 opt_else.as_ref().map(|el| self.visit_expr(el));
@@ -1661,79 +1740,7 @@ fn visit_pat(&mut self, p: &'l ast::Pat) {
     }
 
     fn visit_arm(&mut self, arm: &'l ast::Arm) {
-        let mut collector = PathCollector::new();
-        for pattern in &arm.pats {
-            // collect paths from the arm's patterns
-            collector.visit_pat(&pattern);
-            self.visit_pat(&pattern);
-        }
-
-        // process collected paths
-        for (id, i, sp, immut) in collector.collected_idents {
-            match self.save_ctxt.get_path_def(id) {
-                HirDef::Local(id) => {
-                    let mut value = if immut == ast::Mutability::Immutable {
-                        self.span.snippet(sp).to_string()
-                    } else {
-                        "<mutable>".to_string()
-                    };
-                    let hir_id = self.tcx.hir.node_to_hir_id(id);
-                    let typ = self.save_ctxt
-                        .tables
-                        .node_id_to_type_opt(hir_id)
-                        .map(|t| t.to_string())
-                        .unwrap_or(String::new());
-                    value.push_str(": ");
-                    value.push_str(&typ);
-
-                    if !self.span.filter_generated(Some(sp), sp) {
-                        let qualname = format!("{}${}", i.to_string(), id);
-                        let id = ::id_from_node_id(id, &self.save_ctxt);
-                        let span = self.span_from_span(sp);
-
-                        self.dumper.dump_def(
-                            &Access {
-                                public: false,
-                                reachable: false,
-                            },
-                            Def {
-                                kind: DefKind::Local,
-                                id,
-                                span,
-                                name: i.to_string(),
-                                qualname,
-                                value: typ,
-                                parent: None,
-                                children: vec![],
-                                decl_id: None,
-                                docs: String::new(),
-                                sig: None,
-                                attributes: vec![],
-                            },
-                        );
-                    }
-                }
-                HirDef::StructCtor(..) |
-                HirDef::VariantCtor(..) |
-                HirDef::Const(..) |
-                HirDef::AssociatedConst(..) |
-                HirDef::Struct(..) |
-                HirDef::Variant(..) |
-                HirDef::TyAlias(..) |
-                HirDef::AssociatedTy(..) |
-                HirDef::SelfTy(..) => {
-                    self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
-                }
-                def => error!(
-                    "unexpected definition kind when processing collected idents: {:?}",
-                    def
-                ),
-            }
-        }
-
-        for (id, ref path) in collector.collected_paths {
-            self.process_path(id, path);
-        }
+        self.process_var_decl_multi(&arm.pats);
         walk_list!(self, visit_expr, &arm.guard);
         self.visit_expr(&arm.body);
     }
index c7ce7fffaa21b2e3fd72043a8542ce7ae918eeaf..6609b77b132c62f27dec7f5c3ea4c61c182a1bc9 100644 (file)
@@ -1085,7 +1085,7 @@ pub enum ExprKind {
     /// `if let pat = expr { block } else { expr }`
     ///
     /// This is desugared to a `match` expression.
-    IfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
+    IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>),
     /// A while loop, with an optional label
     ///
     /// `'label: while expr { block }`
@@ -1095,7 +1095,7 @@ pub enum ExprKind {
     /// `'label: while let pat = expr { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    WhileLet(P<Pat>, P<Expr>, P<Block>, Option<Label>),
+    WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>),
     /// A for loop, with an optional label
     ///
     /// `'label: for pat in expr { block }`
index c0fde71d086f4a717d701a506379c573296d6e1b..04f2a0048fa781b30addab5ef3fdd1996d834331 100644 (file)
@@ -449,6 +449,9 @@ pub fn new() -> Features {
 
     // Use `?` as the Kleene "at most one" operator
     (active, macro_at_most_once_rep, "1.25.0", Some(48075)),
+
+    // Multiple patterns with `|` in `if let` and `while let`
+    (active, if_while_or_patterns, "1.26.0", Some(48215)),
 );
 
 declare_features! (
@@ -1686,6 +1689,12 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
             ast::ExprKind::Catch(_) => {
                 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
             }
+            ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => {
+                if pats.len() > 1 {
+                    gate_feature_post!(&self, if_while_or_patterns, e.span,
+                                    "multiple patterns in `if let` and `while let` are unstable");
+                }
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
index 1a2025b073b2b85081f96883242dda1909531f13..e8eb75f5e6018e6e97e1c39d6cdbd1caf8d79130 100644 (file)
@@ -1210,8 +1210,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                        folder.fold_block(tr),
                        fl.map(|x| folder.fold_expr(x)))
             }
-            ExprKind::IfLet(pat, expr, tr, fl) => {
-                ExprKind::IfLet(folder.fold_pat(pat),
+            ExprKind::IfLet(pats, expr, tr, fl) => {
+                ExprKind::IfLet(pats.move_map(|pat| folder.fold_pat(pat)),
                           folder.fold_expr(expr),
                           folder.fold_block(tr),
                           fl.map(|x| folder.fold_expr(x)))
@@ -1221,8 +1221,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                           folder.fold_block(body),
                           opt_label.map(|label| folder.fold_label(label)))
             }
-            ExprKind::WhileLet(pat, expr, body, opt_label) => {
-                ExprKind::WhileLet(folder.fold_pat(pat),
+            ExprKind::WhileLet(pats, expr, body, opt_label) => {
+                ExprKind::WhileLet(pats.move_map(|pat| folder.fold_pat(pat)),
                              folder.fold_expr(expr),
                              folder.fold_block(body),
                              opt_label.map(|label| folder.fold_label(label)))
index 74daa5179d381c79d5e86f620a4f21df2ebfb550..50955f2786fc619a98493afad125cfe719bdbae8 100644 (file)
@@ -3226,7 +3226,7 @@ pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>> {
         let lo = self.prev_span;
         self.expect_keyword(keywords::Let)?;
-        let pat = self.parse_pat()?;
+        let pats = self.parse_pats()?;
         self.expect(&token::Eq)?;
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
@@ -3236,7 +3236,7 @@ pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
         } else {
             (thn.span, None)
         };
-        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs))
+        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
     }
 
     // `move |args| expr`
@@ -3327,13 +3327,13 @@ pub fn parse_while_let_expr(&mut self, opt_label: Option<Label>,
                                 span_lo: Span,
                                 mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         self.expect_keyword(keywords::Let)?;
-        let pat = self.parse_pat()?;
+        let pats = self.parse_pats()?;
         self.expect(&token::Eq)?;
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
-        return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_label), attrs));
+        return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
     }
 
     // parse `loop {...}`, `loop` token already eaten
index 3dfe3c9e5b990590e12c1e8efe97a45163eb1875..9cad9f46e98cfef05af3906fc9d24a2a763a16d5 100644 (file)
@@ -1767,11 +1767,11 @@ fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "another else-if-let"
-                    ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
+                    ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         self.s.word(" else if let ")?;
-                        self.print_pat(pat)?;
+                        self.print_pats(pats)?;
                         self.s.space()?;
                         self.word_space("=")?;
                         self.print_expr_as_cond(expr)?;
@@ -1805,10 +1805,10 @@ pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
         self.print_else(elseopt)
     }
 
-    pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
+    pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
                         elseopt: Option<&ast::Expr>) -> io::Result<()> {
         self.head("if let")?;
-        self.print_pat(pat)?;
+        self.print_pats(pats)?;
         self.s.space()?;
         self.word_space("=")?;
         self.print_expr_as_cond(expr)?;
@@ -2109,8 +2109,8 @@ fn print_expr_outer_attr_style(&mut self,
             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
                 self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
-                self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
+            ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => {
+                self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?;
             }
             ast::ExprKind::While(ref test, ref blk, opt_label) => {
                 if let Some(label) = opt_label {
@@ -2122,13 +2122,13 @@ fn print_expr_outer_attr_style(&mut self,
                 self.s.space()?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
-            ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => {
+            ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident)?;
                     self.word_space(":")?;
                 }
                 self.head("while let")?;
-                self.print_pat(pat)?;
+                self.print_pats(pats)?;
                 self.s.space()?;
                 self.word_space("=")?;
                 self.print_expr_as_cond(expr)?;
@@ -2664,6 +2664,20 @@ pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
         self.ann.post(self, NodePat(pat))
     }
 
+    fn print_pats(&mut self, pats: &[P<ast::Pat>]) -> io::Result<()> {
+        let mut first = true;
+        for p in pats {
+            if first {
+                first = false;
+            } else {
+                self.s.space()?;
+                self.word_space("|")?;
+            }
+            self.print_pat(p)?;
+        }
+        Ok(())
+    }
+
     fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
         // I have no idea why this check is necessary, but here it
         // is :(
@@ -2674,16 +2688,7 @@ fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
         self.ibox(0)?;
         self.maybe_print_comment(arm.pats[0].span.lo())?;
         self.print_outer_attributes(&arm.attrs)?;
-        let mut first = true;
-        for p in &arm.pats {
-            if first {
-                first = false;
-            } else {
-                self.s.space()?;
-                self.word_space("|")?;
-            }
-            self.print_pat(p)?;
-        }
+        self.print_pats(&arm.pats)?;
         self.s.space()?;
         if let Some(ref e) = arm.guard {
             self.word_space("if")?;
index 4691ddafa36e8480f2463ad81caffe85245bf214..640f90ecb4a4367e57d9b4b32b4f1bf1966f6279 100644 (file)
@@ -705,15 +705,15 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
         }
-        ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
-            visitor.visit_pat(pattern);
+        ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
+            walk_list!(visitor, visit_pat, pats);
             visitor.visit_expr(subexpression);
             visitor.visit_block(if_block);
             walk_list!(visitor, visit_expr, optional_else);
         }
-        ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_label) => {
+        ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_pat(pattern);
+            walk_list!(visitor, visit_pat, pats);
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
         }
diff --git a/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs b/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs
new file mode 100644 (file)
index 0000000..a516a3e
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(if_while_or_patterns)]
+
+enum E {
+    V(u8),
+    U(u8),
+    W,
+}
+use E::*;
+
+fn main() {
+    let mut e = V(10);
+
+    if let V(x) | U(x) = e {
+        assert_eq!(x, 10);
+    }
+    while let V(x) | U(x) = e {
+        assert_eq!(x, 10);
+        e = W;
+    }
+}
diff --git a/src/test/ui/feature-gate-if_while_or_patterns.rs b/src/test/ui/feature-gate-if_while_or_patterns.rs
new file mode 100644 (file)
index 0000000..3df140c
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+        ;
+    }
+    while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+        break;
+    }
+}
diff --git a/src/test/ui/feature-gate-if_while_or_patterns.stderr b/src/test/ui/feature-gate-if_while_or_patterns.stderr
new file mode 100644 (file)
index 0000000..c906fa5
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
+  --> $DIR/feature-gate-if_while_or_patterns.rs:12:5
+   |
+12 | /     if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+13 | |         ;
+14 | |     }
+   | |_____^
+   |
+   = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
+
+error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
+  --> $DIR/feature-gate-if_while_or_patterns.rs:15:5
+   |
+15 | /     while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+16 | |         break;
+17 | |     }
+   | |_____^
+   |
+   = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+