Skip to content

Commit 5c002ac

Browse files
committed
Adjust lowering of Slice patterns.
- Make sure extra `x @ ..` do not cause ICEs.
1 parent 634ebd5 commit 5c002ac

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
@@ -4174,30 +4174,8 @@ impl<'a> LoweringContext<'a> {
41744174
let node = match p.node {
41754175
PatKind::Wild => hir::PatKind::Wild,
41764176
PatKind::Ident(ref binding_mode, ident, ref sub) => {
4177-
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
4178-
// `None` can occur in body-less function signatures
4179-
res @ None | res @ Some(Res::Local(_)) => {
4180-
let canonical_id = match res {
4181-
Some(Res::Local(id)) => id,
4182-
_ => p.id,
4183-
};
4184-
4185-
hir::PatKind::Binding(
4186-
self.lower_binding_mode(binding_mode),
4187-
self.lower_node_id(canonical_id),
4188-
ident,
4189-
sub.as_ref().map(|x| self.lower_pat(x)),
4190-
)
4191-
}
4192-
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
4193-
None,
4194-
P(hir::Path {
4195-
span: ident.span,
4196-
res: self.lower_res(res),
4197-
segments: hir_vec![hir::PathSegment::from_ident(ident)],
4198-
}),
4199-
)),
4200-
}
4177+
let lower_sub = |this: &mut Self| sub.as_ref().map(|x| this.lower_pat(x));
4178+
self.lower_pat_ident(p, binding_mode, ident, lower_sub)
42014179
}
42024180
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
42034181
PatKind::TupleStruct(ref path, ref pats) => {
@@ -4259,11 +4237,7 @@ impl<'a> LoweringContext<'a> {
42594237
P(self.lower_expr(e2)),
42604238
self.lower_range_end(end),
42614239
),
4262-
PatKind::Slice(ref before, ref slice, ref after) => hir::PatKind::Slice(
4263-
before.iter().map(|x| self.lower_pat(x)).collect(),
4264-
slice.as_ref().map(|x| self.lower_pat(x)),
4265-
after.iter().map(|x| self.lower_pat(x)).collect(),
4266-
),
4240+
PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
42674241
PatKind::Rest => {
42684242
// If we reach here the `..` pattern is not semantically allowed.
42694243
self.ban_illegal_rest_pat(p.span)
@@ -4272,11 +4246,7 @@ impl<'a> LoweringContext<'a> {
42724246
PatKind::Mac(_) => panic!("Shouldn't exist here"),
42734247
};
42744248

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

42824252
fn lower_pat_tuple(
@@ -4310,6 +4280,102 @@ impl<'a> LoweringContext<'a> {
43104280
(elems.into(), rest.map(|(ddpos, _)| ddpos))
43114281
}
43124282

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

0 commit comments

Comments
 (0)