about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-10-12 21:47:34 +0000
committerbors <bors@rust-lang.org>2014-10-12 21:47:34 +0000
commitff0abf05c9852df629df4a1ebe2e4276a87fc4f9 (patch)
treee514a4b21d62bb60dda148b2c9988f14e3f6d5c8
parent38517d0eba2ee69443449fbe6b1ce7dea7deca7b (diff)
parent0c48c5712dc52bb1f9e70181f1b68feff75269c2 (diff)
downloadrust-ff0abf05c9852df629df4a1ebe2e4276a87fc4f9.tar.gz
rust-ff0abf05c9852df629df4a1ebe2e4276a87fc4f9.zip
auto merge of #17944 : jakub-/rust/issue-17877, r=alexcrichton
Fixes #17877.
-rw-r--r--src/librustc/middle/check_match.rs4
-rw-r--r--src/librustc/middle/pat_util.rs16
-rw-r--r--src/librustc/middle/trans/_match.rs128
-rw-r--r--src/test/run-pass/issue-17877.rs21
4 files changed, 107 insertions, 62 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 29764070768..16329fe9c65 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -638,7 +638,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
         PatEnum(..) =>
             match cx.tcx.def_map.borrow().find(&pat.id) {
                 Some(&DefConst(..)) =>
-                    cx.tcx.sess.span_bug(pat.span, "static pattern should've \
+                    cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
                 _ => vec!(Single)
@@ -646,7 +646,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
         PatStruct(..) =>
             match cx.tcx.def_map.borrow().find(&pat.id) {
                 Some(&DefConst(..)) =>
-                    cx.tcx.sess.span_bug(pat.span, "static pattern should've \
+                    cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
                 _ => vec!(Single)
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index 4d61baca708..357f4cdf0eb 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -25,11 +25,25 @@ pub type PatIdMap = HashMap<Ident, NodeId>;
 pub fn pat_id_map(dm: &resolve::DefMap, pat: &Pat) -> PatIdMap {
     let mut map = HashMap::new();
     pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
-      map.insert(path1.node, p_id);
+        map.insert(path1.node, p_id);
     });
     map
 }
 
+pub fn pat_is_refutable(dm: &resolve::DefMap, pat: &Pat) -> bool {
+    match pat.node {
+        PatLit(_) | PatRange(_, _) => true,
+        PatEnum(_, _) | PatIdent(_, _, None) | PatStruct(..) => {
+            match dm.borrow().find(&pat.id) {
+                Some(&DefVariant(..)) => true,
+                _ => false
+            }
+        }
+        PatVec(_, _, _) => true,
+        _ => false
+    }
+}
+
 pub fn pat_is_variant_or_struct(dm: &resolve::DefMap, pat: &Pat) -> bool {
     match pat.node {
         PatEnum(_, _) | PatIdent(_, _, None) | PatStruct(..) => {
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 9eb02717f04..55486354e7d 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -218,6 +218,7 @@ use util::ppaux::{Repr, vec_map_to_string};
 
 use std;
 use std::collections::HashMap;
+use std::iter::AdditiveIterator;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::ast::{DUMMY_NODE_ID, Ident};
@@ -754,33 +755,41 @@ impl FailureHandler {
     }
 }
 
-fn pick_col(m: &[Match]) -> uint {
-    fn score(p: &ast::Pat) -> uint {
-        match p.node {
-          ast::PatLit(_) | ast::PatEnum(_, _) | ast::PatRange(_, _) => 1u,
-          ast::PatIdent(_, _, Some(ref p)) => score(&**p),
-          _ => 0u
+fn pick_column_to_specialize(def_map: &DefMap, m: &[Match]) -> Option<uint> {
+    fn pat_score(def_map: &DefMap, pat: &ast::Pat) -> uint {
+        match pat.node {
+            ast::PatIdent(_, _, Some(ref inner)) => pat_score(def_map, &**inner),
+            _ if pat_is_refutable(def_map, pat) => 1u,
+            _ => 0u
         }
     }
-    let mut scores = Vec::from_elem(m[0].pats.len(), 0u);
-    for br in m.iter() {
-        for (i, ref p) in br.pats.iter().enumerate() {
-            *scores.get_mut(i) += score(&***p);
+
+    let column_score: |&[Match], uint| -> uint = |m, col| {
+        let total_score = m.iter()
+            .map(|row| row.pats[col])
+            .map(|pat| pat_score(def_map, pat))
+            .sum();
+
+        // Irrefutable columns always go first, they'd only be duplicated in the branches.
+        if total_score == 0 {
+            std::uint::MAX
+        } else {
+            total_score
         }
-    }
-    let mut max_score = 0u;
-    let mut best_col = 0u;
-    for (i, score) in scores.iter().enumerate() {
-        let score = *score;
-
-        // Irrefutable columns always go first, they'd only be duplicated in
-        // the branches.
-        if score == 0u { return i; }
-        // If no irrefutable ones are found, we pick the one with the biggest
-        // branching factor.
-        if score > max_score { max_score = score; best_col = i; }
-    }
-    return best_col;
+    };
+
+    let column_contains_any_nonwild_patterns: |&uint| -> bool = |&col| {
+        m.iter().any(|row| match row.pats[col].node {
+            ast::PatWild(_) => false,
+            _ => true
+        })
+    };
+
+    range(0, m[0].pats.len())
+        .filter(column_contains_any_nonwild_patterns)
+        .map(|col| (col, column_score(m, col)))
+        .max_by(|&(_, score)| score)
+        .map(|(col, _)| col)
 }
 
 // Compiles a comparison between two things.
@@ -951,44 +960,45 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         return;
     }
 
-    let col_count = m[0].pats.len();
-    if col_count == 0u {
-        let data = &m[0].data;
-        for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
-            let llmatch = data.bindings_map.get(ident).llmatch;
-            call_lifetime_start(bcx, llmatch);
-            Store(bcx, *value_ptr, llmatch);
+    let tcx = bcx.tcx();
+    let def_map = &tcx.def_map;
+    match pick_column_to_specialize(def_map, m) {
+        Some(col) => {
+            let val = vals[col];
+            if has_nested_bindings(m, col) {
+                let expanded = expand_nested_bindings(bcx, m, col, val);
+                compile_submatch_continue(bcx,
+                                          expanded.as_slice(),
+                                          vals,
+                                          chk,
+                                          col,
+                                          val,
+                                          has_genuine_default)
+            } else {
+                compile_submatch_continue(bcx, m, vals, chk, col, val, has_genuine_default)
+            }
         }
-        match data.arm.guard {
-            Some(ref guard_expr) => {
-                bcx = compile_guard(bcx,
-                                    &**guard_expr,
-                                    m[0].data,
-                                    m[1..m.len()],
-                                    vals,
-                                    chk,
-                                    has_genuine_default);
+        None => {
+            let data = &m[0].data;
+            for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
+                let llmatch = data.bindings_map.get(ident).llmatch;
+                call_lifetime_start(bcx, llmatch);
+                Store(bcx, *value_ptr, llmatch);
             }
-            _ => ()
+            match data.arm.guard {
+                Some(ref guard_expr) => {
+                    bcx = compile_guard(bcx,
+                                        &**guard_expr,
+                                        m[0].data,
+                                        m[1..m.len()],
+                                        vals,
+                                        chk,
+                                        has_genuine_default);
+                }
+                _ => ()
+            }
+            Br(bcx, data.bodycx.llbb);
         }
-        Br(bcx, data.bodycx.llbb);
-        return;
-    }
-
-    let col = pick_col(m);
-    let val = vals[col];
-
-    if has_nested_bindings(m, col) {
-        let expanded = expand_nested_bindings(bcx, m, col, val);
-        compile_submatch_continue(bcx,
-                                  expanded.as_slice(),
-                                  vals,
-                                  chk,
-                                  col,
-                                  val,
-                                  has_genuine_default)
-    } else {
-        compile_submatch_continue(bcx, m, vals, chk, col, val, has_genuine_default)
     }
 }
 
diff --git a/src/test/run-pass/issue-17877.rs b/src/test/run-pass/issue-17877.rs
new file mode 100644
index 00000000000..51db2f05959
--- /dev/null
+++ b/src/test/run-pass/issue-17877.rs
@@ -0,0 +1,21 @@
+// 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() {
+    assert_eq!(match [0u8, ..1024] {
+        _ => 42u,
+    }, 42u);
+
+    assert_eq!(match [0u8, ..1024] {
+        [1, _..] => 0u,
+        [0, _..] => 1u,
+        _ => 2u
+    }, 1u);
+}