Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement .. in tuple (struct) patterns (RFC 1492) #33639

Merged
merged 4 commits into from
May 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -454,11 +454,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 @@ -474,7 +472,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 @@ -872,10 +872,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 @@ -903,8 +903,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 @@ -1857,7 +1857,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