add exclusive range patterns under a feature gate
This commit is contained in:
parent
74c42ac173
commit
c951341a78
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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>>),
|
||||
|
@ -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) => {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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) |
|
||||
|
@ -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! {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>>),
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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) => {
|
||||
|
@ -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 => { }
|
||||
_ => { }
|
||||
|
@ -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
|
||||
_ => {}
|
||||
}
|
||||
}
|
@ -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 `-`
|
||||
}
|
||||
|
@ -12,6 +12,6 @@
|
||||
|
||||
fn main() {
|
||||
match 0 {
|
||||
(pat ..) => {} //~ ERROR expected one of `)`, `,`, or `@`, found `..`
|
||||
(pat ..) => {} //~ ERROR unexpected token: `)`
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user