Skip to content

Commit d912f90

Browse files
committed
Implement .. in tuple (struct) patterns
1 parent 5229e0e commit d912f90

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+736
-299
lines changed

src/doc/reference.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,6 +2433,8 @@ The currently implemented features of the reference compiler are:
24332433
* - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
24342434
(e.g. `extern "vectorcall" func fn_();`)
24352435

2436+
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
2437+
24362438
If a feature is promoted to a language feature, then all existing programs will
24372439
start to receive compilation warnings about `#![feature]` directives which enabled
24382440
the new feature (because the directive is no longer necessary). However, if a

src/librustc/cfg/construct.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
100100
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
101101
match pat.node {
102102
PatKind::Ident(_, _, None) |
103-
PatKind::TupleStruct(_, None) |
104103
PatKind::Path(..) |
105104
PatKind::QPath(..) |
106105
PatKind::Lit(..) |
@@ -116,8 +115,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
116115
self.add_ast_node(pat.id, &[subpat_exit])
117116
}
118117

119-
PatKind::TupleStruct(_, Some(ref subpats)) |
120-
PatKind::Tup(ref subpats) => {
118+
PatKind::TupleStruct(_, ref subpats, _) |
119+
PatKind::Tuple(ref subpats, _) => {
121120
let pats_exit = self.pats_all(subpats.iter(), pred);
122121
self.add_ast_node(pat.id, &[pats_exit])
123122
}

src/librustc/hir/fold.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -923,9 +923,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
923923
sub.map(|x| folder.fold_pat(x)))
924924
}
925925
PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
926-
PatKind::TupleStruct(pth, pats) => {
926+
PatKind::TupleStruct(pth, pats, ddpos) => {
927927
PatKind::TupleStruct(folder.fold_path(pth),
928-
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
928+
pats.move_map(|x| folder.fold_pat(x)), ddpos)
929929
}
930930
PatKind::Path(pth) => {
931931
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> {
948948
});
949949
PatKind::Struct(pth, fs, etc)
950950
}
951-
PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))),
951+
PatKind::Tuple(elts, ddpos) => {
952+
PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos)
953+
}
952954
PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
953955
PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
954956
PatKind::Range(e1, e2) => {

src/librustc/hir/intravisit.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -454,11 +454,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
454454

455455
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
456456
match pattern.node {
457-
PatKind::TupleStruct(ref path, ref opt_children) => {
457+
PatKind::TupleStruct(ref path, ref children, _) => {
458458
visitor.visit_path(path, pattern.id);
459-
if let Some(ref children) = *opt_children {
460-
walk_list!(visitor, visit_pat, children);
461-
}
459+
walk_list!(visitor, visit_pat, children);
462460
}
463461
PatKind::Path(ref path) => {
464462
visitor.visit_path(path, pattern.id);
@@ -474,7 +472,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
474472
visitor.visit_pat(&field.node.pat)
475473
}
476474
}
477-
PatKind::Tup(ref tuple_elements) => {
475+
PatKind::Tuple(ref tuple_elements, _) => {
478476
walk_list!(visitor, visit_pat, tuple_elements);
479477
}
480478
PatKind::Box(ref subpattern) |

src/librustc/hir/lowering.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -872,10 +872,10 @@ impl<'a> LoweringContext<'a> {
872872
})
873873
}
874874
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
875-
PatKind::TupleStruct(ref pth, ref pats) => {
875+
PatKind::TupleStruct(ref pth, ref pats, ddpos) => {
876876
hir::PatKind::TupleStruct(self.lower_path(pth),
877-
pats.as_ref()
878-
.map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect()))
877+
pats.iter().map(|x| self.lower_pat(x)).collect(),
878+
ddpos)
879879
}
880880
PatKind::Path(ref pth) => {
881881
hir::PatKind::Path(self.lower_path(pth))
@@ -903,8 +903,8 @@ impl<'a> LoweringContext<'a> {
903903
.collect();
904904
hir::PatKind::Struct(pth, fs, etc)
905905
}
906-
PatKind::Tup(ref elts) => {
907-
hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect())
906+
PatKind::Tuple(ref elts, ddpos) => {
907+
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
908908
}
909909
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
910910
PatKind::Ref(ref inner, mutbl) => {
@@ -1857,7 +1857,7 @@ impl<'a> LoweringContext<'a> {
18571857
let pt = if subpats.is_empty() {
18581858
hir::PatKind::Path(path)
18591859
} else {
1860-
hir::PatKind::TupleStruct(path, Some(subpats))
1860+
hir::PatKind::TupleStruct(path, subpats, None)
18611861
};
18621862
let pat = self.pat(span, pt);
18631863
self.resolver.record_resolution(pat.id, def);

src/librustc/hir/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ impl Pat {
470470
PatKind::Struct(_, ref fields, _) => {
471471
fields.iter().all(|field| field.node.pat.walk_(it))
472472
}
473-
PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => {
473+
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
474474
s.iter().all(|p| p.walk_(it))
475475
}
476476
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
@@ -485,7 +485,6 @@ impl Pat {
485485
PatKind::Lit(_) |
486486
PatKind::Range(_, _) |
487487
PatKind::Ident(_, _, _) |
488-
PatKind::TupleStruct(..) |
489488
PatKind::Path(..) |
490489
PatKind::QPath(_, _) => {
491490
true
@@ -539,9 +538,10 @@ pub enum PatKind {
539538
/// The `bool` is `true` in the presence of a `..`.
540539
Struct(Path, HirVec<Spanned<FieldPat>>, bool),
541540

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

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

556-
/// A tuple pattern `(a, b)`
557-
Tup(HirVec<P<Pat>>),
556+
/// A tuple pattern `(a, b)`.
557+
/// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
558+
/// 0 <= position <= subpats.len()
559+
Tuple(HirVec<P<Pat>>, Option<usize>),
558560
/// A `box` pattern
559561
Box(P<Pat>),
560562
/// A reference pattern, e.g. `&mut (a, b)`

src/librustc/hir/pat_util.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,28 @@ use std::cell::RefCell;
2121

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

24+
#[derive(Clone, Copy)]
25+
pub struct AjustPos {
26+
gap_pos: usize,
27+
gap_len: usize,
28+
}
29+
30+
impl FnOnce<(usize,)> for AjustPos {
31+
type Output = usize;
32+
extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize {
33+
if i < self.gap_pos { i } else { i + self.gap_len }
34+
}
35+
}
36+
37+
// Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and
38+
// pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2).
39+
pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option<usize>) -> AjustPos {
40+
AjustPos {
41+
gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len },
42+
gap_len: expected_len - actual_len,
43+
}
44+
}
45+
2446
// This is used because same-named variables in alternative patterns need to
2547
// use the NodeId of their namesake in the first pattern.
2648
pub fn pat_id_map(dm: &RefCell<DefMap>, pat: &hir::Pat) -> PatIdMap {

src/librustc/hir/print.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,16 +1736,23 @@ impl<'a> State<'a> {
17361736
None => (),
17371737
}
17381738
}
1739-
PatKind::TupleStruct(ref path, ref args_) => {
1739+
PatKind::TupleStruct(ref path, ref elts, ddpos) => {
17401740
self.print_path(path, true, 0)?;
1741-
match *args_ {
1742-
None => word(&mut self.s, "(..)")?,
1743-
Some(ref args) => {
1744-
self.popen()?;
1745-
self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?;
1746-
self.pclose()?;
1741+
self.popen()?;
1742+
if let Some(ddpos) = ddpos {
1743+
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
1744+
if ddpos != 0 {
1745+
self.word_space(",")?;
1746+
}
1747+
word(&mut self.s, "..")?;
1748+
if ddpos != elts.len() {
1749+
word(&mut self.s, ",")?;
1750+
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
17471751
}
1752+
} else {
1753+
try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
17481754
}
1755+
try!(self.pclose());
17491756
}
17501757
PatKind::Path(ref path) => {
17511758
self.print_path(path, true, 0)?;
@@ -1778,11 +1785,23 @@ impl<'a> State<'a> {
17781785
space(&mut self.s)?;
17791786
word(&mut self.s, "}")?;
17801787
}
1781-
PatKind::Tup(ref elts) => {
1788+
PatKind::Tuple(ref elts, ddpos) => {
17821789
self.popen()?;
1783-
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
1784-
if elts.len() == 1 {
1785-
word(&mut self.s, ",")?;
1790+
if let Some(ddpos) = ddpos {
1791+
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
1792+
if ddpos != 0 {
1793+
self.word_space(",")?;
1794+
}
1795+
word(&mut self.s, "..")?;
1796+
if ddpos != elts.len() {
1797+
word(&mut self.s, ",")?;
1798+
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
1799+
}
1800+
} else {
1801+
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
1802+
if elts.len() == 1 {
1803+
word(&mut self.s, ",")?;
1804+
}
17861805
}
17871806
self.pclose()?;
17881807
}

src/librustc/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#![feature(collections)]
3030
#![feature(const_fn)]
3131
#![feature(enumset)]
32+
#![feature(fn_traits)]
3233
#![feature(iter_arith)]
3334
#![feature(libc)]
3435
#![feature(nonzero)]
@@ -38,6 +39,7 @@
3839
#![feature(slice_patterns)]
3940
#![feature(staged_api)]
4041
#![feature(question_mark)]
42+
#![feature(unboxed_closures)]
4143
#![cfg_attr(test, feature(test))]
4244

4345
extern crate arena;

src/librustc/middle/expr_use_visitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
11271127
// will visit the substructure recursively.
11281128
}
11291129

1130-
PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) |
1130+
PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) |
11311131
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
11321132
PatKind::Vec(..) => {
11331133
// Similarly, each of these cases does not

src/librustc/middle/mem_categorization.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ use ty::adjustment;
8080
use ty::{self, Ty, TyCtxt};
8181

8282
use hir::{MutImmutable, MutMutable, PatKind};
83+
use hir::pat_util::pat_adjust_pos;
8384
use hir;
8485
use syntax::ast;
8586
use syntax::codemap::Span;
@@ -1225,31 +1226,40 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12251226
// _
12261227
}
12271228

1228-
PatKind::TupleStruct(_, None) => {
1229-
// variant(..)
1230-
}
1231-
PatKind::TupleStruct(_, Some(ref subpats)) => {
1229+
PatKind::TupleStruct(_, ref subpats, ddpos) => {
12321230
match opt_def {
1233-
Some(Def::Variant(..)) => {
1231+
Some(Def::Variant(enum_def, def_id)) => {
12341232
// variant(x, y, z)
1233+
let variant = self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id);
1234+
let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos);
12351235
for (i, subpat) in subpats.iter().enumerate() {
12361236
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
12371237

12381238
let subcmt =
12391239
self.cat_imm_interior(
12401240
pat, cmt.clone(), subpat_ty,
1241-
InteriorField(PositionalField(i)));
1241+
InteriorField(PositionalField(adjust(i))));
12421242

12431243
self.cat_pattern_(subcmt, &subpat, op)?;
12441244
}
12451245
}
12461246
Some(Def::Struct(..)) => {
1247+
let expected_len = match self.pat_ty(&pat) {
1248+
Ok(&ty::TyS{sty: ty::TyStruct(adt_def, _), ..}) => {
1249+
adt_def.struct_variant().fields.len()
1250+
}
1251+
ref ty => {
1252+
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
1253+
}
1254+
};
1255+
1256+
let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos);
12471257
for (i, subpat) in subpats.iter().enumerate() {
12481258
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
12491259
let cmt_field =
12501260
self.cat_imm_interior(
12511261
pat, cmt.clone(), subpat_ty,
1252-
InteriorField(PositionalField(i)));
1262+
InteriorField(PositionalField(adjust(i))));
12531263
self.cat_pattern_(cmt_field, &subpat, op)?;
12541264
}
12551265
}
@@ -1284,14 +1294,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12841294
}
12851295
}
12861296

1287-
PatKind::Tup(ref subpats) => {
1297+
PatKind::Tuple(ref subpats, ddpos) => {
12881298
// (p1, ..., pN)
1299+
let expected_len = match self.pat_ty(&pat) {
1300+
Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(),
1301+
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
1302+
};
1303+
let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos);
12891304
for (i, subpat) in subpats.iter().enumerate() {
12901305
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
12911306
let subcmt =
12921307
self.cat_imm_interior(
12931308
pat, cmt.clone(), subpat_ty,
1294-
InteriorField(PositionalField(i)));
1309+
InteriorField(PositionalField(adjust(i))));
12951310
self.cat_pattern_(subcmt, &subpat, op)?;
12961311
}
12971312
}

src/librustc/middle/region.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
970970
pats3.iter().any(|p| is_binding_pat(&p))
971971
}
972972

973-
PatKind::TupleStruct(_, Some(ref subpats)) |
974-
PatKind::Tup(ref subpats) => {
973+
PatKind::TupleStruct(_, ref subpats, _) |
974+
PatKind::Tuple(ref subpats, _) => {
975975
subpats.iter().any(|p| is_binding_pat(&p))
976976
}
977977

src/librustc/middle/stability.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
3333
use hir;
3434
use hir::{Item, Generics, StructField, Variant, PatKind};
3535
use hir::intravisit::{self, Visitor};
36+
use hir::pat_util::pat_adjust_pos;
3637

3738
use std::mem::replace;
3839
use std::cmp::Ordering;
@@ -614,10 +615,10 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
614615
};
615616
match pat.node {
616617
// Foo(a, b, c)
617-
// A Variant(..) pattern `PatKind::TupleStruct(_, None)` doesn't have to be recursed into.
618-
PatKind::TupleStruct(_, Some(ref pat_fields)) => {
619-
for (field, struct_field) in pat_fields.iter().zip(&v.fields) {
620-
maybe_do_stability_check(tcx, struct_field.did, field.span, cb)
618+
PatKind::TupleStruct(_, ref pat_fields, ddpos) => {
619+
let adjust = pat_adjust_pos(v.fields.len(), pat_fields.len(), ddpos);
620+
for (i, field) in pat_fields.iter().enumerate() {
621+
maybe_do_stability_check(tcx, v.fields[adjust(i)].did, field.span, cb)
621622
}
622623
}
623624
// Foo { a, b, c }

0 commit comments

Comments
 (0)