]> git.lizzy.rs Git - rust.git/commitdiff
fix extra subslice lowering
authorMazdak Farrokhzad <twingoow@gmail.com>
Thu, 13 Feb 2020 11:19:36 +0000 (12:19 +0100)
committerMazdak Farrokhzad <twingoow@gmail.com>
Thu, 13 Feb 2020 11:24:53 +0000 (12:24 +0100)
src/librustc_ast_lowering/pat.rs
src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs [new file with mode: 0644]
src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr [new file with mode: 0644]

index 4c3c4ddac78ee40c115889de8d50ded11ff9cbdb..b42b12c4dd8513a1e610f314a1d5b3eea13b58a4 100644 (file)
@@ -128,6 +128,13 @@ fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'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() {
@@ -142,9 +149,7 @@ fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'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.
@@ -157,9 +162,9 @@ fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'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,
diff --git a/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs
new file mode 100644 (file)
index 0000000..061b0d6
--- /dev/null
@@ -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;
+}
diff --git a/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr
new file mode 100644 (file)
index 0000000..9432e2f
--- /dev/null
@@ -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
+