Skip to content

Commit d5df1e0

Browse files
committed
Adjust lowering of Tuple/TupleStruct patterns.
- Make sure we ban duplicate '..'. - Avoid ICEs on PatKind::Rest that doesn't generate HIR nodes.
1 parent 8ba5f49 commit d5df1e0

File tree

1 file changed

+48
-9
lines changed

1 file changed

+48
-9
lines changed

src/librustc/hir/lowering.rs

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use std::mem;
5858
use smallvec::SmallVec;
5959
use syntax::attr;
6060
use syntax::ast;
61+
use syntax::ptr::P as AstP;
6162
use syntax::ast::*;
6263
use syntax::errors;
6364
use syntax::ext::hygiene::ExpnId;
@@ -468,7 +469,7 @@ impl<'a> LoweringContext<'a> {
468469
fn visit_pat(&mut self, p: &'tcx Pat) {
469470
match p.node {
470471
// Doesn't generate a HIR node
471-
PatKind::Paren(..) => {},
472+
PatKind::Paren(..) | PatKind::Rest => {},
472473
_ => {
473474
if let Some(owner) = self.hir_id_owner {
474475
self.lctx.lower_node_id_with_owner(p.id, owner);
@@ -4198,19 +4199,16 @@ impl<'a> LoweringContext<'a> {
41984199
}
41994200
}
42004201
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
4201-
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
4202+
PatKind::TupleStruct(ref path, ref pats) => {
42024203
let qpath = self.lower_qpath(
42034204
p.id,
42044205
&None,
42054206
path,
42064207
ParamMode::Optional,
42074208
ImplTraitContext::disallowed(),
42084209
);
4209-
hir::PatKind::TupleStruct(
4210-
qpath,
4211-
pats.iter().map(|x| self.lower_pat(x)).collect(),
4212-
ddpos,
4213-
)
4210+
let (pats, ddpos) = self.lower_pat_tuple(&*pats, "tuple struct");
4211+
hir::PatKind::TupleStruct(qpath, pats, ddpos)
42144212
}
42154213
PatKind::Path(ref qself, ref path) => {
42164214
let qpath = self.lower_qpath(
@@ -4247,8 +4245,9 @@ impl<'a> LoweringContext<'a> {
42474245
.collect();
42484246
hir::PatKind::Struct(qpath, fs, etc)
42494247
}
4250-
PatKind::Tuple(ref elts, ddpos) => {
4251-
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
4248+
PatKind::Tuple(ref pats) => {
4249+
let (pats, ddpos) = self.lower_pat_tuple(&*pats, "tuple");
4250+
hir::PatKind::Tuple(pats, ddpos)
42524251
}
42534252
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
42544253
PatKind::Ref(ref inner, mutbl) => {
@@ -4279,6 +4278,46 @@ impl<'a> LoweringContext<'a> {
42794278
})
42804279
}
42814280

4281+
fn lower_pat_tuple(
4282+
&mut self,
4283+
pats: &[AstP<Pat>],
4284+
ctx: &str,
4285+
) -> (HirVec<P<hir::Pat>>, Option<usize>) {
4286+
let mut elems = Vec::with_capacity(pats.len());
4287+
let mut rest = None;
4288+
4289+
let mut iter = pats.iter().enumerate();
4290+
while let Some((idx, pat)) = iter.next() {
4291+
// Interpret the first `..` pattern as a subtuple pattern.
4292+
if pat.is_rest() {
4293+
rest = Some((idx, pat.span));
4294+
break;
4295+
}
4296+
// It was not a subslice pattern so lower it normally.
4297+
elems.push(self.lower_pat(pat));
4298+
}
4299+
4300+
while let Some((_, pat)) = iter.next() {
4301+
// There was a previous subtuple pattern; make sure we don't allow more.
4302+
if pat.is_rest() {
4303+
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
4304+
} else {
4305+
elems.push(self.lower_pat(pat));
4306+
}
4307+
}
4308+
4309+
(elems.into(), rest.map(|(ddpos, _)| ddpos))
4310+
}
4311+
4312+
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
4313+
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
4314+
self.diagnostic()
4315+
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
4316+
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
4317+
.span_label(prev_sp, "previously used here")
4318+
.emit();
4319+
}
4320+
42824321
/// Used to ban the `..` pattern in places it shouldn't be semantically.
42834322
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind {
42844323
self.diagnostic()

0 commit comments

Comments
 (0)