Skip to content

Commit afd4a54

Browse files
committed
Auto merge of #29795 - Manishearth:rollup, r=Manishearth
- Successful merges: #29776, #29785, #29786, #29787 - Failed merges:
2 parents 3bd622f + d1d573d commit afd4a54

File tree

8 files changed

+670
-149
lines changed

8 files changed

+670
-149
lines changed

src/liballoc/arc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ use core::cmp::Ordering;
7979
use core::mem::{align_of_val, size_of_val};
8080
use core::intrinsics::abort;
8181
use core::mem;
82-
use core::ops::{Deref, CoerceUnsized};
82+
use core::ops::Deref;
83+
#[cfg(not(stage0))]
84+
use core::ops::CoerceUnsized;
8385
use core::ptr::{self, Shared};
86+
#[cfg(not(stage0))]
8487
use core::marker::Unsize;
8588
use core::hash::{Hash, Hasher};
8689
use core::{usize, isize};

src/liballoc/rc.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,13 @@ use core::cmp::Ordering;
161161
use core::fmt;
162162
use core::hash::{Hasher, Hash};
163163
use core::intrinsics::{assume, abort};
164-
use core::marker::{self, Unsize};
164+
use core::marker;
165+
#[cfg(not(stage0))]
166+
use core::marker::Unsize;
165167
use core::mem::{self, align_of_val, size_of_val, forget};
166-
use core::ops::{CoerceUnsized, Deref};
168+
use core::ops::Deref;
169+
#[cfg(not(stage0))]
170+
use core::ops::CoerceUnsized;
167171
use core::ptr::{self, Shared};
168172

169173
use heap::deallocate;

src/libcore/result.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ impl<T, E> Result<T, E> {
456456
// Transforming contained values
457457
/////////////////////////////////////////////////////////////////////////
458458

459-
/// Maps a `Result<T, E>` to `Result<U, E>` by applying a function to an
459+
/// Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a
460460
/// contained `Ok` value, leaving an `Err` value untouched.
461461
///
462462
/// This function can be used to compose the results of two functions.
@@ -484,7 +484,7 @@ impl<T, E> Result<T, E> {
484484
}
485485
}
486486

487-
/// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to an
487+
/// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a
488488
/// contained `Err` value, leaving an `Ok` value untouched.
489489
///
490490
/// This function can be used to pass through a successful result while handling

src/librustc_mir/build/matches/mod.rs

+184-23
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
8585

8686
// this will generate code to test discriminant_lvalue and
8787
// branch to the appropriate arm block
88-
self.match_candidates(span, &mut arm_blocks, candidates, block);
88+
let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block);
89+
90+
// because all matches are exhaustive, in principle we expect
91+
// an empty vector to be returned here, but the algorithm is
92+
// not entirely precise
93+
if !otherwise.is_empty() {
94+
let join_block = self.join_otherwise_blocks(otherwise);
95+
self.panic(join_block);
96+
}
8997

9098
// all the arm blocks will rejoin here
9199
let end_block = self.cfg.start_new_block();
@@ -279,11 +287,32 @@ struct Test<'tcx> {
279287
// Main matching algorithm
280288

281289
impl<'a,'tcx> Builder<'a,'tcx> {
290+
/// The main match algorithm. It begins with a set of candidates
291+
/// `candidates` and has the job of generating code to determine
292+
/// 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
296+
/// block found in `arm_blocks`.
297+
///
298+
/// The return value is a list of "otherwise" blocks. These are
299+
/// points in execution where we found that *NONE* of the
300+
/// candidates apply. In principle, this means that the input
301+
/// list was not exhaustive, though at present we sometimes are
302+
/// not smart enough to recognize all exhaustive inputs.
303+
///
304+
/// It might be surprising that the input can be inexhaustive.
305+
/// Indeed, initially, it is not, because all matches are
306+
/// exhaustive in Rust. But during processing we sometimes divide
307+
/// up the list of candidates and recurse with a non-exhaustive
308+
/// list. This is important to keep the size of the generated code
309+
/// under control. See `test_candidates` for more details.
282310
fn match_candidates<'pat>(&mut self,
283311
span: Span,
284312
arm_blocks: &mut ArmBlocks,
285313
mut candidates: Vec<Candidate<'pat, 'tcx>>,
286314
mut block: BasicBlock)
315+
-> Vec<BasicBlock>
287316
{
288317
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
289318
span, block, candidates);
@@ -311,17 +340,127 @@ impl<'a,'tcx> Builder<'a,'tcx> {
311340
} else {
312341
// if None is returned, then any remaining candidates
313342
// are unreachable (at least not through this path).
314-
return;
343+
return vec![];
315344
}
316345
}
317346

