Skip to content

Commit e3a4a8b

Browse files
committed
---
yaml --- r: 151324 b: refs/heads/try2 c: 90449ab h: refs/heads/master v: v3
1 parent 8c5ba01 commit e3a4a8b

File tree

4 files changed

+155
-40
lines changed

4 files changed

+155
-40
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 7adc48527fa0505a0cda6eaf1b6cafb01e434170
8+
refs/heads/try2: 90449abcb30ed8b0fd1bab84f45630769f668247
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/librustc/middle/trans/_match.rs

Lines changed: 81 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ fn enter_default<'a, 'b>(
526526
// Collect all of the matches that can match against anything.
527527
let matches = enter_match(bcx, dm, m, col, val, |p| {
528528
match p.node {
529-
ast::PatWild | ast::PatWildMulti | ast::PatTup(_) => Some(Vec::new()),
529+
ast::PatWild | ast::PatWildMulti => Some(Vec::new()),
530530
ast::PatIdent(_, _, None) if pat_is_binding(dm, p) => Some(Vec::new()),
531531
_ => None
532532
}
@@ -712,18 +712,7 @@ fn enter_opt<'a, 'b>(
712712
}
713713
_ => {
714714
assert_is_binding_or_wild(bcx, p);
715-
// In most cases, a binding/wildcard match be
716-
// considered to match against any Opt. However, when
717-
// doing vector pattern matching, submatches are
718-
// considered even if the eventual match might be from
719-
// a different submatch. Thus, when a submatch fails
720-
// when doing a vector match, we proceed to the next
721-
// submatch. Thus, including a default match would
722-
// cause the default match to fire spuriously.
723-
match *opt {
724-
vec_len(..) => None,
725-
_ => Some(Vec::from_elem(variant_size, dummy))
726-
}
715+
Some(Vec::from_elem(variant_size, dummy))
727716
}
728717
};
729718
i += 1;
@@ -1363,7 +1352,8 @@ fn compile_guard<'a, 'b>(
13631352
data: &ArmData,
13641353
m: &'a [Match<'a, 'b>],
13651354
vals: &[ValueRef],
1366-
chk: &FailureHandler)
1355+
chk: &FailureHandler,
1356+
has_genuine_default: bool)
13671357
-> &'b Block<'b> {
13681358
debug!("compile_guard(bcx={}, guard_expr={}, m={}, vals={})",
13691359
bcx.to_str(),
@@ -1394,7 +1384,17 @@ fn compile_guard<'a, 'b>(
13941384
// Guard does not match: free the values we copied,
13951385
// and remove all bindings from the lllocals table
13961386
let bcx = drop_bindings(bcx, data);
1397-
compile_submatch(bcx, m, vals, chk);
1387+
match chk {
1388+
// If the default arm is the only one left, move on to the next
1389+
// condition explicitly rather than (possibly) falling back to
1390+
// the default arm.
1391+
&JumpToBasicBlock(_) if m.len() == 1 && has_genuine_default => {
1392+
Br(bcx, chk.handle_fail());
1393+
}
1394+
_ => {
1395+
compile_submatch(bcx, m, vals, chk, has_genuine_default);
1396+
}
1397+
};
13981398
bcx
13991399
});
14001400

@@ -1418,7 +1418,8 @@ fn compile_submatch<'a, 'b>(
14181418
bcx: &'b Block<'b>,
14191419
m: &'a [Match<'a, 'b>],
14201420
vals: &[ValueRef],
1421-
chk: &FailureHandler) {
1421+
chk: &FailureHandler,
1422+
has_genuine_default: bool) {
14221423
debug!("compile_submatch(bcx={}, m={}, vals={})",
14231424
bcx.to_str(),
14241425
m.repr(bcx.tcx()),
@@ -1448,7 +1449,8 @@ fn compile_submatch<'a, 'b>(
14481449
m[0].data,
14491450
m.slice(1, m.len()),
14501451
vals,
1451-
chk);
1452+
chk,
1453+
has_genuine_default);
14521454
}
14531455
_ => ()
14541456
}
@@ -1466,9 +1468,10 @@ fn compile_submatch<'a, 'b>(
14661468
vals,
14671469
chk,
14681470
col,
1469-
val)
1471+
val,
1472+
has_genuine_default)
14701473
} else {
1471-
compile_submatch_continue(bcx, m, vals, chk, col, val)
1474+
compile_submatch_continue(bcx, m, vals, chk, col, val, has_genuine_default)
14721475
}
14731476
}
14741477

