about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-03-03 06:05:54 +0800
committerkennytm <kennytm@gmail.com>2018-03-15 16:58:03 +0800
commit6399d16cfde37b06f6b82cdafa623e36385d7252 (patch)
tree084c6934333110a4d2d197ac77a0851a68fed3c1
parenta4d80336c96d7f47b0ef025fa141a9c96abcafbd (diff)
downloadrust-6399d16cfde37b06f6b82cdafa623e36385d7252.tar.gz
rust-6399d16cfde37b06f6b82cdafa623e36385d7252.zip
Disallow &a..=b and box a..=b in pattern.
They are disallowed because they have different precedence than
expressions. I assume parenthesis in pattern will be soon stabilized and
thus write that as suggestion directly.
-rw-r--r--src/librustc/hir/print.rs20
-rw-r--r--src/libsyntax/parse/parser.rs29
-rw-r--r--src/test/run-pass/range-inclusive-pattern-precedence.rs32
-rw-r--r--src/test/ui/range-inclusive-pattern-precedence.rs38
-rw-r--r--src/test/ui/range-inclusive-pattern-precedence.stderr14
5 files changed, 131 insertions, 2 deletions
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index d91aa3a3851..9e755f366a7 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1810,15 +1810,35 @@ impl<'a> State<'a> {
                 self.pclose()?;
             }
             PatKind::Box(ref inner) => {
+                let is_range_inner = match inner.node {
+                    PatKind::Range(..) => true,
+                    _ => false,
+                };
                 self.s.word("box ")?;
+                if is_range_inner {
+                    self.popen()?;
+                }
                 self.print_pat(&inner)?;
+                if is_range_inner {
+                    self.pclose()?;
+                }
             }
             PatKind::Ref(ref inner, mutbl) => {
+                let is_range_inner = match inner.node {
+                    PatKind::Range(..) => true,
+                    _ => false,
+                };
                 self.s.word("&")?;
                 if mutbl == hir::MutMutable {
                     self.s.word("mut ")?;
                 }
+                if is_range_inner {
+                    self.popen()?;
+                }
                 self.print_pat(&inner)?;
+                if is_range_inner {
+                    self.pclose()?;
+                }
             }
             PatKind::Lit(ref e) => self.print_expr(&e)?,
             PatKind::Range(ref begin, ref end, ref end_kind) => {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index bd0ca0e6704..e3812ce159a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3804,6 +3804,12 @@ impl<'a> Parser<'a> {
 
     /// Parse a pattern.
     pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
+        self.parse_pat_with_range_pat(true)
+    }
+
+    /// Parse a pattern, with a setting whether modern range patterns e.g. `a..=b`, `a..b` are
+    /// allowed.
+    fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<Pat>> {
         maybe_whole!(self, NtPat, |x| x);
 
         let lo = self.span;
@@ -3824,7 +3830,7 @@ impl<'a> Parser<'a> {
                     err.span_label(self.span, "unexpected lifetime");
                     return Err(err);
                 }
-                let subpat = self.parse_pat()?;
+                let subpat = self.parse_pat_with_range_pat(false)?;
                 pat = PatKind::Ref(subpat, mutbl);
             }
             token::OpenDelim(token::Paren) => {
@@ -3863,7 +3869,7 @@ impl<'a> Parser<'a> {
                 pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?;
             } else if self.eat_keyword(keywords::Box) {
                 // Parse box pat
-                let subpat = self.parse_pat()?;
+                let subpat = self.parse_pat_with_range_pat(false)?;
                 pat = PatKind::Box(subpat);
             } else if self.token.is_ident() && !self.token.is_reserved_ident() &&
                       self.parse_as_ident() {
@@ -3968,6 +3974,25 @@ impl<'a> Parser<'a> {
         let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID };
         let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
 
+        if !allow_range_pat {
+            match pat.node {
+                PatKind::Range(_, _, RangeEnd::Included(RangeSyntax::DotDotDot)) => {}
+                PatKind::Range(..) => {
+                    let mut err = self.struct_span_err(
+                        pat.span,
+                        "the range pattern here has ambiguous interpretation",
+                    );
+                    err.span_suggestion(
+                        pat.span,
+                        "add parentheses to clarify the precedence",
+                        format!("({})", pprust::pat_to_string(&pat)),
+                    );
+                    return Err(err);
+                }
+                _ => {}
+            }
+        }
+
         Ok(P(pat))
     }
 
diff --git a/src/test/run-pass/range-inclusive-pattern-precedence.rs b/src/test/run-pass/range-inclusive-pattern-precedence.rs
new file mode 100644
index 00000000000..5e491d48bcf
--- /dev/null
+++ b/src/test/run-pass/range-inclusive-pattern-precedence.rs
@@ -0,0 +1,32 @@
+// 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.
+
+#![feature(box_patterns, pattern_parentheses)]
+
+const VALUE: usize = 21;
+
+pub fn main() {
+    match &18 {
+        &(18..=18) => {}
+        _ => { unreachable!(); }
+    }
+    match &21 {
+        &(VALUE..=VALUE) => {}
+        _ => { unreachable!(); }
+    }
+    match Box::new(18) {
+        box (18..=18) => {}
+        _ => { unreachable!(); }
+    }
+    match Box::new(21) {
+        box (VALUE..=VALUE) => {}
+        _ => { unreachable!(); }
+    }
+}
diff --git a/src/test/ui/range-inclusive-pattern-precedence.rs b/src/test/ui/range-inclusive-pattern-precedence.rs
new file mode 100644
index 00000000000..67a0f79ca6b
--- /dev/null
+++ b/src/test/ui/range-inclusive-pattern-precedence.rs
@@ -0,0 +1,38 @@
+// 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.
+
+// In expression, `&a..=b` is treated as `(&a)..=(b)` and `box a..=b` is
+// `(box a)..=(b)`. In a pattern, however, `&a..=b` means `&(a..=b)`. This may
+// lead to confusion.
+//
+// We are going to disallow `&a..=b` and `box a..=b` in a pattern. However, the
+// older ... syntax is still allowed as a stability guarantee.
+
+#![feature(box_patterns)]
+
+pub fn main() {
+    match &12 {
+        &0...9 => {}
+        &10..=15 => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~^^ HELP add parentheses to clarify the precedence
+        &(16..=20) => {}
+        _ => {}
+    }
+
+    match Box::new(12) {
+        box 0...9 => {}
+        box 10..=15 => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~^^ HELP add parentheses to clarify the precedence
+        box (16..=20) => {}
+        _ => {}
+    }
+}
diff --git a/src/test/ui/range-inclusive-pattern-precedence.stderr b/src/test/ui/range-inclusive-pattern-precedence.stderr
new file mode 100644
index 00000000000..99e0d739036
--- /dev/null
+++ b/src/test/ui/range-inclusive-pattern-precedence.stderr
@@ -0,0 +1,14 @@
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/range-inclusive-pattern-precedence.rs:23:10
+   |
+LL |         &10..=15 => {}
+   |          ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/range-inclusive-pattern-precedence.rs:32:13
+   |
+LL |         box 10..=15 => {}
+   |             ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
+
+error: aborting due to 2 previous errors
+