Skip to content

Commit 170c438

Browse files
committed
Rollup merge of rust-lang#33639 - petrochenkov:dotdot, r=nmatsakis
cc rust-lang#33627 r? @nikomatsakis plugin-[breaking-change] cc rust-lang#31645 @Manishearth
2 parents 1c9c002 + a7b1ab5 commit 170c438

Some content is hidden

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

50 files changed

+874
-298
lines changed

src/doc/reference.md

+2
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

+2-3
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

+5-3
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

+3-5
Original file line numberDiff line numberDiff line change
@@ -460,11 +460,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
460460

461461
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
462462
match pattern.node {
463-
PatKind::TupleStruct(ref path, ref opt_children) => {
463+
PatKind::TupleStruct(ref path, ref children, _) => {
464464
visitor.visit_path(path, pattern.id);
465-
if let Some(ref children) = *opt_children {
466-
walk_list!(visitor, visit_pat, children);
467-
}
465+
walk_list!(visitor, visit_pat, children);
468466
}
469467
PatKind::Path(ref path) => {
470468
visitor.visit_path(path, pattern.id);
@@ -480,7 +478,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
480478
visitor.visit_pat(&field.node.pat)
481479
}
482480
}
483-
PatKind::Tup(ref tuple_elements) => {
481+
PatKind::Tuple(ref tuple_elements, _) => {
484482
walk_list!(visitor, visit_pat, tuple_elements);
485483
}
486484
PatKind::Box(ref subpattern) |

src/librustc/hir/lowering.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -876,10 +876,10 @@ impl<'a> LoweringContext<'a> {
876876
})
877877
}
878878
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
879-
PatKind::TupleStruct(ref pth, ref pats) => {
879+
PatKind::TupleStruct(ref pth, ref pats, ddpos) => {
880880
hir::PatKind::TupleStruct(self.lower_path(pth),
881-
pats.as_ref()
882-
.map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect()))
881+
pats.iter().map(|x| self.lower_pat(x)).collect(),
882+
ddpos)
883883
}
884884
PatKind::Path(ref pth) => {
885885
hir::PatKind::Path(self.lower_path(pth))
@@ -907,8 +907,8 @@ impl<'a> LoweringContext<'a> {
907907
.collect();
908908
hir::PatKind::Struct(pth, fs, etc)
909909
}
910-
PatKind::Tup(ref elts) => {
911-
hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect())
910+
PatKind::Tuple(ref elts, ddpos) => {
911+
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
912912
}
913913
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
914914
PatKind::Ref(ref inner, mutbl) => {
@@ -1854,7 +1854,7 @@ impl<'a> LoweringContext<'a> {
18541854
let pt = if subpats.is_empty() {
18551855
hir::PatKind::Path(path)
18561856
} else {
1857-
hir::PatKind::TupleStruct(path, Some(subpats))
1857+
hir::PatKind::TupleStruct(path, subpats, None)
18581858
};
18591859
let pat = self.pat(span, pt);
18601860
self.resolver.record_resolution(pat.id, def);

src/librustc/hir/mod.rs

+9-7
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 is present, 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 is present, 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

+34
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,43 @@ use hir::{self, PatKind};
1818
use syntax::codemap::{respan, Span, Spanned, DUMMY_SP};
1919

2020
use std::cell::RefCell;
21+
use std::iter::{Enumerate, ExactSizeIterator};
2122

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

25+
pub struct EnumerateAndAdjust<I> {
26+
enumerate: Enumerate<I>,
27+
gap_pos: usize,
28+
gap_len: usize,
29+
}
30+
31+
impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
32+
type Item = (usize, <I as Iterator>::Item);
33+
34+
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
35+
self.enumerate.next().map(|(i, elem)| {
36+
(if i < self.gap_pos { i } else { i + self.gap_len }, elem)
37+
})
38+
}
39+
}
40+
41+
pub trait EnumerateAndAdjustIterator {
42+
fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
43+
-> EnumerateAndAdjust<Self> where Self: Sized;
44+
}
45+
46+
impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
47+
fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
48+
-> EnumerateAndAdjust<Self> where Self: Sized {
49+
let actual_len = self.len();
50+
EnumerateAndAdjust {
51+
enumerate: self.enumerate(),
52+
gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len },
53+
gap_len: expected_len - actual_len,
54+
}
55+
}
56+
}
57+
2458
// This is used because same-named variables in alternative patterns need to
2559
// use the NodeId of their namesake in the first pattern.
2660
pub fn pat_id_map(dm: &RefCell<DefMap>, pat: &hir::Pat) -> PatIdMap {

src/librustc/hir/print.rs

+30-11
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/middle/expr_use_visitor.rs

+1-1
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

+22-9
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::EnumerateAndAdjustIterator;
8384
use hir;
8485
use syntax::ast;
8586
use syntax::codemap::Span;
@@ -1225,14 +1226,13 @@ 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)
1235-
for (i, subpat) in subpats.iter().enumerate() {
1233+
let expected_len = self.tcx().lookup_adt_def(enum_def)
1234+
.variant_with_id(def_id).fields.len();
1235+
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
12361236
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
12371237

12381238
let subcmt =
@@ -1244,7 +1244,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12441244
}
12451245
}
12461246
Some(Def::Struct(..)) => {
1247-
for (i, subpat) in subpats.iter().enumerate() {
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+
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
12481257
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
12491258
let cmt_field =
12501259
self.cat_imm_interior(
@@ -1284,9 +1293,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12841293
}
12851294
}
12861295

1287-
PatKind::Tup(ref subpats) => {
1296+
PatKind::Tuple(ref subpats, ddpos) => {
12881297
// (p1, ..., pN)
1289-
for (i, subpat) in subpats.iter().enumerate() {
1298+
let expected_len = match self.pat_ty(&pat) {
1299+
Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(),
1300+
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
1301+
};
1302+
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
12901303
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
12911304
let subcmt =
12921305
self.cat_imm_interior(

src/librustc/middle/region.rs

+2-2
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

+4-4
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::EnumerateAndAdjustIterator;
3637

3738
use std::mem::replace;
3839
use std::cmp::Ordering;
@@ -614,10 +615,9 @@ 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+
for (i, field) in pat_fields.iter().enumerate_and_adjust(v.fields.len(), ddpos) {
620+
maybe_do_stability_check(tcx, v.fields[i].did, field.span, cb)
621621
}
622622
}
623623
// Foo { a, b, c }

0 commit comments

Comments
 (0)