@@ -1478,7 +1481,8 @@ fn compile_submatch_continue<'a, 'b>(
14781481
vals: &[ValueRef],
14791482
chk: &FailureHandler,
14801483
col: uint,
1481-
val: ValueRef) {
1484+
val: ValueRef,
1485+
has_genuine_default: bool) {
14821486
let fcx = bcx.fcx;
14831487
let tcx = bcx.tcx();
14841488
let dm = &tcx.def_map;
@@ -1512,7 +1516,7 @@ fn compile_submatch_continue<'a, 'b>(
15121516
rec_fields.as_slice(),
15131517
val).as_slice(),
15141518
rec_vals.append(vals_left.as_slice()).as_slice(),
1515-
chk);
1519+
chk, has_genuine_default);
15161520
});
15171521
return;
15181522
}
@@ -1537,7 +1541,7 @@ fn compile_submatch_continue<'a, 'b>(
15371541
val,
15381542
n_tup_elts).as_slice(),
15391543
tup_vals.append(vals_left.as_slice()).as_slice(),
1540-
chk);
1544+
chk, has_genuine_default);
15411545
return;
15421546
}
15431547

@@ -1562,7 +1566,7 @@ fn compile_submatch_continue<'a, 'b>(
15621566
enter_tuple_struct(bcx, dm, m, col, val,
15631567
struct_element_count).as_slice(),
15641568
llstructvals.append(vals_left.as_slice()).as_slice(),
1565-
chk);
1569+
chk, has_genuine_default);
15661570
return;
15671571
}
15681572

@@ -1571,7 +1575,7 @@ fn compile_submatch_continue<'a, 'b>(
15711575
compile_submatch(bcx,
15721576
enter_uniq(bcx, dm, m, col, val).as_slice(),
15731577
(vec!(llbox)).append(vals_left.as_slice()).as_slice(),
1574-
chk);
1578+
chk, has_genuine_default);
15751579
return;
15761580
}
15771581

@@ -1580,7 +1584,7 @@ fn compile_submatch_continue<'a, 'b>(
15801584
compile_submatch(bcx,
15811585
enter_region(bcx, dm, m, col, val).as_slice(),
15821586
(vec!(loaded_val)).append(vals_left.as_slice()).as_slice(),
1583-
chk);
1587+
chk, has_genuine_default);
15841588
return;
15851589
}
15861590

@@ -1637,9 +1641,9 @@ fn compile_submatch_continue<'a, 'b>(
16371641

16381642
// Compile subtrees for each option
16391643
for (i, opt) in opts.iter().enumerate() {
1640-
// In some cases in vector pattern matching, we need to override
1641-
// the failure case so that instead of failing, it proceeds to
1642-
// try more matching. branch_chk, then, is the proper failure case
1644+
// In some cases of range and vector pattern matching, we need to
1645+
// override the failure case so that instead of failing, it proceeds
1646+
// to try more matching. branch_chk, then, is the proper failure case
16431647
// for the current conditional branch.
16441648
let mut branch_chk = None;
16451649
let mut opt_cx = else_cx;
@@ -1689,6 +1693,16 @@ fn compile_submatch_continue<'a, 'b>(
16891693
}
16901694
};
16911695
bcx = fcx.new_temp_block("compare_next");
1696+
1697+
// If none of the sub-cases match, and the current condition
1698+
// is guarded or has multiple patterns, move on to the next
1699+
// condition, if there is any, rather than falling back to
1700+
// the default.
1701+
let guarded = m[i].data.arm.guard.is_some();
1702+
let multi_pats = m[i].pats.len() > 1;
1703+
if i+1 < len && (guarded || multi_pats) {
1704+
branch_chk = Some(JumpToBasicBlock(bcx.llbb));
1705+
}
16921706
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
16931707
}
16941708
compare_vec_len => {
@@ -1726,8 +1740,10 @@ fn compile_submatch_continue<'a, 'b>(
17261740
bcx = fcx.new_temp_block("compare_vec_len_next");
17271741

17281742
// If none of these subcases match, move on to the
1729-
// next condition.
1730-
branch_chk = Some(JumpToBasicBlock(bcx.llbb));
1743+
// next condition if there is any.
1744+
if i+1 < len {
1745+
branch_chk = Some(JumpToBasicBlock(bcx.llbb));
1746+
}
17311747
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
17321748
}
17331749
_ => ()
@@ -1767,27 +1783,38 @@ fn compile_submatch_continue<'a, 'b>(
17671783
compile_submatch(opt_cx,
17681784
opt_ms.as_slice(),
17691785
opt_vals.as_slice(),
1770-
chk)
1786+
chk,
1787+
has_genuine_default)
17711788
}
17721789
Some(branch_chk) => {
17731790
compile_submatch(opt_cx,
17741791
opt_ms.as_slice(),
17751792
opt_vals.as_slice(),
1776-
&branch_chk)
1793+
&branch_chk,
1794+
has_genuine_default)
17771795
}
17781796
}
17791797
}
17801798

