Skip to content

Commit

Permalink
Rollup merge of rust-lang#69128 - Centril:fix-69103, r=davidtwco
Browse files Browse the repository at this point in the history
Fix extra subslice lowering

We are currently ICEing on e.g.
```rust
fn main() {
    let [.., b @ ..] = [1, 2];
    b;
}
```
This happens because `b @ ..` registers a binding such that `b;` is OK, but then we forget to lower that binding in `rustc_ast_lowering`.

Fixes rust-lang#69103.

r? @davidtwco
  • Loading branch information
JohnTitor authored Feb 14, 2020
2 parents e0ea1e7 + f5bd964 commit 940fff7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 6 deletions.
17 changes: 11 additions & 6 deletions src/librustc_ast_lowering/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let mut slice = None;
let mut prev_rest_span = None;

// Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
this.pat_with_node_id_of(pat, node)
};

let mut iter = pats.iter();
// Lower all the patterns until the first occurrence of a sub-slice pattern.
for pat in iter.by_ref() {
Expand All @@ -142,9 +149,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
prev_rest_span = Some(sub.span);
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
slice = Some(self.pat_with_node_id_of(pat, node));
slice = Some(lower_rest_sub(self, pat, bm, ident, sub));
break;
}
// It was not a subslice pattern so lower it normally.
Expand All @@ -157,9 +162,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// There was a previous subslice pattern; make sure we don't allow more.
let rest_span = match pat.kind {
PatKind::Rest => Some(pat.span),
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
after.push(self.pat_wild_with_node_id_of(pat));
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
// #69103: Lower into `binding @ _` as above to avoid ICEs.
after.push(lower_rest_sub(self, pat, bm, ident, sub));
Some(sub.span)
}
_ => None,
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// We used to not lower the extra `b @ ..` into `b @ _` which meant that no type
// was registered for the binding `b` although it passed through resolve.
// This resulted in an ICE (#69103).

fn main() {
let [a @ .., b @ ..] = &mut [1, 2];
//~^ ERROR `..` can only be used once per slice pattern
b;

let [.., c @ ..] = [1, 2];
//~^ ERROR `..` can only be used once per slice pattern
c;

// This never ICEd, but let's make sure it won't regress either.
let (.., d @ ..) = (1, 2);
//~^ ERROR `..` patterns are not allowed here
d;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: `..` can only be used once per slice pattern
--> $DIR/issue-69103-extra-binding-subslice.rs:6:22
|
LL | let [a @ .., b @ ..] = &mut [1, 2];
| -- ^^ can only be used once per slice pattern
| |
| previously used here

error: `..` can only be used once per slice pattern
--> $DIR/issue-69103-extra-binding-subslice.rs:10:18
|
LL | let [.., c @ ..] = [1, 2];
| -- ^^ can only be used once per slice pattern
| |
| previously used here

error: `..` patterns are not allowed here
--> $DIR/issue-69103-extra-binding-subslice.rs:15:18
|
LL | let (.., d @ ..) = (1, 2);
| ^^
|
= note: only allowed in tuple, tuple struct, and slice patterns

error: aborting due to 3 previous errors

0 comments on commit 940fff7

Please sign in to comment.