Skip to content

Commit 694b3c3

Browse files
committed
Adjust lowering of Slice patterns.
- Make sure extra `x @ ..` do not cause ICEs.
1 parent d5df1e0 commit 694b3c3

File tree

1 file changed

+100
-34
lines changed

1 file changed

+100
-34
lines changed

src/librustc/hir/lowering.rs

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4173,30 +4173,8 @@ impl<'a> LoweringContext<'a> {
41734173
let node = match p.node {
41744174
PatKind::Wild => hir::PatKind::Wild,
41754175
PatKind::Ident(ref binding_mode, ident, ref sub) => {
4176-
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
4177-
// `None` can occur in body-less function signatures
4178-
res @ None | res @ Some(Res::Local(_)) => {
4179-
let canonical_id = match res {
4180-
Some(Res::Local(id)) => id,
4181-
_ => p.id,
4182-
};
4183-
4184-
hir::PatKind::Binding(
4185-
self.lower_binding_mode(binding_mode),
4186-
self.lower_node_id(canonical_id),
4187-
ident,
4188-
sub.as_ref().map(|x| self.lower_pat(x)),
4189-
)
4190-
}
4191-
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
4192-
None,
4193-
P(hir::Path {
4194-
span: ident.span,
4195-
res: self.lower_res(res),
4196-
segments: hir_vec![hir::PathSegment::from_ident(ident)],
4197-
}),
4198-
)),
4199-
}
4176+
let lower_sub = |this: &mut Self| sub.as_ref().map(|x| this.lower_pat(x));
4177+
self.lower_pat_ident(p, binding_mode, ident, lower_sub)
42004178
}
42014179
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
42024180
PatKind::TupleStruct(ref path, ref pats) => {
@@ -4258,11 +4236,7 @@ impl<'a> LoweringContext<'a> {
42584236
P(self.lower_expr(e2)),
42594237
self.lower_range_end(end),
42604238
),
4261-
PatKind::Slice(ref before, ref slice, ref after) => hir::PatKind::Slice(
4262-
before.iter().map(|x| self.lower_pat(x)).collect(),
4263-
slice.as_ref().map(|x| self.lower_pat(x)),
4264-
after.iter().map(|x| self.lower_pat(x)).collect(),
4265-
),
4239+
PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
42664240
PatKind::Rest => {
42674241
// If we reach here the `..` pattern is not semantically allowed.
42684242
self.ban_illegal_rest_pat(p.span)
@@ -4271,11 +4245,7 @@ impl<'a> LoweringContext<'a> {
42714245
PatKind::Mac(_) => panic!("Shouldn't exist here"),
42724246
};
42734247

4274-
P(hir::Pat {
4275-
hir_id: self.lower_node_id(p.id),
4276-
node,
4277-
span: p.span,
4278-
})
4248+
self.pat_bound(p, node)
42794249
}
42804250

42814251
fn lower_pat_tuple(
@@ -4309,6 +4279,102 @@ impl<'a> LoweringContext<'a> {
43094279
(elems.into(), rest.map(|(ddpos, _)| ddpos))
43104280
}
43114281

4282+
fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
4283+
let mut before = Vec::new();
4284+
let mut after = Vec::new();
4285+
let mut slice = None;
4286+
let mut prev_rest_span = None;
4287+
4288+
let mut iter = pats.iter();
4289+
while let Some(pat) = iter.next() {
4290+
// Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
4291+
match pat.node {
4292+
PatKind::Rest => {
4293+
prev_rest_span = Some(pat.span);
4294+
slice = Some(self.pat_bound_wild(pat));
4295+
break;
4296+
},
4297+
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
4298+
prev_rest_span = Some(sub.span);
4299+
let lower_sub = |this: &mut Self| Some(this.pat_bound_wild(sub));
4300+
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
4301+
slice = Some(self.pat_bound(pat, node));
4302+
break;
4303+
},
4304+
_ => {}
4305+
}
4306+
4307+
// It was not a subslice pattern so lower it normally.
4308+
before.push(self.lower_pat(pat));
4309+
}
4310+
4311+
while let Some(pat) = iter.next() {
4312+
// There was a previous subslice pattern; make sure we don't allow more.
4313+
let rest_span = match pat.node {
4314+
PatKind::Rest => Some(pat.span),
4315+
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
4316+
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
4317+
after.push(self.pat_bound_wild(pat));
4318+
Some(sub.span)
4319+
},
4320+
_ => None,
4321+
};
4322+
if let Some(rest_span) = rest_span {
4323+
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
4324+
} else {
4325+
after.push(self.lower_pat(pat));
4326+
}
4327+
}
4328+
4329+
hir::PatKind::Slice(before.into(), slice, after.into())
4330+
}
4331+
4332+
fn lower_pat_ident(
4333+
&mut self,
4334+
p: &Pat,
4335+
binding_mode: &BindingMode,
4336+
ident: Ident,
4337+
lower_sub: impl FnOnce(&mut Self) -> Option<P<hir::Pat>>,
4338+
) -> hir::PatKind {
4339+
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
4340+
// `None` can occur in body-less function signatures
4341+
res @ None | res @ Some(Res::Local(_)) => {
4342+
let canonical_id = match res {
4343+
Some(Res::Local(id)) => id,
4344+
_ => p.id,
4345+
};
4346+
4347+
hir::PatKind::Binding(
4348+
self.lower_binding_mode(binding_mode),
4349+
self.lower_node_id(canonical_id),
4350+
ident,
4351+
lower_sub(self),
4352+
)
4353+
}
4354+
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
4355+
None,
4356+
P(hir::Path {
4357+
span: ident.span,
4358+
res: self.lower_res(res),
4359+
segments: hir_vec![hir::PathSegment::from_ident(ident)],
4360+
}),
4361+
)),
4362+
}
4363+
}
4364+
4365+
fn pat_bound_wild(&mut self, p: &Pat) -> P<hir::Pat> {
4366+
self.pat_bound(p, hir::PatKind::Wild)
4367+
}
4368+
4369+
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
4370+
fn pat_bound(&mut self, p: &Pat, node: hir::PatKind) -> P<hir::Pat> {
4371+
P(hir::Pat {
4372+
hir_id: self.lower_node_id(p.id),
4373+
node,
4374+
span: p.span,
4375+
})
4376+
}
4377+
43124378
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
43134379
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
43144380
self.diagnostic()

0 commit comments

Comments
 (0)