17811799
// Compile the fall-through case, if any
1782-
if !exhaustive {
1800+
if !exhaustive && kind != single {
17831801
if kind == compare || kind == compare_vec_len {
17841802
Br(bcx, else_cx.llbb);
17851803
}
1786-
if kind != single {
1787-
compile_submatch(else_cx,
1788-
defaults.as_slice(),
1789-
vals_left.as_slice(),
1790-
chk);
1804+
match chk {
1805+
// If there is only one default arm left, move on to the next
1806+
// condition explicitly rather than (eventually) falling back to
1807+
// the last default arm.
1808+
&JumpToBasicBlock(_) if defaults.len() == 1 && has_genuine_default => {
1809+
Br(else_cx, chk.handle_fail());
1810+
}
1811+
_ => {
1812+
compile_submatch(else_cx,
1813+
defaults.as_slice(),
1814+
vals_left.as_slice(),
1815+
chk,
1816+
has_genuine_default);
1817+
}
17911818
}
17921819
}
17931820
}
@@ -1892,7 +1919,22 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
18921919
}));
18931920
}
18941921

1895-
compile_submatch(bcx, matches.as_slice(), [discr_datum.val], &chk);
1922+
// `compile_submatch` works one column of arm patterns a time and
1923+
// then peels that column off. So as we progress, it may become
1924+
// impossible to know whether we have a genuine default arm, i.e.
1925+
// `_ => foo` or not. Sometimes it is important to know that in order
1926+
// to decide whether moving on to the next condition or falling back
1927+
// to the default arm.
1928+
let has_default = arms.len() > 0 && {
1929+
let ref pats = arms.last().unwrap().pats;
1930+
1931+
pats.len() == 1
1932+
&& match pats.last().unwrap().node {
1933+
ast::PatWild => true, _ => false
1934+
}
1935+
};
1936+
1937+
compile_submatch(bcx, matches.as_slice(), [discr_datum.val], &chk, has_default);
18961938

18971939
let mut arm_cxs = Vec::new();
18981940
for arm_data in arm_datas.iter() {

branches/try2/src/test/run-pass/issue-13027.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn main() {
2323
multi_pats_shadow_range();
2424
lit_shadow_multi_pats();
2525
range_shadow_multi_pats();
26+
misc();
2627
}
2728

2829
fn lit_shadow_range() {
@@ -168,3 +169,18 @@ fn range_shadow_multi_pats() {
168169
_ => 3,
169170
});
170171
}
172+
173+
fn misc() {
174+
enum Foo {
175+
Bar(uint, bool)
176+
}
177+
// This test basically mimics how trace_macros! macro is implemented,
178+
// which is a rare combination of vector patterns, multiple wild-card
179+
// patterns and guard functions.
180+
let r = match [Bar(0, false)].as_slice() {
181+
[Bar(_, pred)] if pred => 1,
182+
[Bar(_, pred)] if !pred => 2,
183+
_ => 0,
184+
};
185+
assert_eq!(2, r);
186+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that codegen works correctly when there are multiple refutable
12+
// patterns in match expression.
13+
14+
enum Foo {
15+
FooUint(uint),
16+
FooNullary,
17+
}
18+
19+
fn main() {
20+
let r = match (FooNullary, 'a') {
21+
(FooUint(..), 'a'..'z') => 1,
22+
(FooNullary, 'x') => 2,
23+
_ => 0
24+
};
25+
assert_eq!(r, 0);
26+
27+
let r = match (FooUint(0), 'a') {
28+
(FooUint(1), 'a'..'z') => 1,
29+
(FooUint(..), 'x') => 2,
30+
(FooNullary, 'a') => 3,
31+
_ => 0
32+
};
33+
assert_eq!(r, 0);
34+
35+
let r = match ('a', FooUint(0)) {
36+
('a'..'z', FooUint(1)) => 1,
37+
('x', FooUint(..)) => 2,
38+
('a', FooNullary) => 3,
39+
_ => 0
40+
};
41+
assert_eq!(r, 0);
42+
43+
let r = match ('a', 'a') {
44+
('a'..'z', 'b') => 1,
45+
('x', 'a'..'z') => 2,
46+
_ => 0
47+
};
48+
assert_eq!(r, 0);
49+
50+
let r = match ('a', 'a') {
51+
('a'..'z', 'b') => 1,
52+
('x', 'a'..'z') => 2,
53+
('a', 'a') => 3,
54+
_ => 0
55+
};
56+
assert_eq!(r, 3);
57+
}

0 commit comments

Comments
 (0)