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> { + 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> { 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 or the MIT license +// , 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 or the MIT license +// , 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 +