318347
// If there are no candidates that still need testing, we're done.
319348
// Since all matches are exhaustive, execution should never reach this point.
320349
if candidates.is_empty() {
321-
return self.panic(block);
350+
return vec![block];
351+
}
352+
353+
// Test candidates where possible.
354+
let (otherwise, tested_candidates) =
355+
self.test_candidates(span, arm_blocks, &candidates, block);
356+
357+
// If the target candidates were exhaustive, then we are done.
358+
if otherwise.is_empty() {
359+
return vec![];
360+
}
361+
362+
// If all candidates were sorted into `target_candidates` somewhere, then
363+
// the initial set was inexhaustive.
364+
let untested_candidates = candidates.len() - tested_candidates;
365+
if untested_candidates == 0 {
366+
return otherwise;
322367
}
323368

324-
// otherwise, extract the next match pair and construct tests
369+
// Otherwise, let's process those remaining candidates.
370+
let join_block = self.join_otherwise_blocks(otherwise);
371+
candidates.truncate(untested_candidates);
372+
self.match_candidates(span, arm_blocks, candidates, join_block)
373+
}
374+
375+
fn join_otherwise_blocks(&mut self,
376+
otherwise: Vec<BasicBlock>)
377+
-> BasicBlock
378+
{
379+
if otherwise.len() == 1 {
380+
otherwise[0]
381+
} else {
382+
let join_block = self.cfg.start_new_block();
383+
for block in otherwise {
384+
self.cfg.terminate(block, Terminator::Goto { target: join_block });
385+
}
386+
join_block
387+
}
388+
}
389+
390+
/// This is the most subtle part of the matching algorithm. At
391+
/// this point, the input candidates have been fully simplified,
392+
/// and so we know that all remaining match-pairs require some
393+
/// sort of test. To decide what test to do, we take the highest
394+
/// priority candidate (last one in the list) and extract the
395+
/// first match-pair from the list. From this we decide what kind
396+
/// of test is needed using `test`, defined in the `test` module.
397+
///
398+
/// *Note:* taking the first match pair is somewhat arbitrary, and
399+
/// we might do better here by choosing more carefully what to
400+
/// test.
401+
///
402+
/// For example, consider the following possible match-pairs:
403+
///
404+
/// 1. `x @ Some(P)` -- we will do a `Switch` to decide what variant `x` has
405+
/// 2. `x @ 22` -- we will do a `SwitchInt`
406+
/// 3. `x @ 3..5` -- we will do a range test
407+
/// 4. etc.
408+
///
409+
/// Once we know what sort of test we are going to perform, this
410+
/// test may also help us with other candidates. So we walk over
411+
/// the candidates (from high to low priority) and check. This
412+
/// gives us, for each outcome of the test, a transformed list of
413+
/// candidates. For example, if we are testing the current
414+
/// variant of `x.0`, and we have a candidate `{x.0 @ Some(v), x.1
415+
/// @ 22}`, then we would have a resulting candidate of `{(x.0 as
416+
/// Some).0 @ v, x.1 @ 22}`. Note that the first match-pair is now
417+
/// simpler (and, in fact, irrefutable).
418+
///
419+
/// But there may also be candidates that the test just doesn't
420+
/// apply to. For example, consider the case of #29740:
421+
///
422+
/// ```rust
423+
/// match x {
424+
/// "foo" => ...,
425+
/// "bar" => ...,
426+
/// "baz" => ...,
427+
/// _ => ...,
428+
/// }
429+
/// ```
430+
///
431+
/// Here the match-pair we are testing will be `x @ "foo"`, and we
432+
/// will generate an `Eq` test. Because `"bar"` and `"baz"` are different
433+
/// constants, we will decide that these later candidates are just not
434+
/// informed by the eq test. So we'll wind up with three candidate sets:
435+
///
436+
/// - If outcome is that `x == "foo"` (one candidate, derived from `x @ "foo"`)
437+
/// - If outcome is that `x != "foo"` (empty list of candidates)
438+
/// - Otherwise (three candidates, `x @ "bar"`, `x @ "baz"`, `x @
439+
/// _`). Here we have the invariant that everything in the
440+
/// otherwise list is of **lower priority** than the stuff in the
441+
/// other lists.
442+
///
443+
/// So we'll compile the test. For each outcome of the test, we
444+
/// recursively call `match_candidates` with the corresponding set
445+
/// of candidates. But note that this set is now inexhaustive: for
446+
/// example, in the case where the test returns false, there are
447+
/// NO candidates, even though there is stll a value to be
448+
/// matched. So we'll collect the return values from
449+
/// `match_candidates`, which are the blocks where control-flow
450+
/// goes if none of the candidates matched. At this point, we can
451+
/// continue with the "otherwise" list.
452+
///
453+
/// If you apply this to the above test, you basically wind up
454+
/// with an if-else-if chain, testing each candidate in turn,
455+
/// which is precisely what we want.
456+
fn test_candidates<'pat>(&mut self,
457+
span: Span,
458+
arm_blocks: &mut ArmBlocks,
459+
candidates: &[Candidate<'pat, 'tcx>],
460+
block: BasicBlock)
461+
-> (Vec<BasicBlock>, usize)
462+
{
463+
// extract the match-pair from the highest priority candidate
325464
let match_pair = &candidates.last().unwrap().match_pairs[0];
326465
let mut test = self.test(match_pair);
327466

@@ -331,35 +470,57 @@ impl<'a,'tcx> Builder<'a,'tcx> {
331470
// available
332471
match test.kind {
333472
TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
334-
for candidate in &candidates {
335-
self.add_cases_to_switch(&match_pair.lvalue,
336-
candidate,
337-
switch_ty,
338-
options,
339-
indices);
473+
for candidate in candidates.iter().rev() {
474+
if !self.add_cases_to_switch(&match_pair.lvalue,
475+
candidate,
476+
switch_ty,
477+
options,
478+
indices) {
479+
break;
480+
}
340481
}
341482
}
342483
_ => { }
343484
}
344485

486+
// perform the test, branching to one of N blocks. For each of
487+
// those N possible outcomes, create a (initially empty)
488+
// vector of candidates. Those are the candidates that still
489+
// apply if the test has that particular outcome.
345490
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
346491
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
347-
348492
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
349493

350-
for candidate in &candidates {
351-
self.sort_candidate(&match_pair.lvalue,
352-
&test,
353-
candidate,
354-
&mut target_candidates);
355-
}
356-
357-
for (target_block, target_candidates) in
494+
// Sort the candidates into the appropriate vector in
495+
// `target_candidates`. Note that at some point we may
496+
// encounter a candidate where the test is not relevant; at
497+
// that point, we stop sorting.
498+
let tested_candidates =
499+
candidates.iter()
500+
.rev()
501+
.take_while(|c| self.sort_candidate(&match_pair.lvalue,
502+
&test,
503+
c,
504+
&mut target_candidates))
505+
.count();
506+
assert!(tested_candidates > 0); // at least the last candidate ought to be tested
507+
508+
// For each outcome of test, process the candidates that still
509+
// apply. Collect a list of blocks where control flow will
510+
// branch if one of the `target_candidate` sets is not
511+
// exhaustive.
512+
let otherwise: Vec<_> =
358513
target_blocks.into_iter()
359-
.zip(target_candidates.into_iter())
360-
{
361-
self.match_candidates(span, arm_blocks, target_candidates, target_block);
362-
}
514+
.zip(target_candidates)
515+
.flat_map(|(target_block, target_candidates)| {
516+
self.match_candidates(span,
517+
arm_blocks,
518+
target_candidates,
519+
target_block)
520+
})
521+
.collect();
522+
523+
(otherwise, tested_candidates)
363524
}
364525

365526
/// Initializes each of the bindings from the candidate by

0 commit comments

Comments
 (0)