about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Wieczorek <jakub@jakub.cc>2014-06-21 14:52:23 +0200
committerJakub Wieczorek <jakub@jakub.cc>2014-06-21 20:36:17 +0200
commitd4da4ba4b2f3412c7f9630c4d88ea3e121cd6f2a (patch)
treed050018ad9987c9e9fe9e8502b543d9f492ba33c
parentf556c8cbd8af182a9dd871a4a36692a0dba7cc2e (diff)
downloadrust-d4da4ba4b2f3412c7f9630c4d88ea3e121cd6f2a.tar.gz
rust-d4da4ba4b2f3412c7f9630c4d88ea3e121cd6f2a.zip
Fix a #14731 regression in missing_constructor() for vector patterns
Fixes #15080.
-rw-r--r--src/librustc/middle/check_match.rs26
-rw-r--r--src/test/run-pass/issue-15080.rs30
-rw-r--r--src/test/run-pass/vec-matching.rs8
3 files changed, 54 insertions, 10 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 6d8b178ba00..2c3ba98daae 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -281,21 +281,27 @@ fn missing_constructor(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Optio
 }
 
 fn all_constructors(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Vec<ctor> {
+    // This produces a list of all vector constructors that we would expect to appear
+    // in an exhaustive set of patterns. Because such a list would normally be infinite,
+    // we narrow it down to only those constructors that actually appear in the inspected
+    // column, plus, any that are missing and not covered by a pattern with a destructured slice.
     fn vec_constructors(m: &Matrix) -> Vec<ctor> {
         let max_vec_len = m.iter().map(|r| match r.get(0).node {
             PatVec(ref before, _, ref after) => before.len() + after.len(),
             _ => 0u
         }).max().unwrap_or(0u);
-        let contains_slice = m.iter().any(|r| match r.get(0).node {
-            PatVec(_, ref slice, _) => slice.is_some(),
-            _ => false
-        });
-        let lengths = iter::range_inclusive(0u, if contains_slice {
-            max_vec_len
-        } else {
-            max_vec_len + 1
-        });
-        lengths.map(|len| vec(len)).collect()
+        let min_vec_len_with_slice = m.iter().map(|r| match r.get(0).node {
+            PatVec(ref before, Some(_), ref after) => before.len() + after.len(),
+            _ => max_vec_len + 1
+        }).min().unwrap_or(max_vec_len + 1);
+        let other_lengths = m.iter().map(|r| match r.get(0).node {
+            PatVec(ref before, _, ref after) => before.len() + after.len(),
+            _ => 0u
+        }).filter(|&len| len > min_vec_len_with_slice);
+        iter::range_inclusive(0u, min_vec_len_with_slice)
+            .chain(other_lengths)
+            .map(|len| vec(len))
+            .collect()
     }
 
     match ty::get(left_ty).sty {
diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs
new file mode 100644
index 00000000000..b12f0c6462e
--- /dev/null
+++ b/src/test/run-pass/issue-15080.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let mut x = &[1, 2, 3, 4];
+
+    let mut result = vec!();
+    loop {
+        x = match x {
+            [1, n, 3, ..rest] => {
+                result.push(n);
+                rest
+            }
+            [n, ..rest] => {
+                result.push(n);
+                rest
+            }
+            [] =>
+                break
+        }
+    }
+    assert!(result.as_slice() == [2, 4]);
+}
diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs
index 175f774bdfd..11143ba0c84 100644
--- a/src/test/run-pass/vec-matching.rs
+++ b/src/test/run-pass/vec-matching.rs
@@ -68,9 +68,17 @@ fn d() {
     assert_eq!(branch, 1);
 }
 
+fn e() {
+    match &[1, 2, 3] {
+        [1, 2] => (),
+        [..] => ()
+    }
+}
+
 pub fn main() {
     a();
     b();
     c();
     d();
+    e();
 }