Skip to content

Commit b622891

Browse files
committed
Auto merge of #30553 - luqmana:mir-match-arm-guards, r=nikomatsakis
Fixes #30527. ```Rust fn main() { let _abc = match Some(101i8) { Some(xyz) if xyz > 100 => xyz, Some(_) => -1, None => -2 }; } ``` Resulting MIR now includes the `Some(xyz)` arm, guard and all: ![match.dot](https://cloud.githubusercontent.com/assets/287063/11999413/066f7610-aa8b-11e5-927b-24215af57fc4.png) ~~Not quite sure how to write a test for this.~~ Thinking too hard, just tested the end result. r? @nikomatsakis
2 parents 543bb03 + f88c808 commit b622891

File tree

2 files changed

+46
-23
lines changed

2 files changed

+46
-23
lines changed

src/librustc_mir/build/matches/mod.rs

+18-23
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
6161
// assemble a list of candidates: there is one candidate per
6262
// pattern, which means there may be more than one candidate
6363
// *per arm*. These candidates are kept sorted such that the
64-
// highest priority candidate comes last in the list. This the
65-
// reverse of the order in which candidates are written in the
66-
// source.
64+
// highest priority candidate comes first in the list.
65+
// (i.e. same order as in source)
6766
let candidates: Vec<_> =
6867
arms.iter()
6968
.enumerate()
70-
.rev() // highest priority comes last
7169
.flat_map(|(arm_index, arm)| {
7270
arm.patterns.iter()
73-
.rev()
7471
.map(move |pat| (arm_index, pat, arm.guard.clone()))
7572
})
7673
.map(|(arm_index, pattern, guard)| {
@@ -290,9 +287,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
290287
/// The main match algorithm. It begins with a set of candidates
291288
/// `candidates` and has the job of generating code to determine
292289
/// which of these candidates, if any, is the correct one. The
293-
/// candidates are sorted in inverse priority -- so the last item
294-
/// in the list has highest priority. When a candidate is found to
295-
/// match the value, we will generate a branch to the appropriate
290+
/// candidates are sorted such that the first item in the list
291+
/// has the highest priority. When a candidate is found to match
292+
/// the value, we will generate a branch to the appropriate
296293
/// block found in `arm_blocks`.
297294
///
298295
/// The return value is a list of "otherwise" blocks. These are
@@ -324,17 +321,17 @@ impl<'a,'tcx> Builder<'a,'tcx> {
324321
unpack!(block = self.simplify_candidate(block, candidate));
325322
}
326323

327-
// The candidates are inversely sorted by priority. Check to
328-
// see whether the candidates in the front of the queue (and
329-
// hence back of the vec) have satisfied all their match
324+
// The candidates are sorted by priority. Check to see
325+
// whether the higher priority candidates (and hence at
326+
// the front of the vec) have satisfied all their match
330327
// pairs.
331328
let fully_matched =
332-
candidates.iter().rev().take_while(|c| c.match_pairs.is_empty()).count();
329+
candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
333330
debug!("match_candidates: {:?} candidates fully matched", fully_matched);
334-
for _ in 0..fully_matched {
331+
let mut unmatched_candidates = candidates.split_off(fully_matched);
332+
for candidate in candidates {
335333
// If so, apply any bindings, test the guard (if any), and
336334
// branch to the arm.
337-
let candidate = candidates.pop().unwrap();
338335
if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
339336
block = b;
340337
} else {
@@ -346,13 +343,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
346343

347344
// If there are no candidates that still need testing, we're done.
348345
// Since all matches are exhaustive, execution should never reach this point.
349-
if candidates.is_empty() {
346+
if unmatched_candidates.is_empty() {
350347
return vec![block];
351348
}
352349

353350
// Test candidates where possible.
354351
let (otherwise, tested_candidates) =
355-
self.test_candidates(span, arm_blocks, &candidates, block);
352+
self.test_candidates(span, arm_blocks, &unmatched_candidates, block);
356353

357354
// If the target candidates were exhaustive, then we are done.
358355
if otherwise.is_empty() {
@@ -361,15 +358,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
361358

362359
// If all candidates were sorted into `target_candidates` somewhere, then
363360
// the initial set was inexhaustive.
364-
let untested_candidates = candidates.len() - tested_candidates;
365-
if untested_candidates == 0 {
361+
let untested_candidates = unmatched_candidates.split_off(tested_candidates);
362+
if untested_candidates.len() == 0 {
366363
return otherwise;
367364
}
368365

369366
// Otherwise, let's process those remaining candidates.
370367
let join_block = self.join_otherwise_blocks(otherwise);
371-
candidates.truncate(untested_candidates);
372-
self.match_candidates(span, arm_blocks, candidates, join_block)
368+
self.match_candidates(span, arm_blocks, untested_candidates, join_block)
373369
}
374370

375371
fn join_otherwise_blocks(&mut self,
@@ -461,7 +457,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
461457
-> (Vec<BasicBlock>, usize)
462458
{
463459
// extract the match-pair from the highest priority candidate
464-
let match_pair = &candidates.last().unwrap().match_pairs[0];
460+
let match_pair = &candidates.first().unwrap().match_pairs[0];
465461
let mut test = self.test(match_pair);
466462

467463
// most of the time, the test to perform is simply a function
@@ -470,7 +466,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
470466
// available
471467
match test.kind {
472468
TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
473-
for candidate in candidates.iter().rev() {
469+
for candidate in candidates.iter() {
474470
if !self.add_cases_to_switch(&match_pair.lvalue,
475471
candidate,
476472
switch_ty,
@@ -497,7 +493,6 @@ impl<'a,'tcx> Builder<'a,'tcx> {
497493
// that point, we stop sorting.
498494
let tested_candidates =
499495
candidates.iter()
500-
.rev()
501496
.take_while(|c| self.sort_candidate(&match_pair.lvalue,
502497
&test,
503498
c,
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2015 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+
// #30527 - We were not generating arms with guards in certain cases.
12+
13+
#![feature(rustc_attrs)]
14+
15+
#[rustc_mir]
16+
fn match_with_guard(x: Option<i8>) -> i8 {
17+
match x {
18+
Some(xyz) if xyz > 100 => 0,
19+
Some(_) => -1,
20+
None => -2
21+
}
22+
}
23+
24+
fn main() {
25+
assert_eq!(match_with_guard(Some(111)), 0);
26+
assert_eq!(match_with_guard(Some(2)), -1);
27+
assert_eq!(match_with_guard(None), -2);
28+
}

0 commit comments

Comments
 (0)