Skip to content

Commit

Permalink
Rollup merge of rust-lang#33639 - petrochenkov:dotdot, r=nmatsakis
Browse files Browse the repository at this point in the history
 cc rust-lang#33627
r? @nikomatsakis

plugin-[breaking-change] cc rust-lang#31645 @Manishearth
  • Loading branch information
Manishearth committed May 26, 2016
2 parents 1c9c002 + a7b1ab5 commit 170c438
Show file tree
Hide file tree
Showing 50 changed files with 874 additions and 298 deletions.
2 changes: 2 additions & 0 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2433,6 +2433,8 @@ The currently implemented features of the reference compiler are:
* - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
(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
start to receive compilation warnings about `#![feature]` directives which enabled
the new feature (because the directive is no longer necessary). However, if a
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
match pat.node {
PatKind::Ident(_, _, None) |
PatKind::TupleStruct(_, None) |
PatKind::Path(..) |
PatKind::QPath(..) |
PatKind::Lit(..) |
Expand All @@ -116,8 +115,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.add_ast_node(pat.id, &[subpat_exit])
}

PatKind::TupleStruct(_, Some(ref subpats)) |
PatKind::Tup(ref subpats) => {
PatKind::TupleStruct(_, ref subpats, _) |
PatKind::Tuple(ref subpats, _) => {
let pats_exit = self.pats_all(subpats.iter(), pred);
self.add_ast_node(pat.id, &[pats_exit])
}
Expand Down
8 changes: 5 additions & 3 deletions src/librustc/hir/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
PatKind::TupleStruct(pth, pats) => {
PatKind::TupleStruct(pth, pats, ddpos) => {
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(folder.fold_path(pth))
Expand All @@ -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::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::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
PatKind::Range(e1, e2) => {
Expand Down
8 changes: 3 additions & 5 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,9 @@ 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) {
match pattern.node {
PatKind::TupleStruct(ref path, ref opt_children) => {
PatKind::TupleStruct(ref path, ref children, _) => {
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) => {
visitor.visit_path(path, pattern.id);
Expand All @@ -480,7 +478,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
visitor.visit_pat(&field.node.pat)
}
}
PatKind::Tup(ref tuple_elements) => {
PatKind::Tuple(ref tuple_elements, _) => {
walk_list!(visitor, visit_pat, tuple_elements);
}
PatKind::Box(ref subpattern) |
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,10 +876,10 @@ impl<'a> LoweringContext<'a> {
})
}
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),
pats.as_ref()
.map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect()))
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos)
}
PatKind::Path(ref pth) => {
hir::PatKind::Path(self.lower_path(pth))
Expand Down Expand Up @@ -907,8 +907,8 @@ impl<'a> LoweringContext<'a> {
.collect();
hir::PatKind::Struct(pth, fs, etc)
}
PatKind::Tup(ref elts) => {
hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect())
PatKind::Tuple(ref elts, ddpos) => {
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::Ref(ref inner, mutbl) => {
Expand Down Expand Up @@ -1854,7 +1854,7 @@ impl<'a> LoweringContext<'a> {
let pt = if subpats.is_empty() {
hir::PatKind::Path(path)
} else {
hir::PatKind::TupleStruct(path, Some(subpats))
hir::PatKind::TupleStruct(path, subpats, None)
};
let pat = self.pat(span, pt);
self.resolver.record_resolution(pat.id, def);
Expand Down
16 changes: 9 additions & 7 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ impl Pat {
PatKind::Struct(_, ref fields, _) => {
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))
}
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
Expand All @@ -485,7 +485,6 @@ impl Pat {
PatKind::Lit(_) |
PatKind::Range(_, _) |
PatKind::Ident(_, _, _) |
PatKind::TupleStruct(..) |
PatKind::Path(..) |
PatKind::QPath(_, _) => {
true
Expand Down Expand Up @@ -539,9 +538,10 @@ pub enum PatKind {
/// The `bool` is `true` in the presence of a `..`.
Struct(Path, HirVec<Spanned<FieldPat>>, bool),

/// A tuple struct/variant pattern `Variant(x, y, z)`.
/// "None" means a `Variant(..)` pattern where we don't bind the fields to names.
TupleStruct(Path, Option<HirVec<P<Pat>>>),
/// A tuple struct/variant pattern `Variant(x, y, .., z)`.
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
/// 0 <= position <= subpats.len()
TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),

/// A path pattern.
/// Such pattern can be resolved to a unit struct/variant or a constant.
Expand All @@ -553,8 +553,10 @@ pub enum PatKind {
/// PatKind::Path, and the resolver will have to sort that out.
QPath(QSelf, Path),

/// A tuple pattern `(a, b)`
Tup(HirVec<P<Pat>>),
/// A tuple pattern `(a, b)`.
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
/// 0 <= position <= subpats.len()
Tuple(HirVec<P<Pat>>, Option<usize>),
/// A `box` pattern
Box(P<Pat>),
/// A reference pattern, e.g. `&mut (a, b)`
Expand Down
34 changes: 34 additions & 0 deletions src/librustc/hir/pat_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,43 @@ use hir::{self, PatKind};
use syntax::codemap::{respan, Span, Spanned, DUMMY_SP};

use std::cell::RefCell;
use std::iter::{Enumerate, ExactSizeIterator};

pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;

pub struct EnumerateAndAdjust<I> {
enumerate: Enumerate<I>,
gap_pos: usize,
gap_len: usize,
}

impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
type Item = (usize, <I as Iterator>::Item);

fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
self.enumerate.next().map(|(i, elem)| {
(if i < self.gap_pos { i } else { i + self.gap_len }, elem)
})
}
}

pub trait EnumerateAndAdjustIterator {
fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
-> EnumerateAndAdjust<Self> where Self: Sized;
}

impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
-> EnumerateAndAdjust<Self> where Self: Sized {
let actual_len = self.len();
EnumerateAndAdjust {
enumerate: self.enumerate(),
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
// use the NodeId of their namesake in the first pattern.
pub fn pat_id_map(dm: &RefCell<DefMap>, pat: &hir::Pat) -> PatIdMap {
Expand Down
41 changes: 30 additions & 11 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1736,16 +1736,23 @@ impl<'a> State<'a> {
None => (),
}
}
PatKind::TupleStruct(ref path, ref args_) => {
PatKind::TupleStruct(ref path, ref elts, ddpos) => {
self.print_path(path, true, 0)?;
match *args_ {
None => word(&mut self.s, "(..)")?,
Some(ref args) => {
self.popen()?;
self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?;
self.pclose()?;
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 {
try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
}
try!(self.pclose());
}
PatKind::Path(ref path) => {
self.print_path(path, true, 0)?;
Expand Down Expand Up @@ -1778,11 +1785,23 @@ impl<'a> State<'a> {
space(&mut self.s)?;
word(&mut self.s, "}")?;
}
PatKind::Tup(ref elts) => {
PatKind::Tuple(ref elts, ddpos) => {
self.popen()?;
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
if elts.len() == 1 {
word(&mut self.s, ",")?;
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))?;
if elts.len() == 1 {
word(&mut self.s, ",")?;
}
}
self.pclose()?;
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
// will visit the substructure recursively.
}

PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) |
PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) |
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
PatKind::Vec(..) => {
// Similarly, each of these cases does not
Expand Down
31 changes: 22 additions & 9 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use ty::adjustment;
use ty::{self, Ty, TyCtxt};

use hir::{MutImmutable, MutMutable, PatKind};
use hir::pat_util::EnumerateAndAdjustIterator;
use hir;
use syntax::ast;
use syntax::codemap::Span;
Expand Down Expand Up @@ -1225,14 +1226,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// _
}

PatKind::TupleStruct(_, None) => {
// variant(..)
}
PatKind::TupleStruct(_, Some(ref subpats)) => {
PatKind::TupleStruct(_, ref subpats, ddpos) => {
match opt_def {
Some(Def::Variant(..)) => {
Some(Def::Variant(enum_def, def_id)) => {
// variant(x, y, z)
for (i, subpat) in subpats.iter().enumerate() {
let expected_len = self.tcx().lookup_adt_def(enum_def)
.variant_with_id(def_id).fields.len();
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)

let subcmt =
Expand All @@ -1244,7 +1244,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
}
}
Some(Def::Struct(..)) => {
for (i, subpat) in subpats.iter().enumerate() {
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);
}
};

for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
let cmt_field =
self.cat_imm_interior(
Expand Down Expand Up @@ -1284,9 +1293,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
}
}

PatKind::Tup(ref subpats) => {
PatKind::Tuple(ref subpats, ddpos) => {
// (p1, ..., pN)
for (i, subpat) in subpats.iter().enumerate() {
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),
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
let subcmt =
self.cat_imm_interior(
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -970,8 +970,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
pats3.iter().any(|p| is_binding_pat(&p))
}

PatKind::TupleStruct(_, Some(ref subpats)) |
PatKind::Tup(ref subpats) => {
PatKind::TupleStruct(_, ref subpats, _) |
PatKind::Tuple(ref subpats, _) => {
subpats.iter().any(|p| is_binding_pat(&p))
}

Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
use hir;
use hir::{Item, Generics, StructField, Variant, PatKind};
use hir::intravisit::{self, Visitor};
use hir::pat_util::EnumerateAndAdjustIterator;

use std::mem::replace;
use std::cmp::Ordering;
Expand Down Expand Up @@ -614,10 +615,9 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
};
match pat.node {
// Foo(a, b, c)
// A Variant(..) pattern `PatKind::TupleStruct(_, None)` doesn't have to be recursed into.
PatKind::TupleStruct(_, Some(ref pat_fields)) => {
for (field, struct_field) in pat_fields.iter().zip(&v.fields) {
maybe_do_stability_check(tcx, struct_field.did, field.span, cb)
PatKind::TupleStruct(_, ref pat_fields, ddpos) => {
for (i, field) in pat_fields.iter().enumerate_and_adjust(v.fields.len(), ddpos) {
maybe_do_stability_check(tcx, v.fields[i].did, field.span, cb)
}
}
// Foo { a, b, c }
Expand Down
Loading

0 comments on commit 170c438

Please sign in to comment.