add exclusive range patterns under a feature gate

This commit is contained in:
Oliver Schneider 2017-01-10 22:13:53 +01:00 committed by Oliver Schneider
parent 74c42ac173
commit c951341a78
No known key found for this signature in database
GPG Key ID: 56D6EEA0FC67AC46
22 changed files with 215 additions and 67 deletions

View File

@ -661,7 +661,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
walk_list!(visitor, visit_pat, optional_subpattern);
}
PatKind::Lit(ref expression) => visitor.visit_expr(expression),
PatKind::Range(ref lower_bound, ref upper_bound) => {
PatKind::Range(ref lower_bound, ref upper_bound, _) => {
visitor.visit_expr(lower_bound);
visitor.visit_expr(upper_bound)
}

View File

@ -1249,8 +1249,10 @@ impl<'a> LoweringContext<'a> {
PatKind::Ref(ref inner, mutbl) => {
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
}
PatKind::Range(ref e1, ref e2) => {
hir::PatKind::Range(P(self.lower_expr(e1)), P(self.lower_expr(e2)))
PatKind::Range(ref e1, ref e2, ref end) => {
hir::PatKind::Range(P(self.lower_expr(e1)),
P(self.lower_expr(e2)),
self.lower_range_end(end))
}
PatKind::Slice(ref before, ref slice, ref after) => {
hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
@ -1263,6 +1265,13 @@ impl<'a> LoweringContext<'a> {
})
}
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
match *e {
RangeEnd::Included => hir::RangeEnd::Included,
RangeEnd::Excluded => hir::RangeEnd::Excluded,
}
}
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
hir::Expr {
id: e.id,

View File

@ -572,6 +572,12 @@ pub enum BindingMode {
BindByValue(Mutability),
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum RangeEnd {
Included,
Excluded,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum PatKind {
/// Represents a wildcard pattern (`_`)
@ -603,8 +609,8 @@ pub enum PatKind {
Ref(P<Pat>, Mutability),
/// A literal
Lit(P<Expr>),
/// A range pattern, e.g. `1...2`
Range(P<Expr>, P<Expr>),
/// A range pattern, e.g. `1...2` or `1..2`
Range(P<Expr>, P<Expr>, RangeEnd),
/// `[a, b, ..i, y, z]` is represented as:
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),

View File

@ -24,7 +24,7 @@ use syntax_pos::{self, BytePos};
use errors;
use hir;
use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd};
use std::io::{self, Write, Read};
@ -1735,10 +1735,13 @@ impl<'a> State<'a> {
self.print_pat(&inner)?;
}
PatKind::Lit(ref e) => self.print_expr(&e)?,
PatKind::Range(ref begin, ref end) => {
PatKind::Range(ref begin, ref end, ref end_kind) => {
self.print_expr(&begin)?;
space(&mut self.s)?;
word(&mut self.s, "...")?;
match *end_kind {
RangeEnd::Included => word(&mut self.s, "...")?,
RangeEnd::Excluded => word(&mut self.s, "..")?,
}
self.print_expr(&end)?;
}
PatKind::Slice(ref before, ref slice, ref after) => {

View File

@ -24,6 +24,7 @@ use pattern::{FieldPattern, Pattern, PatternKind};
use pattern::{PatternFoldable, PatternFolder};
use rustc::hir::def_id::DefId;
use rustc::hir::RangeEnd;
use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
use rustc::mir::Field;
@ -206,8 +207,8 @@ pub enum Constructor {
Variant(DefId),
/// Literal values.
ConstantValue(ConstVal),
/// Ranges of literal values (2..5).
ConstantRange(ConstVal, ConstVal),
/// Ranges of literal values (`2...5` and `2..5`).
ConstantRange(ConstVal, ConstVal, RangeEnd),
/// Array patterns of length n.
Slice(usize),
}
@ -686,8 +687,8 @@ fn pat_constructors(_cx: &mut MatchCheckCtxt,
Some(vec![Variant(adt_def.variants[variant_index].did)]),
PatternKind::Constant { ref value } =>
Some(vec![ConstantValue(value.clone())]),
PatternKind::Range { ref lo, ref hi } =>
Some(vec![ConstantRange(lo.clone(), hi.clone())]),
PatternKind::Range { ref lo, ref hi, ref end } =>
Some(vec![ConstantRange(lo.clone(), hi.clone(), end.clone())]),
PatternKind::Array { .. } => match pcx.ty.sty {
ty::TyArray(_, length) => Some(vec![Slice(length)]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
@ -791,17 +792,33 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
ctor: &Constructor,
from: &ConstVal, to: &ConstVal)
from: &ConstVal, to: &ConstVal,
end: RangeEnd)
-> Result<bool, ErrorReported> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
Single => return Ok(true),
_ => bug!()
};
let cmp_from = compare_const_vals(tcx, span, c_from, from)?;
let cmp_to = compare_const_vals(tcx, span, c_to, to)?;
Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
match *ctor {
ConstantValue(ref value) => {
let to = cmp_to(value)?;
let end = (to != Ordering::Greater) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
Ok(cmp_from(value)? && end)
},
ConstantRange(ref from, ref to, RangeEnd::Included) => {
let to = cmp_to(to)?;
let end = (to != Ordering::Greater) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
Ok(cmp_from(from)? && end)
},
ConstantRange(ref from, ref to, RangeEnd::Excluded) => {
let to = cmp_to(to)?;
let end = (to == Ordering::Less) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
Ok(cmp_from(from)? && end)
}
Single => Ok(true),
_ => bug!(),
}
}
fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
@ -872,7 +889,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
},
_ => {
match range_covered_by_constructor(
cx.tcx, pat.span, constructor, value, value
cx.tcx, pat.span, constructor, value, value, RangeEnd::Included
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
@ -882,9 +899,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
}
}
PatternKind::Range { ref lo, ref hi } => {
PatternKind::Range { ref lo, ref hi, ref end } => {
match range_covered_by_constructor(
cx.tcx, pat.span, constructor, lo, hi
cx.tcx, pat.span, constructor, lo, hi, end.clone()
) {
Ok(true) => Some(vec![]),
Ok(false) => None,

View File

@ -15,7 +15,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind};
use rustc::hir::{self, PatKind, RangeEnd};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
@ -90,6 +90,7 @@ pub enum PatternKind<'tcx> {
Range {
lo: ConstVal,
hi: ConstVal,
end: RangeEnd,
},
/// matches against a slice, checking the length and extracting elements
@ -228,9 +229,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
PatternKind::Constant { ref value } => {
print_const_val(value, f)
}
PatternKind::Range { ref lo, ref hi } => {
PatternKind::Range { ref lo, ref hi, ref end } => {
print_const_val(lo, f)?;
write!(f, "...")?;
match *end {
RangeEnd::Included => write!(f, "...")?,
RangeEnd::Excluded => write!(f, "..")?,
}
print_const_val(hi, f)
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
@ -291,11 +295,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
PatKind::Lit(ref value) => self.lower_lit(value),
PatKind::Range(ref lo, ref hi) => {
PatKind::Range(ref lo, ref hi, ref end) => {
match (self.lower_lit(lo), self.lower_lit(hi)) {
(PatternKind::Constant { value: lo },
PatternKind::Constant { value: hi }) => {
PatternKind::Range { lo: lo, hi: hi }
PatternKind::Range { lo: lo, hi: hi, end: end.clone() }
}
_ => PatternKind::Wild
}
@ -871,10 +875,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
},
PatternKind::Range {
ref lo,
ref hi
ref hi,
ref end,
} => PatternKind::Range {
lo: lo.fold_with(folder),
hi: hi.fold_with(folder)
hi: hi.fold_with(folder),
end: end.clone(),
},
PatternKind::Slice {
ref prefix,

View File

@ -19,6 +19,7 @@ use rustc_data_structures::bitvec::BitVector;
use rustc::middle::const_val::ConstVal;
use rustc::ty::{AdtDef, Ty};
use rustc::mir::*;
use rustc::hir;
use hair::*;
use syntax::ast::{Name, NodeId};
use syntax_pos::Span;
@ -318,11 +319,12 @@ enum TestKind<'tcx> {
ty: Ty<'tcx>,
},
// test whether the value falls within an inclusive range
// test whether the value falls within an inclusive or exclusive range
Range {
lo: Literal<'tcx>,
hi: Literal<'tcx>,
ty: Ty<'tcx>,
end: hir::RangeEnd,
},
// test length of the slice is equal to len

View File

@ -23,6 +23,7 @@ use rustc_data_structures::bitvec::BitVector;
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::mir::*;
use rustc::hir::RangeEnd;
use syntax_pos::Span;
use std::cmp::Ordering;
@ -69,13 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
PatternKind::Range { ref lo, ref hi } => {
PatternKind::Range { ref lo, ref hi, ref end } => {
Test {
span: match_pair.pattern.span,
kind: TestKind::Range {
lo: Literal::Value { value: lo.clone() },
hi: Literal::Value { value: hi.clone() },
ty: match_pair.pattern.ty.clone(),
end: end.clone(),
},
}
}
@ -324,7 +326,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
TestKind::Range { ref lo, ref hi, ty } => {
TestKind::Range { ref lo, ref hi, ty, ref end } => {
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
@ -332,7 +334,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let fail = self.cfg.start_new_block();
let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
let block = self.compare(block, fail, test.span, BinOp::Le, val, hi);
let block = match *end {
RangeEnd::Included => self.compare(block, fail, test.span, BinOp::Le, val, hi),
RangeEnd::Excluded => self.compare(block, fail, test.span, BinOp::Lt, val, hi),
};
vec![block, fail]
}

View File

@ -45,7 +45,7 @@ use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeSet;
use rustc::lint::builtin::CONST_ERR;
use rustc::hir::{self, PatKind};
use rustc::hir::{self, PatKind, RangeEnd};
use syntax::ast;
use syntax_pos::Span;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@ -157,7 +157,21 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
PatKind::Lit(ref lit) => {
self.check_const_eval(lit);
}
PatKind::Range(ref start, ref end) => {
PatKind::Range(ref start, ref end, RangeEnd::Excluded) => {
let const_cx = ConstContext::with_tables(self.tcx, self.tables);
match const_cx.compare_lit_exprs(p.span, start, end) {
Ok(Ordering::Less) => {}
Ok(Ordering::Equal) |
Ok(Ordering::Greater) => {
span_err!(self.tcx.sess,
start.span,
E0579,
"lower range bound must be less than upper");
}
Err(ErrorReported) => {}
}
}
PatKind::Range(ref start, ref end, RangeEnd::Included) => {
let const_cx = ConstContext::with_tables(self.tcx, self.tables);
match const_cx.compare_lit_exprs(p.span, start, end) {
Ok(Ordering::Less) |

View File

@ -223,6 +223,24 @@ pub impl Foo for Bar {
```
"##,
E0579: r##"
When matching against an exclusive range, the compiler verifies that the range
is non-empty. Exclusive range patterns include the start point but not the end
point, so this is equivalent to requiring the start of the range to be less
than the end of the range.
For example:
```compile_fail
match 5u32 {
// This range is ok, albeit pointless.
1 .. 2 => {}
// This range is empty, and the compiler can tell.
5 .. 5 => {}
}
```
"##,
}
register_diagnostics! {

View File

@ -76,7 +76,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.demand_suptype(pat.span, expected, pat_ty);
pat_ty
}
PatKind::Range(ref begin, ref end) => {
PatKind::Range(ref begin, ref end, _) => {
let lhs_ty = self.check_expr(begin);
let rhs_ty = self.check_expr(end);

View File

@ -547,6 +547,12 @@ pub enum BindingMode {
ByValue(Mutability),
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum RangeEnd {
Included,
Excluded,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum PatKind {
/// Represents a wildcard pattern (`_`)
@ -583,8 +589,8 @@ pub enum PatKind {
Ref(P<Pat>, Mutability),
/// A literal
Lit(P<Expr>),
/// A range pattern, e.g. `1...2`
Range(P<Expr>, P<Expr>),
/// A range pattern, e.g. `1...2` or `1..2`
Range(P<Expr>, P<Expr>, RangeEnd),
/// `[a, b, ..i, y, z]` is represented as:
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),

View File

@ -26,7 +26,7 @@ use self::AttributeType::*;
use self::AttributeGate::*;
use abi::Abi;
use ast::{self, NodeId, PatKind};
use ast::{self, NodeId, PatKind, RangeEnd};
use attr;
use codemap::{CodeMap, Spanned};
use syntax_pos::Span;
@ -248,6 +248,9 @@ declare_features! (
// a...b and ...b
(active, inclusive_range_syntax, "1.7.0", Some(28237)),
// X..Y patterns
(active, exclusive_range_pattern, "1.11.0", Some(37854)),
// impl specialization (RFC 1210)
(active, specialization, "1.7.0", Some(31844)),
@ -1262,6 +1265,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
}
PatKind::Range(_, _, RangeEnd::Excluded) => {
gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
"exclusive range pattern syntax is experimental");
}
_ => {}
}
visit::walk_pat(self, pattern)

View File

@ -112,6 +112,10 @@ pub trait Folder : Sized {
e.map(|e| noop_fold_expr(e, self))
}
fn fold_range_end(&mut self, re: RangeEnd) -> RangeEnd {
noop_fold_range_end(re, self)
}
fn fold_opt_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
noop_fold_opt_expr(e, self)
}
@ -1095,8 +1099,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
}
PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
PatKind::Range(e1, e2) => {
PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
PatKind::Range(e1, e2, end) => {
PatKind::Range(folder.fold_expr(e1),
folder.fold_expr(e2),
folder.fold_range_end(end))
},
PatKind::Slice(before, slice, after) => {
PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
@ -1109,6 +1115,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
})
}
pub fn noop_fold_range_end<T: Folder>(end: RangeEnd, _folder: &mut T) -> RangeEnd {
end
}
pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mut T) -> Expr {
Expr {
node: match node {

View File

@ -38,6 +38,7 @@ use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
use ast::{BinOpKind, UnOp};
use ast::RangeEnd;
use {ast, attr};
use codemap::{self, CodeMap, Spanned, spanned, respan};
use syntax_pos::{self, Span, Pos, BytePos, mk_sp};
@ -3445,8 +3446,7 @@ impl<'a> Parser<'a> {
}
if before_slice {
if self.check(&token::DotDot) {
self.bump();
if self.eat(&token::DotDot) {
if self.check(&token::Comma) ||
self.check(&token::CloseDelim(token::Bracket)) {
@ -3462,8 +3462,7 @@ impl<'a> Parser<'a> {
}
let subpat = self.parse_pat()?;
if before_slice && self.check(&token::DotDot) {
self.bump();
if before_slice && self.eat(&token::DotDot) {
slice = Some(subpat);
before_slice = false;
} else if before_slice {
@ -3578,6 +3577,22 @@ impl<'a> Parser<'a> {
}
}
// helper function to decide whether to parse as ident binding or to try to do
// something more complex like range patterns
fn parse_as_ident(&mut self) -> bool {
self.look_ahead(1, |t| match *t {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::ModSep | token::Not => Some(false),
// ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the
// range pattern branch
token::DotDot => None,
_ => Some(true),
}).unwrap_or_else(|| self.look_ahead(2, |t| match *t {
token::Comma | token::CloseDelim(token::Bracket) => true,
_ => false,
}))
}
/// Parse a pattern.
pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
maybe_whole!(self, NtPat, |x| x);
@ -3627,11 +3642,7 @@ impl<'a> Parser<'a> {
let subpat = self.parse_pat()?;
pat = PatKind::Box(subpat);
} else if self.token.is_ident() && !self.token.is_any_keyword() &&
self.look_ahead(1, |t| match *t {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::ModSep | token::Not => false,
_ => true,
}) {
self.parse_as_ident() {
// Parse ident @ pat
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve
@ -3658,14 +3669,19 @@ impl<'a> Parser<'a> {
let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
pat = PatKind::Mac(mac);
}
token::DotDotDot => {
token::DotDotDot | token::DotDot => {
let end_kind = match self.token {
token::DotDot => RangeEnd::Excluded,
token::DotDotDot => RangeEnd::Included,
_ => panic!("can only parse `..` or `...` for ranges (checked above)"),
};
// Parse range
let hi = self.prev_span.hi;
let begin =
self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
self.bump();
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end);
pat = PatKind::Range(begin, end, end_kind);
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
@ -3699,7 +3715,10 @@ impl<'a> Parser<'a> {
Ok(begin) => {
if self.eat(&token::DotDotDot) {
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end);
pat = PatKind::Range(begin, end, RangeEnd::Included);
} else if self.eat(&token::DotDot) {
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end, RangeEnd::Excluded);
} else {
pat = PatKind::Lit(begin);
}

View File

@ -11,7 +11,7 @@
pub use self::AnnNode::*;
use abi::{self, Abi};
use ast::{self, BlockCheckMode, PatKind};
use ast::{self, BlockCheckMode, PatKind, RangeEnd};
use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use ast::Attribute;
use util::parser::AssocOp;
@ -2553,10 +2553,13 @@ impl<'a> State<'a> {
self.print_pat(&inner)?;
}
PatKind::Lit(ref e) => self.print_expr(&**e)?,
PatKind::Range(ref begin, ref end) => {
PatKind::Range(ref begin, ref end, ref end_kind) => {
self.print_expr(&begin)?;
space(&mut self.s)?;
word(&mut self.s, "...")?;
match *end_kind {
RangeEnd::Included => word(&mut self.s, "...")?,
RangeEnd::Excluded => word(&mut self.s, "..")?,
}
self.print_expr(&end)?;
}
PatKind::Slice(ref before, ref slice, ref after) => {

View File

@ -440,9 +440,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
walk_list!(visitor, visit_pat, optional_subpattern);
}
PatKind::Lit(ref expression) => visitor.visit_expr(expression),
PatKind::Range(ref lower_bound, ref upper_bound) => {
PatKind::Range(ref lower_bound, ref upper_bound, _) => {
visitor.visit_expr(lower_bound);
visitor.visit_expr(upper_bound)
visitor.visit_expr(upper_bound);
}
PatKind::Wild => (),
PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(exclusive_range_pattern)]
fn main() {
match 5 {
6 ... 1 => { }
@ -15,6 +17,12 @@ fn main() {
};
//~^^^ ERROR lower range bound must be less than or equal to upper
match 5 {
0 .. 0 => { }
_ => { }
};
//~^^^ ERROR lower range bound must be less than upper
match 5u64 {
0xFFFF_FFFF_FFFF_FFFF ... 1 => { }
_ => { }

View File

@ -8,11 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
pub fn main() {
match 22 {
0 .. 3 => {} //~ ERROR expected one of `...`, `=>`, `if`, or `|`, found `..`
0 .. 3 => {} //~ ERROR exclusive range pattern syntax is experimental
_ => {}
}
}

View File

@ -11,5 +11,5 @@
// Parsing of range patterns
fn main() {
let 10 - 3 ... 10 = 8; //~ error: expected one of `...`, `:`, `;`, or `=`, found `-`
let 10 - 3 ... 10 = 8; //~ error: expected one of `...`, `..`, `:`, `;`, or `=`, found `-`
}

View File

@ -12,6 +12,6 @@
fn main() {
match 0 {
(pat ..) => {} //~ ERROR expected one of `)`, `,`, or `@`, found `..`
(pat ..) => {} //~ ERROR unexpected token: `)`
}
}

View File

@ -7,17 +7,26 @@
// <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(exclusive_range_pattern)]
pub fn main() {
match 5_usize {
1_usize...5_usize => {}
_ => panic!("should match range"),
}
match 1_usize {
1_usize..5_usize => {}
_ => panic!("should match range start"),
}
match 5_usize {
6_usize...7_usize => panic!("shouldn't match range"),
_ => {}
}
match 7_usize {
6_usize..7_usize => panic!("shouldn't match range end"),
_ => {},
}
match 5_usize {
1_usize => panic!("should match non-first range"),
2_usize...6_usize => {}
@ -39,4 +48,12 @@ pub fn main() {
-3.6...3.6 => {}
_ => panic!("should match negative float range")
}
match 3.5 {
0.0..3.5 => panic!("should not match the range end"),
_ => {},
}
match 0.0 {
0.0..3.5 => {},
_ => panic!("should match the range start"),
}
}