Implement ..
in tuple (struct) patterns
This commit is contained in:
parent
d5759a3417
commit
d69aeaf662
48 changed files with 735 additions and 298 deletions
|
@ -2433,6 +2433,8 @@ The currently implemented features of the reference compiler are:
|
||||||
* - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
|
* - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
|
||||||
(e.g. `extern "vectorcall" func fn_();`)
|
(e.g. `extern "vectorcall" func fn_();`)
|
||||||
|
|
||||||
|
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
|
||||||
|
|
||||||
If a feature is promoted to a language feature, then all existing programs will
|
If a feature is promoted to a language feature, then all existing programs will
|
||||||
start to receive compilation warnings about `#![feature]` directives which enabled
|
start to receive compilation warnings about `#![feature]` directives which enabled
|
||||||
the new feature (because the directive is no longer necessary). However, if a
|
the new feature (because the directive is no longer necessary). However, if a
|
||||||
|
|
|
@ -100,7 +100,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||||
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
|
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
|
||||||
match pat.node {
|
match pat.node {
|
||||||
PatKind::Ident(_, _, None) |
|
PatKind::Ident(_, _, None) |
|
||||||
PatKind::TupleStruct(_, None) |
|
|
||||||
PatKind::Path(..) |
|
PatKind::Path(..) |
|
||||||
PatKind::QPath(..) |
|
PatKind::QPath(..) |
|
||||||
PatKind::Lit(..) |
|
PatKind::Lit(..) |
|
||||||
|
@ -116,8 +115,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||||
self.add_ast_node(pat.id, &[subpat_exit])
|
self.add_ast_node(pat.id, &[subpat_exit])
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(_, Some(ref subpats)) |
|
PatKind::TupleStruct(_, ref subpats, _) |
|
||||||
PatKind::Tup(ref subpats) => {
|
PatKind::Tuple(ref subpats, _) => {
|
||||||
let pats_exit = self.pats_all(subpats.iter(), pred);
|
let pats_exit = self.pats_all(subpats.iter(), pred);
|
||||||
self.add_ast_node(pat.id, &[pats_exit])
|
self.add_ast_node(pat.id, &[pats_exit])
|
||||||
}
|
}
|
||||||
|
|
|
@ -923,9 +923,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
||||||
sub.map(|x| folder.fold_pat(x)))
|
sub.map(|x| folder.fold_pat(x)))
|
||||||
}
|
}
|
||||||
PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
|
PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
|
||||||
PatKind::TupleStruct(pth, pats) => {
|
PatKind::TupleStruct(pth, pats, ddpos) => {
|
||||||
PatKind::TupleStruct(folder.fold_path(pth),
|
PatKind::TupleStruct(folder.fold_path(pth),
|
||||||
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
|
pats.move_map(|x| folder.fold_pat(x)), ddpos)
|
||||||
}
|
}
|
||||||
PatKind::Path(pth) => {
|
PatKind::Path(pth) => {
|
||||||
PatKind::Path(folder.fold_path(pth))
|
PatKind::Path(folder.fold_path(pth))
|
||||||
|
@ -948,7 +948,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
||||||
});
|
});
|
||||||
PatKind::Struct(pth, fs, etc)
|
PatKind::Struct(pth, fs, etc)
|
||||||
}
|
}
|
||||||
PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))),
|
PatKind::Tuple(elts, ddpos) => {
|
||||||
|
PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos)
|
||||||
|
}
|
||||||
PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
|
PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
|
||||||
PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
|
PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
|
||||||
PatKind::Range(e1, e2) => {
|
PatKind::Range(e1, e2) => {
|
||||||
|
|
|
@ -454,12 +454,10 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||||
|
|
||||||
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||||
match pattern.node {
|
match pattern.node {
|
||||||
PatKind::TupleStruct(ref path, ref opt_children) => {
|
PatKind::TupleStruct(ref path, ref children, _) => {
|
||||||
visitor.visit_path(path, pattern.id);
|
visitor.visit_path(path, pattern.id);
|
||||||
if let Some(ref children) = *opt_children {
|
|
||||||
walk_list!(visitor, visit_pat, children);
|
walk_list!(visitor, visit_pat, children);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
PatKind::Path(ref path) => {
|
PatKind::Path(ref path) => {
|
||||||
visitor.visit_path(path, pattern.id);
|
visitor.visit_path(path, pattern.id);
|
||||||
}
|
}
|
||||||
|
@ -474,7 +472,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||||
visitor.visit_pat(&field.node.pat)
|
visitor.visit_pat(&field.node.pat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref tuple_elements) => {
|
PatKind::Tuple(ref tuple_elements, _) => {
|
||||||
walk_list!(visitor, visit_pat, tuple_elements);
|
walk_list!(visitor, visit_pat, tuple_elements);
|
||||||
}
|
}
|
||||||
PatKind::Box(ref subpattern) |
|
PatKind::Box(ref subpattern) |
|
||||||
|
|
|
@ -872,10 +872,10 @@ impl<'a> LoweringContext<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
|
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
|
||||||
PatKind::TupleStruct(ref pth, ref pats) => {
|
PatKind::TupleStruct(ref pth, ref pats, ddpos) => {
|
||||||
hir::PatKind::TupleStruct(self.lower_path(pth),
|
hir::PatKind::TupleStruct(self.lower_path(pth),
|
||||||
pats.as_ref()
|
pats.iter().map(|x| self.lower_pat(x)).collect(),
|
||||||
.map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect()))
|
ddpos)
|
||||||
}
|
}
|
||||||
PatKind::Path(ref pth) => {
|
PatKind::Path(ref pth) => {
|
||||||
hir::PatKind::Path(self.lower_path(pth))
|
hir::PatKind::Path(self.lower_path(pth))
|
||||||
|
@ -903,8 +903,8 @@ impl<'a> LoweringContext<'a> {
|
||||||
.collect();
|
.collect();
|
||||||
hir::PatKind::Struct(pth, fs, etc)
|
hir::PatKind::Struct(pth, fs, etc)
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref elts) => {
|
PatKind::Tuple(ref elts, ddpos) => {
|
||||||
hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect())
|
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
|
||||||
}
|
}
|
||||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||||
PatKind::Ref(ref inner, mutbl) => {
|
PatKind::Ref(ref inner, mutbl) => {
|
||||||
|
@ -1857,7 +1857,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
let pt = if subpats.is_empty() {
|
let pt = if subpats.is_empty() {
|
||||||
hir::PatKind::Path(path)
|
hir::PatKind::Path(path)
|
||||||
} else {
|
} else {
|
||||||
hir::PatKind::TupleStruct(path, Some(subpats))
|
hir::PatKind::TupleStruct(path, subpats, None)
|
||||||
};
|
};
|
||||||
let pat = self.pat(span, pt);
|
let pat = self.pat(span, pt);
|
||||||
self.resolver.record_resolution(pat.id, def);
|
self.resolver.record_resolution(pat.id, def);
|
||||||
|
|
|
@ -470,7 +470,7 @@ impl Pat {
|
||||||
PatKind::Struct(_, ref fields, _) => {
|
PatKind::Struct(_, ref fields, _) => {
|
||||||
fields.iter().all(|field| field.node.pat.walk_(it))
|
fields.iter().all(|field| field.node.pat.walk_(it))
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => {
|
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||||
s.iter().all(|p| p.walk_(it))
|
s.iter().all(|p| p.walk_(it))
|
||||||
}
|
}
|
||||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
||||||
|
@ -485,7 +485,6 @@ impl Pat {
|
||||||
PatKind::Lit(_) |
|
PatKind::Lit(_) |
|
||||||
PatKind::Range(_, _) |
|
PatKind::Range(_, _) |
|
||||||
PatKind::Ident(_, _, _) |
|
PatKind::Ident(_, _, _) |
|
||||||
PatKind::TupleStruct(..) |
|
|
||||||
PatKind::Path(..) |
|
PatKind::Path(..) |
|
||||||
PatKind::QPath(_, _) => {
|
PatKind::QPath(_, _) => {
|
||||||
true
|
true
|
||||||
|
@ -539,9 +538,10 @@ pub enum PatKind {
|
||||||
/// The `bool` is `true` in the presence of a `..`.
|
/// The `bool` is `true` in the presence of a `..`.
|
||||||
Struct(Path, HirVec<Spanned<FieldPat>>, bool),
|
Struct(Path, HirVec<Spanned<FieldPat>>, bool),
|
||||||
|
|
||||||
/// A tuple struct/variant pattern `Variant(x, y, z)`.
|
/// A tuple struct/variant pattern `Variant(x, y, .., z)`.
|
||||||
/// "None" means a `Variant(..)` pattern where we don't bind the fields to names.
|
/// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
|
||||||
TupleStruct(Path, Option<HirVec<P<Pat>>>),
|
/// 0 <= position <= subpats.len()
|
||||||
|
TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),
|
||||||
|
|
||||||
/// A path pattern.
|
/// A path pattern.
|
||||||
/// Such pattern can be resolved to a unit struct/variant or a constant.
|
/// Such pattern can be resolved to a unit struct/variant or a constant.
|
||||||
|
@ -553,8 +553,10 @@ pub enum PatKind {
|
||||||
/// PatKind::Path, and the resolver will have to sort that out.
|
/// PatKind::Path, and the resolver will have to sort that out.
|
||||||
QPath(QSelf, Path),
|
QPath(QSelf, Path),
|
||||||
|
|
||||||
/// A tuple pattern `(a, b)`
|
/// A tuple pattern `(a, b)`.
|
||||||
Tup(HirVec<P<Pat>>),
|
/// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
|
||||||
|
/// 0 <= position <= subpats.len()
|
||||||
|
Tuple(HirVec<P<Pat>>, Option<usize>),
|
||||||
/// A `box` pattern
|
/// A `box` pattern
|
||||||
Box(P<Pat>),
|
Box(P<Pat>),
|
||||||
/// A reference pattern, e.g. `&mut (a, b)`
|
/// A reference pattern, e.g. `&mut (a, b)`
|
||||||
|
|
|
@ -21,6 +21,28 @@ use std::cell::RefCell;
|
||||||
|
|
||||||
pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
|
pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct AjustPos {
|
||||||
|
gap_pos: usize,
|
||||||
|
gap_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FnOnce<(usize,)> for AjustPos {
|
||||||
|
type Output = usize;
|
||||||
|
extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize {
|
||||||
|
if i < self.gap_pos { i } else { i + self.gap_len }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and
|
||||||
|
// pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2).
|
||||||
|
pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option<usize>) -> AjustPos {
|
||||||
|
AjustPos {
|
||||||
|
gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len },
|
||||||
|
gap_len: expected_len - actual_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is used because same-named variables in alternative patterns need to
|
// This is used because same-named variables in alternative patterns need to
|
||||||
// use the NodeId of their namesake in the first pattern.
|
// use the NodeId of their namesake in the first pattern.
|
||||||
pub fn pat_id_map(dm: &RefCell<DefMap>, pat: &hir::Pat) -> PatIdMap {
|
pub fn pat_id_map(dm: &RefCell<DefMap>, pat: &hir::Pat) -> PatIdMap {
|
||||||
|
|
|
@ -1736,16 +1736,23 @@ impl<'a> State<'a> {
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref path, ref args_) => {
|
PatKind::TupleStruct(ref path, ref elts, ddpos) => {
|
||||||
self.print_path(path, true, 0)?;
|
self.print_path(path, true, 0)?;
|
||||||
match *args_ {
|
|
||||||
None => word(&mut self.s, "(..)")?,
|
|
||||||
Some(ref args) => {
|
|
||||||
self.popen()?;
|
self.popen()?;
|
||||||
self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?;
|
if let Some(ddpos) = ddpos {
|
||||||
self.pclose()?;
|
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
|
||||||
|
if ddpos != 0 {
|
||||||
|
self.word_space(",")?;
|
||||||
}
|
}
|
||||||
|
word(&mut self.s, "..")?;
|
||||||
|
if ddpos != elts.len() {
|
||||||
|
word(&mut self.s, ",")?;
|
||||||
|
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
|
||||||
|
}
|
||||||
|
try!(self.pclose());
|
||||||
}
|
}
|
||||||
PatKind::Path(ref path) => {
|
PatKind::Path(ref path) => {
|
||||||
self.print_path(path, true, 0)?;
|
self.print_path(path, true, 0)?;
|
||||||
|
@ -1778,12 +1785,24 @@ impl<'a> State<'a> {
|
||||||
space(&mut self.s)?;
|
space(&mut self.s)?;
|
||||||
word(&mut self.s, "}")?;
|
word(&mut self.s, "}")?;
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref elts) => {
|
PatKind::Tuple(ref elts, ddpos) => {
|
||||||
self.popen()?;
|
self.popen()?;
|
||||||
|
if let Some(ddpos) = ddpos {
|
||||||
|
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
|
||||||
|
if ddpos != 0 {
|
||||||
|
self.word_space(",")?;
|
||||||
|
}
|
||||||
|
word(&mut self.s, "..")?;
|
||||||
|
if ddpos != elts.len() {
|
||||||
|
word(&mut self.s, ",")?;
|
||||||
|
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
|
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
|
||||||
if elts.len() == 1 {
|
if elts.len() == 1 {
|
||||||
word(&mut self.s, ",")?;
|
word(&mut self.s, ",")?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.pclose()?;
|
self.pclose()?;
|
||||||
}
|
}
|
||||||
PatKind::Box(ref inner) => {
|
PatKind::Box(ref inner) => {
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#![feature(collections)]
|
#![feature(collections)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(enumset)]
|
#![feature(enumset)]
|
||||||
|
#![feature(fn_traits)]
|
||||||
#![feature(iter_arith)]
|
#![feature(iter_arith)]
|
||||||
#![feature(libc)]
|
#![feature(libc)]
|
||||||
#![feature(nonzero)]
|
#![feature(nonzero)]
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(question_mark)]
|
#![feature(question_mark)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
|
|
||||||
extern crate arena;
|
extern crate arena;
|
||||||
|
|
|
@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
// will visit the substructure recursively.
|
// will visit the substructure recursively.
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) |
|
PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) |
|
||||||
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
|
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
|
||||||
PatKind::Vec(..) => {
|
PatKind::Vec(..) => {
|
||||||
// Similarly, each of these cases does not
|
// Similarly, each of these cases does not
|
||||||
|
|
|
@ -80,6 +80,7 @@ use ty::adjustment;
|
||||||
use ty::{self, Ty, TyCtxt};
|
use ty::{self, Ty, TyCtxt};
|
||||||
|
|
||||||
use hir::{MutImmutable, MutMutable, PatKind};
|
use hir::{MutImmutable, MutMutable, PatKind};
|
||||||
|
use hir::pat_util::pat_adjust_pos;
|
||||||
use hir;
|
use hir;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
@ -1225,31 +1226,40 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
// _
|
// _
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(_, None) => {
|
PatKind::TupleStruct(_, ref subpats, ddpos) => {
|
||||||
// variant(..)
|
|
||||||
}
|
|
||||||
PatKind::TupleStruct(_, Some(ref subpats)) => {
|
|
||||||
match opt_def {
|
match opt_def {
|
||||||
Some(Def::Variant(..)) => {
|
Some(Def::Variant(enum_def, def_id)) => {
|
||||||
// variant(x, y, z)
|
// variant(x, y, z)
|
||||||
|
let variant = self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id);
|
||||||
|
let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos);
|
||||||
for (i, subpat) in subpats.iter().enumerate() {
|
for (i, subpat) in subpats.iter().enumerate() {
|
||||||
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
|
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
|
||||||
|
|
||||||
let subcmt =
|
let subcmt =
|
||||||
self.cat_imm_interior(
|
self.cat_imm_interior(
|
||||||
pat, cmt.clone(), subpat_ty,
|
pat, cmt.clone(), subpat_ty,
|
||||||
InteriorField(PositionalField(i)));
|
InteriorField(PositionalField(adjust(i))));
|
||||||
|
|
||||||
self.cat_pattern_(subcmt, &subpat, op)?;
|
self.cat_pattern_(subcmt, &subpat, op)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Def::Struct(..)) => {
|
Some(Def::Struct(..)) => {
|
||||||
|
let expected_len = match self.pat_ty(&pat) {
|
||||||
|
Ok(&ty::TyS{sty: ty::TyStruct(adt_def, _), ..}) => {
|
||||||
|
adt_def.struct_variant().fields.len()
|
||||||
|
}
|
||||||
|
ref ty => {
|
||||||
|
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos);
|
||||||
for (i, subpat) in subpats.iter().enumerate() {
|
for (i, subpat) in subpats.iter().enumerate() {
|
||||||
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
|
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
|
||||||
let cmt_field =
|
let cmt_field =
|
||||||
self.cat_imm_interior(
|
self.cat_imm_interior(
|
||||||
pat, cmt.clone(), subpat_ty,
|
pat, cmt.clone(), subpat_ty,
|
||||||
InteriorField(PositionalField(i)));
|
InteriorField(PositionalField(adjust(i))));
|
||||||
self.cat_pattern_(cmt_field, &subpat, op)?;
|
self.cat_pattern_(cmt_field, &subpat, op)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1284,14 +1294,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Tup(ref subpats) => {
|
PatKind::Tuple(ref subpats, ddpos) => {
|
||||||
// (p1, ..., pN)
|
// (p1, ..., pN)
|
||||||
|
let expected_len = match self.pat_ty(&pat) {
|
||||||
|
Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(),
|
||||||
|
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
|
||||||
|
};
|
||||||
|
let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos);
|
||||||
for (i, subpat) in subpats.iter().enumerate() {
|
for (i, subpat) in subpats.iter().enumerate() {
|
||||||
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
|
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
|
||||||
let subcmt =
|
let subcmt =
|
||||||
self.cat_imm_interior(
|
self.cat_imm_interior(
|
||||||
pat, cmt.clone(), subpat_ty,
|
pat, cmt.clone(), subpat_ty,
|
||||||
InteriorField(PositionalField(i)));
|
InteriorField(PositionalField(adjust(i))));
|
||||||
self.cat_pattern_(subcmt, &subpat, op)?;
|
self.cat_pattern_(subcmt, &subpat, op)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -970,8 +970,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
|
||||||
pats3.iter().any(|p| is_binding_pat(&p))
|
pats3.iter().any(|p| is_binding_pat(&p))
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(_, Some(ref subpats)) |
|
PatKind::TupleStruct(_, ref subpats, _) |
|
||||||
PatKind::Tup(ref subpats) => {
|
PatKind::Tuple(ref subpats, _) => {
|
||||||
subpats.iter().any(|p| is_binding_pat(&p))
|
subpats.iter().any(|p| is_binding_pat(&p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
|
||||||
use hir;
|
use hir;
|
||||||
use hir::{Item, Generics, StructField, Variant, PatKind};
|
use hir::{Item, Generics, StructField, Variant, PatKind};
|
||||||
use hir::intravisit::{self, Visitor};
|
use hir::intravisit::{self, Visitor};
|
||||||
|
use hir::pat_util::pat_adjust_pos;
|
||||||
|
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -614,10 +615,10 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
|
||||||
};
|
};
|
||||||
match pat.node {
|
match pat.node {
|
||||||
// Foo(a, b, c)
|
// Foo(a, b, c)
|
||||||
// A Variant(..) pattern `PatKind::TupleStruct(_, None)` doesn't have to be recursed into.
|
PatKind::TupleStruct(_, ref pat_fields, ddpos) => {
|
||||||
PatKind::TupleStruct(_, Some(ref pat_fields)) => {
|
let adjust = pat_adjust_pos(v.fields.len(), pat_fields.len(), ddpos);
|
||||||
for (field, struct_field) in pat_fields.iter().zip(&v.fields) {
|
for (i, field) in pat_fields.iter().enumerate() {
|
||||||
maybe_do_stability_check(tcx, struct_field.did, field.span, cb)
|
maybe_do_stability_check(tcx, v.fields[adjust(i)].did, field.span, cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Foo { a, b, c }
|
// Foo { a, b, c }
|
||||||
|
|
|
@ -374,7 +374,7 @@ fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
|
||||||
PatKind::Ident(_, _, None) => pat_is_binding(dm, p),
|
PatKind::Ident(_, _, None) => pat_is_binding(dm, p),
|
||||||
PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s),
|
PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s),
|
||||||
PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
|
PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
|
||||||
PatKind::Tup(ref v) => v.iter().all(|p| pat_is_catchall(dm, &p)),
|
PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)),
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir:
|
||||||
hir::MatchSource::ForLoopDesugar => {
|
hir::MatchSource::ForLoopDesugar => {
|
||||||
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
|
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
|
||||||
let witness = match witnesses[0].node {
|
let witness = match witnesses[0].node {
|
||||||
PatKind::TupleStruct(_, Some(ref pats)) => match &pats[..] {
|
PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
|
||||||
[ref pat] => &**pat,
|
[ref pat] => &**pat,
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
},
|
},
|
||||||
|
@ -559,7 +559,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
|
||||||
let pats_len = pats.len();
|
let pats_len = pats.len();
|
||||||
let mut pats = pats.into_iter().map(|p| P((*p).clone()));
|
let mut pats = pats.into_iter().map(|p| P((*p).clone()));
|
||||||
let pat = match left_ty.sty {
|
let pat = match left_ty.sty {
|
||||||
ty::TyTuple(_) => PatKind::Tup(pats.collect()),
|
ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),
|
||||||
|
|
||||||
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
|
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
|
||||||
let v = ctor.variant_for_adt(adt);
|
let v = ctor.variant_for_adt(adt);
|
||||||
|
@ -580,7 +580,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
|
||||||
PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields)
|
PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields)
|
||||||
}
|
}
|
||||||
VariantKind::Tuple => {
|
VariantKind::Tuple => {
|
||||||
PatKind::TupleStruct(def_to_path(cx.tcx, v.did), Some(pats.collect()))
|
PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None)
|
||||||
}
|
}
|
||||||
VariantKind::Unit => {
|
VariantKind::Unit => {
|
||||||
PatKind::Path(def_to_path(cx.tcx, v.did))
|
PatKind::Path(def_to_path(cx.tcx, v.did))
|
||||||
|
@ -832,7 +832,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
||||||
vec!(Slice(before.len() + after.len()))
|
vec!(Slice(before.len() + after.len()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PatKind::Box(_) | PatKind::Tup(_) | PatKind::Ref(..) =>
|
PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) =>
|
||||||
vec!(Single),
|
vec!(Single),
|
||||||
PatKind::Wild =>
|
PatKind::Wild =>
|
||||||
vec!(),
|
vec!(),
|
||||||
|
@ -914,7 +914,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(_, ref args) => {
|
PatKind::TupleStruct(_, ref args, ddpos) => {
|
||||||
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
||||||
match def {
|
match def {
|
||||||
Def::Const(..) | Def::AssociatedConst(..) =>
|
Def::Const(..) | Def::AssociatedConst(..) =>
|
||||||
|
@ -922,10 +922,15 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
||||||
been rewritten"),
|
been rewritten"),
|
||||||
Def::Variant(_, id) if *constructor != Variant(id) => None,
|
Def::Variant(_, id) if *constructor != Variant(id) => None,
|
||||||
Def::Variant(..) | Def::Struct(..) => {
|
Def::Variant(..) | Def::Struct(..) => {
|
||||||
Some(match args {
|
match ddpos {
|
||||||
&Some(ref args) => args.iter().map(|p| &**p).collect(),
|
Some(ddpos) => {
|
||||||
&None => vec![DUMMY_WILD_PAT; arity],
|
let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>;
|
||||||
})
|
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len()));
|
||||||
|
pats.extend(args[ddpos..].iter().map(|p| &**p));
|
||||||
|
Some(pats)
|
||||||
|
}
|
||||||
|
None => Some(args.iter().map(|p| &**p).collect())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
@ -952,7 +957,13 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Tup(ref args) =>
|
PatKind::Tuple(ref args, Some(ddpos)) => {
|
||||||
|
let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>;
|
||||||
|
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len()));
|
||||||
|
pats.extend(args[ddpos..].iter().map(|p| &**p));
|
||||||
|
Some(pats)
|
||||||
|
}
|
||||||
|
PatKind::Tuple(ref args, None) =>
|
||||||
Some(args.iter().map(|p| &**p).collect()),
|
Some(args.iter().map(|p| &**p).collect()),
|
||||||
|
|
||||||
PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) =>
|
PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) =>
|
||||||
|
|
|
@ -271,10 +271,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
let pat = match expr.node {
|
let pat = match expr.node {
|
||||||
hir::ExprTup(ref exprs) =>
|
hir::ExprTup(ref exprs) =>
|
||||||
PatKind::Tup(try!(exprs.iter()
|
PatKind::Tuple(try!(exprs.iter()
|
||||||
.map(|expr| const_expr_to_pat(tcx, &expr,
|
.map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
|
||||||
pat_id, span))
|
.collect()), None),
|
||||||
.collect())),
|
|
||||||
|
|
||||||
hir::ExprCall(ref callee, ref args) => {
|
hir::ExprCall(ref callee, ref args) => {
|
||||||
let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
|
let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
|
||||||
|
@ -295,7 +294,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
.map(|expr| const_expr_to_pat(tcx, &**expr,
|
.map(|expr| const_expr_to_pat(tcx, &**expr,
|
||||||
pat_id, span))
|
pat_id, span))
|
||||||
.collect());
|
.collect());
|
||||||
PatKind::TupleStruct(path, Some(pats))
|
PatKind::TupleStruct(path, pats, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprStruct(ref path, ref fields, None) => {
|
hir::ExprStruct(ref path, ref fields, None) => {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#![feature(question_mark)]
|
#![feature(question_mark)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
#![feature(type_ascription)]
|
||||||
|
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
|
|
@ -13,7 +13,7 @@ use hair::cx::Cx;
|
||||||
use rustc_data_structures::fnv::FnvHashMap;
|
use rustc_data_structures::fnv::FnvHashMap;
|
||||||
use rustc_const_eval as const_eval;
|
use rustc_const_eval as const_eval;
|
||||||
use rustc::hir::def::Def;
|
use rustc::hir::def::Def;
|
||||||
use rustc::hir::pat_util::{pat_is_resolved_const, pat_is_binding};
|
use rustc::hir::pat_util::{pat_adjust_pos, pat_is_resolved_const, pat_is_binding};
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::hir::{self, PatKind};
|
use rustc::hir::{self, PatKind};
|
||||||
|
@ -148,12 +148,15 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Tup(ref subpatterns) => {
|
PatKind::Tuple(ref subpatterns, ddpos) => {
|
||||||
|
match self.cx.tcx.node_id_to_type(pat.id).sty {
|
||||||
|
ty::TyTuple(ref tys) => {
|
||||||
|
let adjust = pat_adjust_pos(tys.len(), subpatterns.len(), ddpos);
|
||||||
let subpatterns =
|
let subpatterns =
|
||||||
subpatterns.iter()
|
subpatterns.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, subpattern)| FieldPattern {
|
.map(|(i, subpattern)| FieldPattern {
|
||||||
field: Field::new(i),
|
field: Field::new(adjust(i)),
|
||||||
pattern: self.to_pattern(subpattern),
|
pattern: self.to_pattern(subpattern),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -161,6 +164,10 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
|
||||||
PatternKind::Leaf { subpatterns: subpatterns }
|
PatternKind::Leaf { subpatterns: subpatterns }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Ident(bm, ref ident, ref sub)
|
PatKind::Ident(bm, ref ident, ref sub)
|
||||||
if pat_is_binding(&self.cx.tcx.def_map.borrow(), pat) =>
|
if pat_is_binding(&self.cx.tcx.def_map.borrow(), pat) =>
|
||||||
{
|
{
|
||||||
|
@ -208,13 +215,21 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
|
||||||
self.variant_or_leaf(pat, vec![])
|
self.variant_or_leaf(pat, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(_, ref opt_subpatterns) => {
|
PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
|
||||||
|
let pat_ty = self.cx.tcx.node_id_to_type(pat.id);
|
||||||
|
let adt_def = match pat_ty.sty {
|
||||||
|
ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def,
|
||||||
|
_ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"),
|
||||||
|
};
|
||||||
|
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
|
||||||
|
let variant_def = adt_def.variant_of_def(def);
|
||||||
|
|
||||||
|
let adjust = pat_adjust_pos(variant_def.fields.len(), subpatterns.len(), ddpos);
|
||||||
let subpatterns =
|
let subpatterns =
|
||||||
opt_subpatterns.iter()
|
subpatterns.iter()
|
||||||
.flat_map(|v| v.iter())
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, field)| FieldPattern {
|
.map(|(i, field)| FieldPattern {
|
||||||
field: Field::new(i),
|
field: Field::new(adjust(i)),
|
||||||
pattern: self.to_pattern(field),
|
pattern: self.to_pattern(field),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -31,7 +31,7 @@ use std::mem::replace;
|
||||||
|
|
||||||
use rustc::hir::{self, PatKind};
|
use rustc::hir::{self, PatKind};
|
||||||
use rustc::hir::intravisit::{self, Visitor};
|
use rustc::hir::intravisit::{self, Visitor};
|
||||||
|
use rustc::hir::pat_util::pat_adjust_pos;
|
||||||
use rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
use rustc::hir::def::{self, Def};
|
use rustc::hir::def::{self, Def};
|
||||||
|
@ -488,17 +488,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
|
||||||
self.check_field(pattern.span, adt, variant.field_named(field.node.name));
|
self.check_field(pattern.span, adt, variant.field_named(field.node.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatKind::TupleStruct(_, ref fields, ddpos) => {
|
||||||
// Patterns which bind no fields are allowable (the path is check
|
|
||||||
// elsewhere).
|
|
||||||
PatKind::TupleStruct(_, Some(ref fields)) => {
|
|
||||||
match self.tcx.pat_ty(pattern).sty {
|
match self.tcx.pat_ty(pattern).sty {
|
||||||
ty::TyStruct(def, _) => {
|
ty::TyStruct(def, _) => {
|
||||||
|
let adjust = pat_adjust_pos(def.struct_variant().fields.len(),
|
||||||
|
fields.len(), ddpos);
|
||||||
for (i, field) in fields.iter().enumerate() {
|
for (i, field) in fields.iter().enumerate() {
|
||||||
if let PatKind::Wild = field.node {
|
if let PatKind::Wild = field.node {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
self.check_field(field.span, def, &def.struct_variant().fields[i]);
|
self.check_field(field.span, def,
|
||||||
|
&def.struct_variant().fields[adjust(i)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::TyEnum(..) => {
|
ty::TyEnum(..) => {
|
||||||
|
@ -506,7 +506,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2360,7 +2360,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(ref path, _) | PatKind::Path(ref path) => {
|
PatKind::TupleStruct(ref path, _, _) | PatKind::Path(ref path) => {
|
||||||
// This must be an enum variant, struct or const.
|
// This must be an enum variant, struct or const.
|
||||||
let resolution = match self.resolve_possibly_assoc_item(pat_id,
|
let resolution = match self.resolve_possibly_assoc_item(pat_id,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -696,7 +696,7 @@ impl<'v> Visitor<'v> for PathCollector {
|
||||||
self.collected_paths.push((p.id, path.clone(),
|
self.collected_paths.push((p.id, path.clone(),
|
||||||
ast::Mutability::Mutable, recorder::TypeRef));
|
ast::Mutability::Mutable, recorder::TypeRef));
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref path, _) |
|
PatKind::TupleStruct(ref path, _, _) |
|
||||||
PatKind::Path(ref path) |
|
PatKind::Path(ref path) |
|
||||||
PatKind::QPath(_, ref path) => {
|
PatKind::QPath(_, ref path) => {
|
||||||
self.collected_paths.push((p.id, path.clone(),
|
self.collected_paths.push((p.id, path.clone(),
|
||||||
|
|
|
@ -792,7 +792,7 @@ fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool {
|
||||||
m.iter().any(|br| {
|
m.iter().any(|br| {
|
||||||
let pat = br.pats[col];
|
let pat = br.pats[col];
|
||||||
match pat.node {
|
match pat.node {
|
||||||
PatKind::Tup(_) => true,
|
PatKind::Tuple(..) => true,
|
||||||
PatKind::Struct(..) | PatKind::TupleStruct(..) |
|
PatKind::Struct(..) | PatKind::TupleStruct(..) |
|
||||||
PatKind::Path(..) | PatKind::Ident(_, _, None) => {
|
PatKind::Path(..) | PatKind::Ident(_, _, None) => {
|
||||||
match tcx.def_map.borrow().get(&pat.id).unwrap().full_def() {
|
match tcx.def_map.borrow().get(&pat.id).unwrap().full_def() {
|
||||||
|
@ -1833,7 +1833,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
bcx = bind_irrefutable_pat(bcx, &inner_pat, val, cleanup_scope);
|
bcx = bind_irrefutable_pat(bcx, &inner_pat, val, cleanup_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(_, ref sub_pats) => {
|
PatKind::TupleStruct(_, ref sub_pats, ddpos) => {
|
||||||
let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
|
let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
|
||||||
match opt_def {
|
match opt_def {
|
||||||
Some(Def::Variant(enum_id, var_id)) => {
|
Some(Def::Variant(enum_id, var_id)) => {
|
||||||
|
@ -1843,28 +1843,31 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
&repr,
|
&repr,
|
||||||
Disr::from(vinfo.disr_val),
|
Disr::from(vinfo.disr_val),
|
||||||
val);
|
val);
|
||||||
if let Some(ref sub_pat) = *sub_pats {
|
let adjust = pat_adjust_pos(vinfo.fields.len(), sub_pats.len(), ddpos);
|
||||||
for (i, &argval) in args.vals.iter().enumerate() {
|
for (i, subpat) in sub_pats.iter().enumerate() {
|
||||||
bcx = bind_irrefutable_pat(
|
bcx = bind_irrefutable_pat(
|
||||||
bcx,
|
bcx,
|
||||||
&sub_pat[i],
|
subpat,
|
||||||
MatchInput::from_val(argval),
|
MatchInput::from_val(args.vals[adjust(i)]),
|
||||||
cleanup_scope);
|
cleanup_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Some(Def::Struct(..)) => {
|
Some(Def::Struct(..)) => {
|
||||||
match *sub_pats {
|
let expected_len = match *ccx.tcx().pat_ty(&pat) {
|
||||||
None => {
|
ty::TyS{sty: ty::TyStruct(adt_def, _), ..} => {
|
||||||
// This is a unit-like struct. Nothing to do here.
|
adt_def.struct_variant().fields.len()
|
||||||
}
|
}
|
||||||
Some(ref elems) => {
|
ref ty => {
|
||||||
// This is the tuple struct case.
|
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let adjust = pat_adjust_pos(expected_len, sub_pats.len(), ddpos);
|
||||||
let repr = adt::represent_node(bcx, pat.id);
|
let repr = adt::represent_node(bcx, pat.id);
|
||||||
let val = adt::MaybeSizedValue::sized(val.val);
|
let val = adt::MaybeSizedValue::sized(val.val);
|
||||||
for (i, elem) in elems.iter().enumerate() {
|
for (i, elem) in sub_pats.iter().enumerate() {
|
||||||
let fldptr = adt::trans_field_ptr(bcx, &repr,
|
let fldptr = adt::trans_field_ptr(bcx, &repr,
|
||||||
val, Disr(0), i);
|
val, Disr(0), adjust(i));
|
||||||
bcx = bind_irrefutable_pat(
|
bcx = bind_irrefutable_pat(
|
||||||
bcx,
|
bcx,
|
||||||
&elem,
|
&elem,
|
||||||
|
@ -1872,8 +1875,6 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
cleanup_scope);
|
cleanup_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
}
|
}
|
||||||
|
@ -1919,11 +1920,14 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
cleanup_scope);
|
cleanup_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref elems) => {
|
PatKind::Tuple(ref elems, ddpos) => {
|
||||||
|
match tcx.node_id_to_type(pat.id).sty {
|
||||||
|
ty::TyTuple(ref tys) => {
|
||||||
|
let adjust = pat_adjust_pos(tys.len(), elems.len(), ddpos);
|
||||||
let repr = adt::represent_node(bcx, pat.id);
|
let repr = adt::represent_node(bcx, pat.id);
|
||||||
let val = adt::MaybeSizedValue::sized(val.val);
|
let val = adt::MaybeSizedValue::sized(val.val);
|
||||||
for (i, elem) in elems.iter().enumerate() {
|
for (i, elem) in elems.iter().enumerate() {
|
||||||
let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i);
|
let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), adjust(i));
|
||||||
bcx = bind_irrefutable_pat(
|
bcx = bind_irrefutable_pat(
|
||||||
bcx,
|
bcx,
|
||||||
&elem,
|
&elem,
|
||||||
|
@ -1931,6 +1935,9 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
cleanup_scope);
|
cleanup_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
|
||||||
|
}
|
||||||
|
}
|
||||||
PatKind::Box(ref inner) => {
|
PatKind::Box(ref inner) => {
|
||||||
let pat_ty = node_id_type(bcx, inner.id);
|
let pat_ty = node_id_type(bcx, inner.id);
|
||||||
// Pass along DSTs as fat pointers.
|
// Pass along DSTs as fat pointers.
|
||||||
|
|
|
@ -318,15 +318,13 @@ fn walk_pattern(cx: &CrateContext,
|
||||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::TupleStruct(_, ref sub_pats_opt) => {
|
PatKind::TupleStruct(_, ref sub_pats, _) => {
|
||||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||||
|
|
||||||
if let Some(ref sub_pats) = *sub_pats_opt {
|
|
||||||
for p in sub_pats {
|
for p in sub_pats {
|
||||||
walk_pattern(cx, &p, scope_stack, scope_map);
|
walk_pattern(cx, &p, scope_stack, scope_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Path(..) | PatKind::QPath(..) => {
|
PatKind::Path(..) | PatKind::QPath(..) => {
|
||||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||||
|
@ -343,7 +341,7 @@ fn walk_pattern(cx: &CrateContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Tup(ref sub_pats) => {
|
PatKind::Tuple(ref sub_pats, _) => {
|
||||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||||
|
|
||||||
for sub_pat in sub_pats {
|
for sub_pat in sub_pats {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use hir::def::{self, Def};
|
use hir::def::{self, Def};
|
||||||
use rustc::infer::{self, InferOk, TypeOrigin};
|
use rustc::infer::{self, InferOk, TypeOrigin};
|
||||||
use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
|
use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
|
||||||
use hir::pat_util::pat_is_resolved_const;
|
use hir::pat_util::{pat_adjust_pos, pat_is_resolved_const};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
|
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
|
||||||
use check::{FnCtxt, Expectation};
|
use check::{FnCtxt, Expectation};
|
||||||
|
@ -213,13 +213,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
PatKind::Ident(_, ref path, _) => {
|
PatKind::Ident(_, ref path, _) => {
|
||||||
let path = hir::Path::from_name(path.span, path.node);
|
let path = hir::Path::from_name(path.span, path.node);
|
||||||
self.check_pat_enum(pat, &path, Some(&[]), expected, false);
|
self.check_pat_enum(pat, &path, &[], None, expected, false);
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref path, ref subpats) => {
|
PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
|
||||||
self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true);
|
self.check_pat_enum(pat, path, &subpats, ddpos, expected, true);
|
||||||
}
|
}
|
||||||
PatKind::Path(ref path) => {
|
PatKind::Path(ref path) => {
|
||||||
self.check_pat_enum(pat, path, Some(&[]), expected, false);
|
self.check_pat_enum(pat, path, &[], None, expected, false);
|
||||||
}
|
}
|
||||||
PatKind::QPath(ref qself, ref path) => {
|
PatKind::QPath(ref qself, ref path) => {
|
||||||
let self_ty = self.to_ty(&qself.ty);
|
let self_ty = self.to_ty(&qself.ty);
|
||||||
|
@ -260,14 +260,24 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
PatKind::Struct(ref path, ref fields, etc) => {
|
PatKind::Struct(ref path, ref fields, etc) => {
|
||||||
self.check_pat_struct(pat, path, fields, etc, expected);
|
self.check_pat_struct(pat, path, fields, etc, expected);
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref elements) => {
|
PatKind::Tuple(ref elements, ddpos) => {
|
||||||
let element_tys: Vec<_> =
|
let mut expected_len = elements.len();
|
||||||
(0..elements.len()).map(|_| self.next_ty_var()).collect();
|
if ddpos.is_some() {
|
||||||
|
// Require known type only when `..` is present
|
||||||
|
if let ty::TyTuple(ref tys) =
|
||||||
|
self.structurally_resolved_type(pat.span, expected).sty {
|
||||||
|
expected_len = tys.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let max_len = cmp::max(expected_len, elements.len());
|
||||||
|
|
||||||
|
let element_tys = (0 .. max_len).map(|_| self.next_ty_var()).collect(): Vec<_>;
|
||||||
let pat_ty = tcx.mk_tup(element_tys.clone());
|
let pat_ty = tcx.mk_tup(element_tys.clone());
|
||||||
self.write_ty(pat.id, pat_ty);
|
self.write_ty(pat.id, pat_ty);
|
||||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||||
for (element_pat, element_ty) in elements.iter().zip(element_tys) {
|
let adjust = pat_adjust_pos(expected_len, elements.len(), ddpos);
|
||||||
self.check_pat(&element_pat, element_ty);
|
for i in 0 .. elements.len() {
|
||||||
|
self.check_pat(&elements[i], &element_tys[adjust(i)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Box(ref inner) => {
|
PatKind::Box(ref inner) => {
|
||||||
|
@ -615,7 +625,8 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
fn check_pat_enum(&self,
|
fn check_pat_enum(&self,
|
||||||
pat: &hir::Pat,
|
pat: &hir::Pat,
|
||||||
path: &hir::Path,
|
path: &hir::Path,
|
||||||
subpats: Option<&'gcx [P<hir::Pat>]>,
|
subpats: &'gcx [P<hir::Pat>],
|
||||||
|
ddpos: Option<usize>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
is_tuple_struct_pat: bool)
|
is_tuple_struct_pat: bool)
|
||||||
{
|
{
|
||||||
|
@ -628,12 +639,9 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.set_tainted_by_errors();
|
self.set_tainted_by_errors();
|
||||||
self.write_error(pat.id);
|
self.write_error(pat.id);
|
||||||
|
|
||||||
if let Some(subpats) = subpats {
|
|
||||||
for pat in subpats {
|
for pat in subpats {
|
||||||
self.check_pat(&pat, tcx.types.err);
|
self.check_pat(&pat, tcx.types.err);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -670,16 +678,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
self.instantiate_path(segments, path_scheme, &ctor_predicates,
|
self.instantiate_path(segments, path_scheme, &ctor_predicates,
|
||||||
opt_ty, def, pat.span, pat.id);
|
opt_ty, def, pat.span, pat.id);
|
||||||
|
|
||||||
let report_bad_struct_kind = |is_warning| {
|
let report_bad_struct_kind = |is_warning| {
|
||||||
bad_struct_kind_err(tcx.sess, pat, path, is_warning);
|
bad_struct_kind_err(tcx.sess, pat, path, is_warning);
|
||||||
if is_warning { return; }
|
if is_warning { return; }
|
||||||
self.write_error(pat.id);
|
self.write_error(pat.id);
|
||||||
if let Some(subpats) = subpats {
|
|
||||||
for pat in subpats {
|
for pat in subpats {
|
||||||
self.check_pat(&pat, tcx.types.err);
|
self.check_pat(&pat, tcx.types.err);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we didn't have a fully resolved path to start with, we had an
|
// If we didn't have a fully resolved path to start with, we had an
|
||||||
|
@ -715,11 +720,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match (is_tuple_struct_pat, variant.kind()) {
|
match (is_tuple_struct_pat, variant.kind()) {
|
||||||
(true, ty::VariantKind::Unit) => {
|
(true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => {
|
||||||
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
|
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
|
||||||
// is allowed for backward compatibility.
|
// is allowed for backward compatibility.
|
||||||
report_bad_struct_kind(true);
|
report_bad_struct_kind(true);
|
||||||
}
|
}
|
||||||
|
(true, ty::VariantKind::Unit) |
|
||||||
|
(false, ty::VariantKind::Tuple) |
|
||||||
(_, ty::VariantKind::Struct) => {
|
(_, ty::VariantKind::Struct) => {
|
||||||
report_bad_struct_kind(false);
|
report_bad_struct_kind(false);
|
||||||
return
|
return
|
||||||
|
@ -727,20 +734,14 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(subpats) = subpats {
|
let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos);
|
||||||
if subpats.len() == variant.fields.len() {
|
if subpats.len() == variant.fields.len() ||
|
||||||
for (subpat, field) in subpats.iter().zip(&variant.fields) {
|
subpats.len() < variant.fields.len() && ddpos.is_some() {
|
||||||
let field_ty = self.field_ty(subpat.span, field, expected_substs);
|
for (i, subpat) in subpats.iter().enumerate() {
|
||||||
|
let field_ty = self.field_ty(subpat.span,
|
||||||
|
&variant.fields[adjust(i)], expected_substs);
|
||||||
self.check_pat(&subpat, field_ty);
|
self.check_pat(&subpat, field_ty);
|
||||||
}
|
}
|
||||||
} else if variant.fields.is_empty() {
|
|
||||||
span_err!(tcx.sess, pat.span, E0024,
|
|
||||||
"this pattern has {} field{}, but the corresponding {} has no fields",
|
|
||||||
subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
|
|
||||||
|
|
||||||
for pat in subpats {
|
|
||||||
self.check_pat(&pat, tcx.types.err);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
span_err!(tcx.sess, pat.span, E0023,
|
span_err!(tcx.sess, pat.span, E0023,
|
||||||
"this pattern has {} field{}, but the corresponding {} has {} field{}",
|
"this pattern has {} field{}, but the corresponding {} has {} field{}",
|
||||||
|
@ -753,7 +754,6 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// `path` is the AST path item naming the type of this struct.
|
/// `path` is the AST path item naming the type of this struct.
|
||||||
/// `fields` is the field patterns of the struct pattern.
|
/// `fields` is the field patterns of the struct pattern.
|
||||||
|
|
|
@ -62,31 +62,6 @@ Check how many fields the enum was declared with and ensure that your pattern
|
||||||
uses the same number.
|
uses the same number.
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0024: r##"
|
|
||||||
This error indicates that a pattern attempted to extract the fields of an enum
|
|
||||||
variant with no fields. Here's a tiny example of this error:
|
|
||||||
|
|
||||||
```compile_fail
|
|
||||||
// This enum has two variants.
|
|
||||||
enum Number {
|
|
||||||
// This variant has no fields.
|
|
||||||
Zero,
|
|
||||||
// This variant has one field.
|
|
||||||
One(u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assuming x is a Number we can pattern match on its contents.
|
|
||||||
match x {
|
|
||||||
Number::Zero(inside) => {},
|
|
||||||
Number::One(inside) => {},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The pattern match `Zero(inside)` is incorrect because the `Zero` variant
|
|
||||||
contains no fields, yet the `inside` name attempts to bind the first field of
|
|
||||||
the enum.
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0025: r##"
|
E0025: r##"
|
||||||
Each field of a struct can only be bound once in a pattern. Erroneous code
|
Each field of a struct can only be bound once in a pattern. Erroneous code
|
||||||
example:
|
example:
|
||||||
|
|
|
@ -77,11 +77,12 @@ This API is completely unstable and subject to change.
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(iter_arith)]
|
#![feature(iter_arith)]
|
||||||
|
#![feature(question_mark)]
|
||||||
#![feature(quote)]
|
#![feature(quote)]
|
||||||
#![feature(rustc_diagnostic_macros)]
|
#![feature(rustc_diagnostic_macros)]
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(question_mark)]
|
#![feature(type_ascription)]
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
|
|
|
@ -2579,7 +2579,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
|
||||||
match p.node {
|
match p.node {
|
||||||
PatKind::Wild => "_".to_string(),
|
PatKind::Wild => "_".to_string(),
|
||||||
PatKind::Ident(_, ref p, _) => p.node.to_string(),
|
PatKind::Ident(_, ref p, _) => p.node.to_string(),
|
||||||
PatKind::TupleStruct(ref p, _) | PatKind::Path(ref p) => path_to_string(p),
|
PatKind::TupleStruct(ref p, _, _) | PatKind::Path(ref p) => path_to_string(p),
|
||||||
PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \
|
PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \
|
||||||
which is not allowed in function arguments"),
|
which is not allowed in function arguments"),
|
||||||
PatKind::Struct(ref name, ref fields, etc) => {
|
PatKind::Struct(ref name, ref fields, etc) => {
|
||||||
|
@ -2590,7 +2590,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
|
||||||
if etc { ", ..." } else { "" }
|
if etc { ", ..." } else { "" }
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
PatKind::Tup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
|
PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
|
||||||
.collect::<Vec<String>>().join(", ")),
|
.collect::<Vec<String>>().join(", ")),
|
||||||
PatKind::Box(ref p) => name_from_pat(&**p),
|
PatKind::Box(ref p) => name_from_pat(&**p),
|
||||||
PatKind::Ref(ref p, _) => name_from_pat(&**p),
|
PatKind::Ref(ref p, _) => name_from_pat(&**p),
|
||||||
|
|
|
@ -567,7 +567,7 @@ impl Pat {
|
||||||
PatKind::Struct(_, ref fields, _) => {
|
PatKind::Struct(_, ref fields, _) => {
|
||||||
fields.iter().all(|field| field.node.pat.walk(it))
|
fields.iter().all(|field| field.node.pat.walk(it))
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => {
|
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||||
s.iter().all(|p| p.walk(it))
|
s.iter().all(|p| p.walk(it))
|
||||||
}
|
}
|
||||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
||||||
|
@ -582,7 +582,6 @@ impl Pat {
|
||||||
PatKind::Lit(_) |
|
PatKind::Lit(_) |
|
||||||
PatKind::Range(_, _) |
|
PatKind::Range(_, _) |
|
||||||
PatKind::Ident(_, _, _) |
|
PatKind::Ident(_, _, _) |
|
||||||
PatKind::TupleStruct(..) |
|
|
||||||
PatKind::Path(..) |
|
PatKind::Path(..) |
|
||||||
PatKind::QPath(_, _) |
|
PatKind::QPath(_, _) |
|
||||||
PatKind::Mac(_) => {
|
PatKind::Mac(_) => {
|
||||||
|
@ -631,9 +630,10 @@ pub enum PatKind {
|
||||||
/// The `bool` is `true` in the presence of a `..`.
|
/// The `bool` is `true` in the presence of a `..`.
|
||||||
Struct(Path, Vec<Spanned<FieldPat>>, bool),
|
Struct(Path, Vec<Spanned<FieldPat>>, bool),
|
||||||
|
|
||||||
/// A tuple struct/variant pattern `Variant(x, y, z)`.
|
/// A tuple struct/variant pattern `Variant(x, y, .., z)`.
|
||||||
/// "None" means a `Variant(..)` pattern where we don't bind the fields to names.
|
/// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
|
||||||
TupleStruct(Path, Option<Vec<P<Pat>>>),
|
/// 0 <= position <= subpats.len()
|
||||||
|
TupleStruct(Path, Vec<P<Pat>>, Option<usize>),
|
||||||
|
|
||||||
/// A path pattern.
|
/// A path pattern.
|
||||||
/// Such pattern can be resolved to a unit struct/variant or a constant.
|
/// Such pattern can be resolved to a unit struct/variant or a constant.
|
||||||
|
@ -645,8 +645,10 @@ pub enum PatKind {
|
||||||
/// PatKind::Path, and the resolver will have to sort that out.
|
/// PatKind::Path, and the resolver will have to sort that out.
|
||||||
QPath(QSelf, Path),
|
QPath(QSelf, Path),
|
||||||
|
|
||||||
/// A tuple pattern `(a, b)`
|
/// A tuple pattern `(a, b)`.
|
||||||
Tup(Vec<P<Pat>>),
|
/// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
|
||||||
|
/// 0 <= position <= subpats.len()
|
||||||
|
Tuple(Vec<P<Pat>>, Option<usize>),
|
||||||
/// A `box` pattern
|
/// A `box` pattern
|
||||||
Box(P<Pat>),
|
Box(P<Pat>),
|
||||||
/// A reference pattern, e.g. `&mut (a, b)`
|
/// A reference pattern, e.g. `&mut (a, b)`
|
||||||
|
|
|
@ -832,7 +832,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
let pat = if subpats.is_empty() {
|
let pat = if subpats.is_empty() {
|
||||||
PatKind::Path(path)
|
PatKind::Path(path)
|
||||||
} else {
|
} else {
|
||||||
PatKind::TupleStruct(path, Some(subpats))
|
PatKind::TupleStruct(path, subpats, None)
|
||||||
};
|
};
|
||||||
self.pat(span, pat)
|
self.pat(span, pat)
|
||||||
}
|
}
|
||||||
|
@ -842,7 +842,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
self.pat(span, pat)
|
self.pat(span, pat)
|
||||||
}
|
}
|
||||||
fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
|
fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
|
||||||
self.pat(span, PatKind::Tup(pats))
|
self.pat(span, PatKind::Tuple(pats, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
|
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
|
||||||
|
|
|
@ -274,7 +274,10 @@ declare_features! (
|
||||||
(active, drop_types_in_const, "1.9.0", Some(33156)),
|
(active, drop_types_in_const, "1.9.0", Some(33156)),
|
||||||
|
|
||||||
// Allows cfg(target_has_atomic = "...").
|
// Allows cfg(target_has_atomic = "...").
|
||||||
(active, cfg_target_has_atomic, "1.9.0", Some(32976))
|
(active, cfg_target_has_atomic, "1.9.0", Some(32976)),
|
||||||
|
|
||||||
|
// Allows `..` in tuple (struct) patterns
|
||||||
|
(active, dotdot_in_tuple_patterns, "1.10.0", Some(33627))
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
|
@ -315,7 +318,6 @@ declare_features! (
|
||||||
// Allows `#[deprecated]` attribute
|
// Allows `#[deprecated]` attribute
|
||||||
(accepted, deprecated, "1.9.0", Some(29935))
|
(accepted, deprecated, "1.9.0", Some(29935))
|
||||||
);
|
);
|
||||||
|
|
||||||
// (changing above list without updating src/doc/reference.md makes @cmr sad)
|
// (changing above list without updating src/doc/reference.md makes @cmr sad)
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||||
|
@ -1021,6 +1023,24 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
|
||||||
pattern.span,
|
pattern.span,
|
||||||
"box pattern syntax is experimental");
|
"box pattern syntax is experimental");
|
||||||
}
|
}
|
||||||
|
PatKind::Tuple(_, ddpos)
|
||||||
|
if ddpos.is_some() => {
|
||||||
|
gate_feature_post!(&self, dotdot_in_tuple_patterns,
|
||||||
|
pattern.span,
|
||||||
|
"`..` in tuple patterns is experimental");
|
||||||
|
}
|
||||||
|
PatKind::TupleStruct(_, ref fields, ddpos)
|
||||||
|
if ddpos.is_some() && !fields.is_empty() => {
|
||||||
|
gate_feature_post!(&self, dotdot_in_tuple_patterns,
|
||||||
|
pattern.span,
|
||||||
|
"`..` in tuple struct patterns is experimental");
|
||||||
|
}
|
||||||
|
PatKind::TupleStruct(_, ref fields, ddpos)
|
||||||
|
if ddpos.is_none() && fields.is_empty() => {
|
||||||
|
self.context.span_handler.struct_span_err(pattern.span,
|
||||||
|
"nullary enum variants are written with \
|
||||||
|
no trailing `( )`").emit();
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_pat(self, pattern)
|
visit::walk_pat(self, pattern)
|
||||||
|
|
|
@ -1115,9 +1115,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
||||||
sub.map(|x| folder.fold_pat(x)))
|
sub.map(|x| folder.fold_pat(x)))
|
||||||
}
|
}
|
||||||
PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
|
PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
|
||||||
PatKind::TupleStruct(pth, pats) => {
|
PatKind::TupleStruct(pth, pats, ddpos) => {
|
||||||
PatKind::TupleStruct(folder.fold_path(pth),
|
PatKind::TupleStruct(folder.fold_path(pth),
|
||||||
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
|
pats.move_map(|x| folder.fold_pat(x)), ddpos)
|
||||||
}
|
}
|
||||||
PatKind::Path(pth) => {
|
PatKind::Path(pth) => {
|
||||||
PatKind::Path(folder.fold_path(pth))
|
PatKind::Path(folder.fold_path(pth))
|
||||||
|
@ -1138,7 +1138,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
||||||
});
|
});
|
||||||
PatKind::Struct(pth, fs, etc)
|
PatKind::Struct(pth, fs, etc)
|
||||||
}
|
}
|
||||||
PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))),
|
PatKind::Tuple(elts, ddpos) => {
|
||||||
|
PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos)
|
||||||
|
}
|
||||||
PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
|
PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
|
||||||
PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
|
PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
|
||||||
PatKind::Range(e1, e2) => {
|
PatKind::Range(e1, e2) => {
|
||||||
|
|
|
@ -954,25 +954,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a sequence parameter of enum variant. For consistency purposes,
|
|
||||||
/// these should not be empty.
|
|
||||||
pub fn parse_enum_variant_seq<T, F>(&mut self,
|
|
||||||
bra: &token::Token,
|
|
||||||
ket: &token::Token,
|
|
||||||
sep: SeqSep,
|
|
||||||
f: F)
|
|
||||||
-> PResult<'a, Vec<T>> where
|
|
||||||
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
|
||||||
{
|
|
||||||
let result = self.parse_unspanned_seq(bra, ket, sep, f)?;
|
|
||||||
if result.is_empty() {
|
|
||||||
let last_span = self.last_span;
|
|
||||||
self.span_err(last_span,
|
|
||||||
"nullary enum variants are written with no trailing `( )`");
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB: Do not use this function unless you actually plan to place the
|
// NB: Do not use this function unless you actually plan to place the
|
||||||
// spanned list in the AST.
|
// spanned list in the AST.
|
||||||
pub fn parse_seq<T, F>(&mut self,
|
pub fn parse_seq<T, F>(&mut self,
|
||||||
|
@ -3433,21 +3414,29 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec<P<Pat>>> {
|
fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool)
|
||||||
|
-> PResult<'a, (Vec<P<Pat>>, Option<usize>)> {
|
||||||
let mut fields = vec![];
|
let mut fields = vec![];
|
||||||
if !self.check(&token::CloseDelim(token::Paren)) {
|
let mut ddpos = None;
|
||||||
fields.push(self.parse_pat()?);
|
|
||||||
if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) {
|
while !self.check(&token::CloseDelim(token::Paren)) {
|
||||||
while self.eat(&token::Comma) &&
|
if ddpos.is_none() && self.eat(&token::DotDot) {
|
||||||
!self.check(&token::CloseDelim(token::Paren)) {
|
ddpos = Some(fields.len());
|
||||||
|
if self.eat(&token::Comma) {
|
||||||
|
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
|
||||||
fields.push(self.parse_pat()?);
|
fields.push(self.parse_pat()?);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fields.push(self.parse_pat()?);
|
||||||
}
|
}
|
||||||
if fields.len() == 1 {
|
|
||||||
|
if !self.check(&token::CloseDelim(token::Paren)) ||
|
||||||
|
(unary_needs_comma && fields.len() == 1 && ddpos.is_none()) {
|
||||||
self.expect(&token::Comma)?;
|
self.expect(&token::Comma)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(fields)
|
|
||||||
|
Ok((fields, ddpos))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pat_vec_elements(
|
fn parse_pat_vec_elements(
|
||||||
|
@ -3626,9 +3615,9 @@ impl<'a> Parser<'a> {
|
||||||
token::OpenDelim(token::Paren) => {
|
token::OpenDelim(token::Paren) => {
|
||||||
// Parse (pat,pat,pat,...) as tuple pattern
|
// Parse (pat,pat,pat,...) as tuple pattern
|
||||||
self.bump();
|
self.bump();
|
||||||
let fields = self.parse_pat_tuple_elements()?;
|
let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
pat = PatKind::Tup(fields);
|
pat = PatKind::Tuple(fields, ddpos);
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Bracket) => {
|
token::OpenDelim(token::Bracket) => {
|
||||||
// Parse [pat,pat,...] as slice pattern
|
// Parse [pat,pat,...] as slice pattern
|
||||||
|
@ -3713,20 +3702,10 @@ impl<'a> Parser<'a> {
|
||||||
return Err(self.fatal("unexpected `(` after qualified path"));
|
return Err(self.fatal("unexpected `(` after qualified path"));
|
||||||
}
|
}
|
||||||
// Parse tuple struct or enum pattern
|
// Parse tuple struct or enum pattern
|
||||||
if self.look_ahead(1, |t| *t == token::DotDot) {
|
|
||||||
// This is a "top constructor only" pat
|
|
||||||
self.bump();
|
|
||||||
self.bump();
|
self.bump();
|
||||||
|
let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
pat = PatKind::TupleStruct(path, None);
|
pat = PatKind::TupleStruct(path, fields, ddpos)
|
||||||
} else {
|
|
||||||
let args = self.parse_enum_variant_seq(
|
|
||||||
&token::OpenDelim(token::Paren),
|
|
||||||
&token::CloseDelim(token::Paren),
|
|
||||||
SeqSep::trailing_allowed(token::Comma),
|
|
||||||
|p| p.parse_pat())?;
|
|
||||||
pat = PatKind::TupleStruct(path, Some(args));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
pat = match qself {
|
pat = match qself {
|
||||||
|
|
|
@ -2472,18 +2472,24 @@ impl<'a> State<'a> {
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref path, ref args_) => {
|
PatKind::TupleStruct(ref path, ref elts, ddpos) => {
|
||||||
self.print_path(path, true, 0)?;
|
self.print_path(path, true, 0)?;
|
||||||
match *args_ {
|
|
||||||
None => word(&mut self.s, "(..)")?,
|
|
||||||
Some(ref args) => {
|
|
||||||
self.popen()?;
|
self.popen()?;
|
||||||
self.commasep(Inconsistent, &args[..],
|
if let Some(ddpos) = ddpos {
|
||||||
|s, p| s.print_pat(&p))?;
|
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
|
||||||
|
if ddpos != 0 {
|
||||||
|
self.word_space(",")?;
|
||||||
|
}
|
||||||
|
word(&mut self.s, "..")?;
|
||||||
|
if ddpos != elts.len() {
|
||||||
|
word(&mut self.s, ",")?;
|
||||||
|
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
|
||||||
|
}
|
||||||
self.pclose()?;
|
self.pclose()?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
PatKind::Path(ref path) => {
|
PatKind::Path(ref path) => {
|
||||||
self.print_path(path, true, 0)?;
|
self.print_path(path, true, 0)?;
|
||||||
}
|
}
|
||||||
|
@ -2513,14 +2519,24 @@ impl<'a> State<'a> {
|
||||||
space(&mut self.s)?;
|
space(&mut self.s)?;
|
||||||
word(&mut self.s, "}")?;
|
word(&mut self.s, "}")?;
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref elts) => {
|
PatKind::Tuple(ref elts, ddpos) => {
|
||||||
self.popen()?;
|
self.popen()?;
|
||||||
self.commasep(Inconsistent,
|
if let Some(ddpos) = ddpos {
|
||||||
&elts[..],
|
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
|
||||||
|s, p| s.print_pat(&p))?;
|
if ddpos != 0 {
|
||||||
|
self.word_space(",")?;
|
||||||
|
}
|
||||||
|
word(&mut self.s, "..")?;
|
||||||
|
if ddpos != elts.len() {
|
||||||
|
word(&mut self.s, ",")?;
|
||||||
|
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
|
||||||
if elts.len() == 1 {
|
if elts.len() == 1 {
|
||||||
word(&mut self.s, ",")?;
|
word(&mut self.s, ",")?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.pclose()?;
|
self.pclose()?;
|
||||||
}
|
}
|
||||||
PatKind::Box(ref inner) => {
|
PatKind::Box(ref inner) => {
|
||||||
|
|
|
@ -423,12 +423,10 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||||
|
|
||||||
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||||
match pattern.node {
|
match pattern.node {
|
||||||
PatKind::TupleStruct(ref path, ref opt_children) => {
|
PatKind::TupleStruct(ref path, ref children, _) => {
|
||||||
visitor.visit_path(path, pattern.id);
|
visitor.visit_path(path, pattern.id);
|
||||||
if let Some(ref children) = *opt_children {
|
|
||||||
walk_list!(visitor, visit_pat, children);
|
walk_list!(visitor, visit_pat, children);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
PatKind::Path(ref path) => {
|
PatKind::Path(ref path) => {
|
||||||
visitor.visit_path(path, pattern.id);
|
visitor.visit_path(path, pattern.id);
|
||||||
}
|
}
|
||||||
|
@ -443,7 +441,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||||
visitor.visit_pat(&field.node.pat)
|
visitor.visit_pat(&field.node.pat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Tup(ref tuple_elements) => {
|
PatKind::Tuple(ref tuple_elements, _) => {
|
||||||
walk_list!(visitor, visit_pat, tuple_elements);
|
walk_list!(visitor, visit_pat, tuple_elements);
|
||||||
}
|
}
|
||||||
PatKind::Box(ref subpattern) |
|
PatKind::Box(ref subpattern) |
|
||||||
|
|
|
@ -18,12 +18,12 @@ struct S;
|
||||||
fn main() {
|
fn main() {
|
||||||
match Foo::Baz {
|
match Foo::Baz {
|
||||||
Foo::Bar => {}
|
Foo::Bar => {}
|
||||||
//~^ ERROR this pattern has 0 fields, but the corresponding variant
|
//~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match S {
|
match S {
|
||||||
S(()) => {}
|
S(()) => {}
|
||||||
//~^ ERROR this pattern has 1 field, but the corresponding struct
|
//~^ ERROR `S` does not name a tuple variant or a tuple struct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ fn main() {
|
||||||
color::rgb(_, _, _) => { }
|
color::rgb(_, _, _) => { }
|
||||||
color::cmyk(_, _, _, _) => { }
|
color::cmyk(_, _, _, _) => { }
|
||||||
color::no_color(_) => { }
|
color::no_color(_) => { }
|
||||||
//~^ ERROR this pattern has 1 field, but the corresponding variant has no fields
|
//~^ ERROR `color::no_color` does not name a tuple variant or a tuple struct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
src/test/compile-fail/pat-tuple-bad-type.rs
Normal file
27
src/test/compile-fail/pat-tuple-bad-type.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2016 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(dotdot_in_tuple_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x;
|
||||||
|
|
||||||
|
match x {
|
||||||
|
(..) => {} //~ ERROR the type of this value must be known in this context
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match 0u8 {
|
||||||
|
(..) => {} //~ ERROR mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
x = 10;
|
||||||
|
}
|
17
src/test/compile-fail/pat-tuple-feature-gate.rs
Normal file
17
src/test/compile-fail/pat-tuple-feature-gate.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2016 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() {
|
||||||
|
match 0 {
|
||||||
|
(..) => {} //~ ERROR `..` in tuple patterns is experimental
|
||||||
|
(pat, ..) => {} //~ ERROR `..` in tuple patterns is experimental
|
||||||
|
S(pat, ..) => {} //~ ERROR `..` in tuple struct patterns is experimental
|
||||||
|
}
|
||||||
|
}
|
28
src/test/compile-fail/pat-tuple-overfield.rs
Normal file
28
src/test/compile-fail/pat-tuple-overfield.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2016 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(dotdot_in_tuple_patterns)]
|
||||||
|
|
||||||
|
struct S(u8, u8, u8);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match (1, 2, 3) {
|
||||||
|
(1, 2, 3, 4) => {} //~ ERROR mismatched types
|
||||||
|
(1, 2, .., 3, 4) => {} //~ ERROR mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match S(1, 2, 3) {
|
||||||
|
S(1, 2, 3, 4) => {}
|
||||||
|
//~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields
|
||||||
|
S(1, 2, .., 3, 4) => {}
|
||||||
|
//~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ fn f(_c: char) {}
|
||||||
fn main() {
|
fn main() {
|
||||||
match A::B(1, 2) {
|
match A::B(1, 2) {
|
||||||
A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
|
A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
|
||||||
A::D(_) => (), //~ ERROR this pattern has 1 field, but
|
A::D(_) => (), //~ ERROR `A::D` does not name a tuple variant or a tuple struct
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
match 'c' {
|
match 'c' {
|
||||||
|
|
|
@ -9,6 +9,5 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let Test(&desc[..]) = x; //~ error: expected one of `,` or `@`, found `[`
|
let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
|
||||||
//~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `[`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,5 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for thing(x[]) in foo {} //~ error: expected one of `,` or `@`, found `[`
|
for thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
|
||||||
//~^ ERROR expected one of `@` or `in`, found `[`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
enum Number {
|
// compile-flags: -Z parse-only
|
||||||
Zero,
|
|
||||||
One(u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = Number::Zero;
|
match 0 {
|
||||||
match x {
|
(, ..) => {} //~ ERROR expected pattern, found `,`
|
||||||
Number::Zero(inside) => {}, //~ ERROR E0024
|
|
||||||
Number::One(inside) => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
17
src/test/parse-fail/pat-tuple-2.rs
Normal file
17
src/test/parse-fail/pat-tuple-2.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
(pat, ..,) => {} //~ ERROR expected pattern, found `)`
|
||||||
|
}
|
||||||
|
}
|
17
src/test/parse-fail/pat-tuple-3.rs
Normal file
17
src/test/parse-fail/pat-tuple-3.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
(.., pat, ..) => {} //~ ERROR expected pattern, found `..`
|
||||||
|
}
|
||||||
|
}
|
17
src/test/parse-fail/pat-tuple-4.rs
Normal file
17
src/test/parse-fail/pat-tuple-4.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
(.. pat) => {} //~ ERROR expected one of `)` or `,`, found `pat`
|
||||||
|
}
|
||||||
|
}
|
17
src/test/parse-fail/pat-tuple-5.rs
Normal file
17
src/test/parse-fail/pat-tuple-5.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
(pat ..) => {} //~ ERROR expected one of `)`, `,`, or `@`, found `..`
|
||||||
|
}
|
||||||
|
}
|
17
src/test/parse-fail/pat-tuple-6.rs
Normal file
17
src/test/parse-fail/pat-tuple-6.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
(pat) => {} //~ ERROR expected one of `,` or `@`, found `)`
|
||||||
|
}
|
||||||
|
}
|
202
src/test/run-pass/pat-tuple.rs
Normal file
202
src/test/run-pass/pat-tuple.rs
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
// Copyright 2016 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(dotdot_in_tuple_patterns)]
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
let x = (1, 2, 3);
|
||||||
|
match x {
|
||||||
|
(a, b, ..) => {
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
assert_eq!(b, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
(.., b, c) => {
|
||||||
|
assert_eq!(b, 2);
|
||||||
|
assert_eq!(c, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
(a, .., c) => {
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
assert_eq!(c, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
(a, b, c) => {
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
assert_eq!(b, 2);
|
||||||
|
assert_eq!(c, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bs() {
|
||||||
|
struct S(u8, u8, u8);
|
||||||
|
|
||||||
|
let x = S(1, 2, 3);
|
||||||
|
match x {
|
||||||
|
S(a, b, ..) => {
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
assert_eq!(b, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
S(.., b, c) => {
|
||||||
|
assert_eq!(b, 2);
|
||||||
|
assert_eq!(c, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
S(a, .., c) => {
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
assert_eq!(c, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
S(a, b, c) => {
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
assert_eq!(b, 2);
|
||||||
|
assert_eq!(c, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() {
|
||||||
|
let x = (1,);
|
||||||
|
match x {
|
||||||
|
(2, ..) => panic!(),
|
||||||
|
(..) => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cs() {
|
||||||
|
struct S(u8);
|
||||||
|
|
||||||
|
let x = S(1);
|
||||||
|
match x {
|
||||||
|
S(2, ..) => panic!(),
|
||||||
|
S(..) => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn d() {
|
||||||
|
let x = (1, 2, 3);
|
||||||
|
let branch = match x {
|
||||||
|
(1, 1, ..) => 0,
|
||||||
|
(1, 2, 3, ..) => 1,
|
||||||
|
(1, 2, ..) => 2,
|
||||||
|
_ => 3
|
||||||
|
};
|
||||||
|
assert_eq!(branch, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ds() {
|
||||||
|
struct S(u8, u8, u8);
|
||||||
|
|
||||||
|
let x = S(1, 2, 3);
|
||||||
|
let branch = match x {
|
||||||
|
S(1, 1, ..) => 0,
|
||||||
|
S(1, 2, 3, ..) => 1,
|
||||||
|
S(1, 2, ..) => 2,
|
||||||
|
_ => 3
|
||||||
|
};
|
||||||
|
assert_eq!(branch, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
let x = (1, 2, 3);
|
||||||
|
match x {
|
||||||
|
(1, 2, 4) => unreachable!(),
|
||||||
|
(0, 2, 3, ..) => unreachable!(),
|
||||||
|
(0, .., 3) => unreachable!(),
|
||||||
|
(0, ..) => unreachable!(),
|
||||||
|
(1, 2, 3) => (),
|
||||||
|
(_, _, _) => unreachable!(),
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
(..) => (),
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
(_, _, _, ..) => (),
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
(a, b, c) => {
|
||||||
|
assert_eq!(1, a);
|
||||||
|
assert_eq!(2, b);
|
||||||
|
assert_eq!(3, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fs() {
|
||||||
|
struct S(u8, u8, u8);
|
||||||
|
|
||||||
|
let x = S(1, 2, 3);
|
||||||
|
match x {
|
||||||
|
S(1, 2, 4) => unreachable!(),
|
||||||
|
S(0, 2, 3, ..) => unreachable!(),
|
||||||
|
S(0, .., 3) => unreachable!(),
|
||||||
|
S(0, ..) => unreachable!(),
|
||||||
|
S(1, 2, 3) => (),
|
||||||
|
S(_, _, _) => unreachable!(),
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
S(..) => (),
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
S(_, _, _, ..) => (),
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
S(a, b, c) => {
|
||||||
|
assert_eq!(1, a);
|
||||||
|
assert_eq!(2, b);
|
||||||
|
assert_eq!(3, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g() {
|
||||||
|
struct S;
|
||||||
|
struct Z;
|
||||||
|
struct W;
|
||||||
|
let x = (S, Z, W);
|
||||||
|
match x { (S, ..) => {} }
|
||||||
|
match x { (.., W) => {} }
|
||||||
|
match x { (S, .., W) => {} }
|
||||||
|
match x { (.., Z, _) => {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gs() {
|
||||||
|
struct SS(S, Z, W);
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
struct Z;
|
||||||
|
struct W;
|
||||||
|
let x = SS(S, Z, W);
|
||||||
|
match x { SS(S, ..) => {} }
|
||||||
|
match x { SS(.., W) => {} }
|
||||||
|
match x { SS(S, .., W) => {} }
|
||||||
|
match x { SS(.., Z, _) => {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
b();
|
||||||
|
bs();
|
||||||
|
c();
|
||||||
|
cs();
|
||||||
|
d();
|
||||||
|
ds();
|
||||||
|
f();
|
||||||
|
fs();
|
||||||
|
g();
|
||||||
|
gs();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue