diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index a5a15cfe66e6d..34c8b5d4139fc 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -79,8 +79,11 @@ use core::cmp::Ordering; use core::mem::{align_of_val, size_of_val}; use core::intrinsics::abort; use core::mem; -use core::ops::{Deref, CoerceUnsized}; +use core::ops::Deref; +#[cfg(not(stage0))] +use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; +#[cfg(not(stage0))] use core::marker::Unsize; use core::hash::{Hash, Hasher}; use core::{usize, isize}; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 672b63eda67c7..b94e74ada9cef 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -161,9 +161,13 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{Hasher, Hash}; use core::intrinsics::{assume, abort}; -use core::marker::{self, Unsize}; +use core::marker; +#[cfg(not(stage0))] +use core::marker::Unsize; use core::mem::{self, align_of_val, size_of_val, forget}; -use core::ops::{CoerceUnsized, Deref}; +use core::ops::Deref; +#[cfg(not(stage0))] +use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; use heap::deallocate; diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c111ea8dce667..71219155cc39f 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -456,7 +456,7 @@ impl Result { // Transforming contained values ///////////////////////////////////////////////////////////////////////// - /// Maps a `Result` to `Result` by applying a function to an + /// Maps a `Result` to `Result` by applying a function to a /// contained `Ok` value, leaving an `Err` value untouched. /// /// This function can be used to compose the results of two functions. @@ -484,7 +484,7 @@ impl Result { } } - /// Maps a `Result` to `Result` by applying a function to an + /// Maps a `Result` to `Result` by applying a function to a /// contained `Err` value, leaving an `Ok` value untouched. /// /// This function can be used to pass through a successful result while handling diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 4eda6961a1921..cc8549de26a6c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -85,7 +85,15 @@ impl<'a,'tcx> Builder<'a,'tcx> { // this will generate code to test discriminant_lvalue and // branch to the appropriate arm block - self.match_candidates(span, &mut arm_blocks, candidates, block); + let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block); + + // because all matches are exhaustive, in principle we expect + // an empty vector to be returned here, but the algorithm is + // not entirely precise + if !otherwise.is_empty() { + let join_block = self.join_otherwise_blocks(otherwise); + self.panic(join_block); + } // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); @@ -279,11 +287,32 @@ struct Test<'tcx> { // Main matching algorithm impl<'a,'tcx> Builder<'a,'tcx> { + /// The main match algorithm. It begins with a set of candidates + /// `candidates` and has the job of generating code to determine + /// which of these candidates, if any, is the correct one. The + /// candidates are sorted in inverse priority -- so the last item + /// in the list has highest priority. When a candidate is found to + /// match the value, we will generate a branch to the appropriate + /// block found in `arm_blocks`. + /// + /// The return value is a list of "otherwise" blocks. These are + /// points in execution where we found that *NONE* of the + /// candidates apply. In principle, this means that the input + /// list was not exhaustive, though at present we sometimes are + /// not smart enough to recognize all exhaustive inputs. + /// + /// It might be surprising that the input can be inexhaustive. + /// Indeed, initially, it is not, because all matches are + /// exhaustive in Rust. But during processing we sometimes divide + /// up the list of candidates and recurse with a non-exhaustive + /// list. This is important to keep the size of the generated code + /// under control. See `test_candidates` for more details. fn match_candidates<'pat>(&mut self, span: Span, arm_blocks: &mut ArmBlocks, mut candidates: Vec>, mut block: BasicBlock) + -> Vec { debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})", span, block, candidates); @@ -311,17 +340,127 @@ impl<'a,'tcx> Builder<'a,'tcx> { } else { // if None is returned, then any remaining candidates // are unreachable (at least not through this path). - return; + return vec![]; } } // If there are no candidates that still need testing, we're done. // Since all matches are exhaustive, execution should never reach this point. if candidates.is_empty() { - return self.panic(block); + return vec![block]; + } + + // Test candidates where possible. + let (otherwise, tested_candidates) = + self.test_candidates(span, arm_blocks, &candidates, block); + + // If the target candidates were exhaustive, then we are done. + if otherwise.is_empty() { + return vec![]; + } + + // If all candidates were sorted into `target_candidates` somewhere, then + // the initial set was inexhaustive. + let untested_candidates = candidates.len() - tested_candidates; + if untested_candidates == 0 { + return otherwise; } - // otherwise, extract the next match pair and construct tests + // Otherwise, let's process those remaining candidates. + let join_block = self.join_otherwise_blocks(otherwise); + candidates.truncate(untested_candidates); + self.match_candidates(span, arm_blocks, candidates, join_block) + } + + fn join_otherwise_blocks(&mut self, + otherwise: Vec) + -> BasicBlock + { + if otherwise.len() == 1 { + otherwise[0] + } else { + let join_block = self.cfg.start_new_block(); + for block in otherwise { + self.cfg.terminate(block, Terminator::Goto { target: join_block }); + } + join_block + } + } + + /// This is the most subtle part of the matching algorithm. At + /// this point, the input candidates have been fully simplified, + /// and so we know that all remaining match-pairs require some + /// sort of test. To decide what test to do, we take the highest + /// priority candidate (last one in the list) and extract the + /// first match-pair from the list. From this we decide what kind + /// of test is needed using `test`, defined in the `test` module. + /// + /// *Note:* taking the first match pair is somewhat arbitrary, and + /// we might do better here by choosing more carefully what to + /// test. + /// + /// For example, consider the following possible match-pairs: + /// + /// 1. `x @ Some(P)` -- we will do a `Switch` to decide what variant `x` has + /// 2. `x @ 22` -- we will do a `SwitchInt` + /// 3. `x @ 3..5` -- we will do a range test + /// 4. etc. + /// + /// Once we know what sort of test we are going to perform, this + /// test may also help us with other candidates. So we walk over + /// the candidates (from high to low priority) and check. This + /// gives us, for each outcome of the test, a transformed list of + /// candidates. For example, if we are testing the current + /// variant of `x.0`, and we have a candidate `{x.0 @ Some(v), x.1 + /// @ 22}`, then we would have a resulting candidate of `{(x.0 as + /// Some).0 @ v, x.1 @ 22}`. Note that the first match-pair is now + /// simpler (and, in fact, irrefutable). + /// + /// But there may also be candidates that the test just doesn't + /// apply to. For example, consider the case of #29740: + /// + /// ```rust + /// match x { + /// "foo" => ..., + /// "bar" => ..., + /// "baz" => ..., + /// _ => ..., + /// } + /// ``` + /// + /// Here the match-pair we are testing will be `x @ "foo"`, and we + /// will generate an `Eq` test. Because `"bar"` and `"baz"` are different + /// constants, we will decide that these later candidates are just not + /// informed by the eq test. So we'll wind up with three candidate sets: + /// + /// - If outcome is that `x == "foo"` (one candidate, derived from `x @ "foo"`) + /// - If outcome is that `x != "foo"` (empty list of candidates) + /// - Otherwise (three candidates, `x @ "bar"`, `x @ "baz"`, `x @ + /// _`). Here we have the invariant that everything in the + /// otherwise list is of **lower priority** than the stuff in the + /// other lists. + /// + /// So we'll compile the test. For each outcome of the test, we + /// recursively call `match_candidates` with the corresponding set + /// of candidates. But note that this set is now inexhaustive: for + /// example, in the case where the test returns false, there are + /// NO candidates, even though there is stll a value to be + /// matched. So we'll collect the return values from + /// `match_candidates`, which are the blocks where control-flow + /// goes if none of the candidates matched. At this point, we can + /// continue with the "otherwise" list. + /// + /// If you apply this to the above test, you basically wind up + /// with an if-else-if chain, testing each candidate in turn, + /// which is precisely what we want. + fn test_candidates<'pat>(&mut self, + span: Span, + arm_blocks: &mut ArmBlocks, + candidates: &[Candidate<'pat, 'tcx>], + block: BasicBlock) + -> (Vec, usize) + { + // extract the match-pair from the highest priority candidate let match_pair = &candidates.last().unwrap().match_pairs[0]; let mut test = self.test(match_pair); @@ -331,35 +470,57 @@ impl<'a,'tcx> Builder<'a,'tcx> { // available match test.kind { TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => { - for candidate in &candidates { - self.add_cases_to_switch(&match_pair.lvalue, - candidate, - switch_ty, - options, - indices); + for candidate in candidates.iter().rev() { + if !self.add_cases_to_switch(&match_pair.lvalue, + candidate, + switch_ty, + options, + indices) { + break; + } } } _ => { } } + // perform the test, branching to one of N blocks. For each of + // those N possible outcomes, create a (initially empty) + // vector of candidates. Those are the candidates that still + // apply if the test has that particular outcome. debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair); let target_blocks = self.perform_test(block, &match_pair.lvalue, &test); - let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect(); - for candidate in &candidates { - self.sort_candidate(&match_pair.lvalue, - &test, - candidate, - &mut target_candidates); - } - - for (target_block, target_candidates) in + // Sort the candidates into the appropriate vector in + // `target_candidates`. Note that at some point we may + // encounter a candidate where the test is not relevant; at + // that point, we stop sorting. + let tested_candidates = + candidates.iter() + .rev() + .take_while(|c| self.sort_candidate(&match_pair.lvalue, + &test, + c, + &mut target_candidates)) + .count(); + assert!(tested_candidates > 0); // at least the last candidate ought to be tested + + // For each outcome of test, process the candidates that still + // apply. Collect a list of blocks where control flow will + // branch if one of the `target_candidate` sets is not + // exhaustive. + let otherwise: Vec<_> = target_blocks.into_iter() - .zip(target_candidates.into_iter()) - { - self.match_candidates(span, arm_blocks, target_candidates, target_block); - } + .zip(target_candidates) + .flat_map(|(target_block, target_candidates)| { + self.match_candidates(span, + arm_blocks, + target_candidates, + target_block) + }) + .collect(); + + (otherwise, tested_candidates) } /// Initializes each of the bindings from the candidate by diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 312ab61ba6cec..dffd83f1c4150 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -105,10 +105,11 @@ impl<'a,'tcx> Builder<'a,'tcx> { switch_ty: Ty<'tcx>, options: &mut Vec, indices: &mut FnvHashMap) + -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { Some(match_pair) => match_pair, - _ => { return; } + _ => { return false; } }; match *match_pair.pattern.kind { @@ -121,11 +122,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { options.push(value.clone()); options.len() - 1 }); + true } - PatternKind::Range { .. } => { - } - + PatternKind::Range { .. } | PatternKind::Constant { .. } | PatternKind::Variant { .. } | PatternKind::Slice { .. } | @@ -134,6 +134,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { PatternKind::Binding { .. } | PatternKind::Leaf { .. } | PatternKind::Deref { .. } => { + // don't know how to add these patterns to a switch + false } } } @@ -284,18 +286,29 @@ impl<'a,'tcx> Builder<'a,'tcx> { /// P0` to the `resulting_candidates` entry corresponding to the /// variant `Some`. /// - /// In many cases we will add the `candidate` to more than one - /// outcome. For example, say that the test is `x == 22`, but the - /// candidate is `x @ 13..55`. In that case, if the test is true, - /// then we know that the candidate applies (without this match - /// pair, potentially, though we don't optimize this due to - /// #29623). If the test is false, the candidate may also apply - /// (with the match pair, still). + /// However, in some cases, the test may just not be relevant to + /// candidate. For example, suppose we are testing whether `foo.x == 22`, + /// but in one match arm we have `Foo { x: _, ... }`... in that case, + /// the test for what value `x` has has no particular relevance + /// to this candidate. In such cases, this function just returns false + /// without doing anything. This is used by the overall `match_candidates` + /// algorithm to structure the match as a whole. See `match_candidates` for + /// more details. + /// + /// FIXME(#29623). In some cases, we have some tricky choices to + /// make. for example, if we are testing that `x == 22`, but the + /// candidate is `x @ 13..55`, what should we do? In the event + /// that the test is true, we know that the candidate applies, but + /// in the event of false, we don't know that it *doesn't* + /// apply. For now, we return false, indicate that the test does + /// not apply to this candidate, but it might be we can get + /// tighter match code if we do something a bit different. pub fn sort_candidate<'pat>(&mut self, test_lvalue: &Lvalue<'tcx>, test: &Test<'tcx>, candidate: &Candidate<'pat, 'tcx>, - resulting_candidates: &mut [Vec>]) { + resulting_candidates: &mut [Vec>]) + -> bool { // Find the match_pair for this lvalue (if any). At present, // afaik, there can be at most one. (In the future, if we // adopted a more general `@` operator, there might be more @@ -311,7 +324,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { None => { // We are not testing this lvalue. Therefore, this // candidate applies to ALL outcomes. - return self.add_to_all_candidate_sets(candidate, resulting_candidates); + return false; } }; @@ -329,9 +342,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { subpatterns, candidate); resulting_candidates[variant_index].push(new_candidate); + true } _ => { - self.add_to_all_candidate_sets(candidate, resulting_candidates); + false } } } @@ -349,9 +363,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { let new_candidate = self.candidate_without_match_pair(match_pair_index, candidate); resulting_candidates[index].push(new_candidate); + true } _ => { - self.add_to_all_candidate_sets(candidate, resulting_candidates); + false } } } @@ -367,8 +382,9 @@ impl<'a,'tcx> Builder<'a,'tcx> { let new_candidate = self.candidate_without_match_pair(match_pair_index, candidate); resulting_candidates[0].push(new_candidate); + true } else { - self.add_to_all_candidate_sets(candidate, resulting_candidates); + false } } } @@ -392,14 +408,6 @@ impl<'a,'tcx> Builder<'a,'tcx> { } } - fn add_to_all_candidate_sets<'pat>(&mut self, - candidate: &Candidate<'pat, 'tcx>, - resulting_candidates: &mut [Vec>]) { - for resulting_candidate in resulting_candidates { - resulting_candidate.push(candidate.clone()); - } - } - fn candidate_after_variant_switch<'pat>(&mut self, match_pair_index: usize, adt_def: ty::AdtDef<'tcx>, @@ -447,5 +455,5 @@ impl<'a,'tcx> Builder<'a,'tcx> { } fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool { - ty.is_integral() || ty.is_char() + ty.is_integral() || ty.is_char() || ty.is_bool() } diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 08227cfb35322..bda4cdfb43733 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -10,119 +10,136 @@ //! The Rust Prelude //! -//! Because `std` is required by most serious Rust software, it is -//! imported at the topmost level of every crate by default, as if -//! each crate contains the following: +//! Rust comes with a variety of things in its standard library. However, if +//! you had to manually import every single thing that you used, it would be +//! very verbose. But importing a lot of things that a program never uses isn't +//! good either. A balance needs to be struck. +//! +//! The *prelude* is the list of things that Rust automatically imports into +//! every Rust program. It's kept as small as possible, and is focused on +//! things, particuarly traits, which are used in almost every single Rust +//! program. +//! +//! On a technical level, Rust inserts //! //! ```ignore //! extern crate std; //! ``` //! -//! This means that the contents of std can be accessed from any context -//! with the `std::` path prefix, as in `use std::vec`, `use std::thread::spawn`, -//! etc. -//! -//! Additionally, `std` contains a versioned *prelude* that reexports many of the -//! most common traits, types, and functions. *The contents of the prelude are -//! imported into every module by default*. Implicitly, all modules behave as if -//! they contained the following [`use` statement][book-use]: -//! -//! [book-use]: ../../book/crates-and-modules.html#importing-modules-with-use +//! into the crate root of every crate, and //! //! ```ignore //! use std::prelude::v1::*; //! ``` //! -//! The prelude is primarily concerned with exporting *traits* that -//! are so pervasive that they would be onerous to import for every use, -//! particularly those that are commonly mentioned in [generic type -//! bounds][book-traits]. +//! into every module. +//! +//! # Other preludes +//! +//! Preludes can be seen as a pattern to make using multiple types more +//! convenient. As such, you'll find other preludes in the standard library, +//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may +//! also define their own preludes. +//! +//! [`std::io::prelude`]: ../io/prelude/index.html +//! +//! The differece between 'the prelude' and these other preludes is that they +//! are not automatically `use`'d, and must be imported manually. This is still +//! easier than importing all of their consitutent components. +//! +//! # Prelude contents //! //! The current version of the prelude (version 1) lives in -//! [`std::prelude::v1`](v1/index.html), and reexports the following. +//! [`std::prelude::v1`], and reexports the following. //! -//! * `std::marker::`{ -//! [`Copy`](../marker/trait.Copy.html), -//! [`Send`](../marker/trait.Send.html), -//! [`Sized`](../marker/trait.Sized.html), -//! [`Sync`](../marker/trait.Sync.html) -//! }. -//! The marker traits indicate fundamental properties of types. -//! * `std::ops::`{ -//! [`Drop`](../ops/trait.Drop.html), -//! [`Fn`](../ops/trait.Fn.html), -//! [`FnMut`](../ops/trait.FnMut.html), -//! [`FnOnce`](../ops/trait.FnOnce.html) -//! }. -//! The [destructor][book-dtor] trait and the -//! [closure][book-closures] traits, reexported from the same -//! [module that also defines overloaded -//! operators](../ops/index.html). -//! * `std::mem::`[`drop`](../mem/fn.drop.html). -//! A convenience function for explicitly dropping a value. -//! * `std::boxed::`[`Box`](../boxed/struct.Box.html). -//! The owned heap pointer. -//! * `std::borrow::`[`ToOwned`](../borrow/trait.ToOwned.html). -//! The conversion trait that defines `to_owned`, the generic method -//! for creating an owned type from a borrowed type. -//! * `std::clone::`[`Clone`](../clone/trait.Clone.html). -//! The ubiquitous trait that defines `clone`, the method for -//! producing copies of values that are consider expensive to copy. -//! * `std::cmp::`{ -//! [`PartialEq`](../cmp/trait.PartialEq.html), -//! [`PartialOrd`](../cmp/trait.PartialOrd.html), -//! [`Eq`](../cmp/trait.Eq.html), -//! [`Ord`](../cmp/trait.Ord.html) -//! }. -//! The comparison traits, which implement the comparison operators -//! and are often seen in trait bounds. -//! * `std::convert::`{ -//! [`AsRef`](../convert/trait.AsRef.html), -//! [`AsMut`](../convert/trait.AsMut.html), -//! [`Into`](../convert/trait.Into.html), -//! [`From`](../convert/trait.From.html) -//! }. -//! Generic conversions, used by savvy API authors to create -//! overloaded methods. -//! * `std::default::`[`Default`](../default/trait.Default.html). -//! Types that have default values. -//! * `std::iter::`{ -//! [`Iterator`](../iter/trait.Iterator.html), -//! [`Extend`](../iter/trait.Extend.html), -//! [`IntoIterator`](../iter/trait.IntoIterator.html), -//! [`DoubleEndedIterator`](../iter/trait.DoubleEndedIterator.html), -//! [`ExactSizeIterator`](../iter/trait.ExactSizeIterator.html) -//! }. -//! [Iterators][book-iter]. -//! * `std::option::Option::`{ -//! [`self`](../option/enum.Option.html), -//! [`Some`](../option/enum.Option.html), -//! [`None`](../option/enum.Option.html) -//! }. -//! The ubiquitous `Option` type and its two [variants][book-enums], -//! `Some` and `None`. -//! * `std::result::Result::`{ -//! [`self`](../result/enum.Result.html), -//! [`Ok`](../result/enum.Result.html), -//! [`Err`](../result/enum.Result.html) -//! }. -//! The ubiquitous `Result` type and its two [variants][book-enums], -//! `Ok` and `Err`. -//! * `std::slice::`[`SliceConcatExt`](../slice/trait.SliceConcatExt.html). -//! An unstable extension to slices that shouldn't have to exist. -//! * `std::string::`{ -//! [`String`](../string/struct.String.html), -//! [`ToString`](../string/trait.ToString.html) -//! }. -//! Heap allocated strings. -//! * `std::vec::`[`Vec`](../vec/struct.Vec.html). -//! Heap allocated vectors. +//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`]}. The marker +//! traits indicate fundamental properties of types. +//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various +//! operations for both destuctors and overloading `()`. +//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a +//! value. +//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. +//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines +//! [`to_owned()`], the generic method for creating an owned type from a +//! borrowed type. +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`], +//! the method for producing a copy of a value. +//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The +//! comparison traits, which implement the comparison operators and are often +//! seen in trait bounds. +//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic +//! conversions, used by savvy API authors to create overloaded methods. +//! * [`std::default`]::[`Default`], types that have default values. +//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`], +//! [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various +//! kinds. +//! * [`std::option`]::[`Option`]::{`self`, `Some`, `None`}. A type which +//! expresses the presence or absence of a value. This type is so commonly +//! used, its variants are also exported. +//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions +//! that may succeed or fail. Like [`Option`], its variants are exported as +//! well. +//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical +//! reasons, but shouldn't have to exist. It provides a few useful methods on +//! slices. +//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings. +//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated +//! vector. //! -//! [book-traits]: ../../book/traits.html +//! [`AsMut`]: ../convert/trait.AsMut.html +//! [`AsRef`]: ../convert/trait.AsRef.html +//! [`Box`]: ../boxed/struct.Box.html +//! [`Clone`]: ../clone/trait.Clone.html +//! [`Copy`]: ../marker/trait.Copy.html +//! [`Default`]: ../default/trait.Default.html +//! [`DoubleEndedIterator`]: ../iter/trait.DoubleEndedIterator.html +//! [`Drop`]: ../ops/trait.Drop.html +//! [`Eq`]: ../cmp/trait.Eq.html +//! [`ExactSizeIterator`]: ../iter/trait.ExactSizeIterator.html +//! [`Extend`]: ../iter/trait.Extend.html +//! [`FnMut`]: ../ops/trait.FnMut.html +//! [`FnOnce`]: ../ops/trait.FnOnce.html +//! [`Fn`]: ../ops/trait.Fn.html +//! [`From`]: ../convert/trait.From.html +//! [`IntoIterator`]: ../iter/trait.IntoIterator.html +//! [`Into`]: ../convert/trait.Into.html +//! [`Iterator`]: ../iter/trait.Iterator.html +//! [`Option`]: ../option/enum.Option.html +//! [`Ord`]: ../cmp/trait.Ord.html +//! [`PartialEq`]: ../cmp/trait.PartialEq.html +//! [`PartialOrd`]: ../cmp/trait.PartialOrd.html +//! [`Result`]: ../result/enum.Result.html +//! [`Send`]: ../marker/trait.Send.html +//! [`Sized`]: ../marker/trait.Sized.html +//! [`SliceConcatExt`]: ../slice/trait.SliceConcatExt.html +//! [`String`]: ../string/struct.String.html +//! [`Sync`]: ../marker/trait.Sync.html +//! [`ToOwned`]: ../borrow/trait.ToOwned.html +//! [`ToString`]: ../string/trait.ToString.html +//! [`Vec`]: ../vec/struct.Vec.html +//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone +//! [`drop`]: ../mem/fn.drop.html +//! [`std::borrow`]: ../borrow/index.html +//! [`std::boxed`]: ../boxed/index.html +//! [`std::clone`]: ../clone/index.html +//! [`std::cmp`]: ../cmp/index.html +//! [`std::convert`]: ../convert/index.html +//! [`std::default`]: ../default/index.html +//! [`std::iter`]: ../iter/index.html +//! [`std::marker`]: ../marker/index.html +//! [`std::mem`]: ../mem/index.html +//! [`std::ops`]: ../ops/index.html +//! [`std::option`]: ../option/index.html +//! [`std::prelude::v1`]: v1/index.html +//! [`std::result`]: ../result/index.html +//! [`std::slice`]: ../slice/index.html +//! [`std::string`]: ../string/index.html +//! [`std::vec`]: ../vec/index.html +//! [`to_owned()`]: ../borrow/trait.ToOwned.html#tymethod.to_owned //! [book-closures]: ../../book/closures.html //! [book-dtor]: ../../book/drop.html -//! [book-iter]: ../../book/iterators.html //! [book-enums]: ../../book/enums.html +//! [book-iter]: ../../book/iterators.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 46c0103e08764..9ca5b445c86a9 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -9,6 +9,8 @@ // except according to those terms. //! The first version of the prelude of The Rust Standard Library. +//! +//! See the [module-level documentation](../index.html) for more. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/run-pass/issue-29740.rs b/src/test/run-pass/issue-29740.rs new file mode 100644 index 0000000000000..75bcd431ec8e1 --- /dev/null +++ b/src/test/run-pass/issue-29740.rs @@ -0,0 +1,326 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #29740. Inefficient MIR matching algorithms +// generated way too much code for this sort of case, leading to OOM. + +// ignore-pretty + +pub mod KeyboardEventConstants { + pub const DOM_KEY_LOCATION_STANDARD: u32 = 0; + pub const DOM_KEY_LOCATION_LEFT: u32 = 1; + pub const DOM_KEY_LOCATION_RIGHT: u32 = 2; + pub const DOM_KEY_LOCATION_NUMPAD: u32 = 3; +} // mod KeyboardEventConstants + +pub enum Key { + Space, + Apostrophe, + Comma, + Minus, + Period, + Slash, + Num0, + Num1, + Num2, + Num3, + Num4, + Num5, + Num6, + Num7, + Num8, + Num9, + Semicolon, + Equal, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + LeftBracket, + Backslash, + RightBracket, + GraveAccent, + World1, + World2, + + Escape, + Enter, + Tab, + Backspace, + Insert, + Delete, + Right, + Left, + Down, + Up, + PageUp, + PageDown, + Home, + End, + CapsLock, + ScrollLock, + NumLock, + PrintScreen, + Pause, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + F25, + Kp0, + Kp1, + Kp2, + Kp3, + Kp4, + Kp5, + Kp6, + Kp7, + Kp8, + Kp9, + KpDecimal, + KpDivide, + KpMultiply, + KpSubtract, + KpAdd, + KpEnter, + KpEqual, + LeftShift, + LeftControl, + LeftAlt, + LeftSuper, + RightShift, + RightControl, + RightAlt, + RightSuper, + Menu, +} + +fn key_from_string(key_string: &str, location: u32) -> Option { + match key_string { + " " => Some(Key::Space), + "\"" => Some(Key::Apostrophe), + "'" => Some(Key::Apostrophe), + "<" => Some(Key::Comma), + "," => Some(Key::Comma), + "_" => Some(Key::Minus), + "-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Minus), + ">" => Some(Key::Period), + "." if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Period), + "?" => Some(Key::Slash), + "/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Slash), + "~" => Some(Key::GraveAccent), + "`" => Some(Key::GraveAccent), + ")" => Some(Key::Num0), + "0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num0), + "!" => Some(Key::Num1), + "1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num1), + "@" => Some(Key::Num2), + "2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num2), + "#" => Some(Key::Num3), + "3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num3), + "$" => Some(Key::Num4), + "4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num4), + "%" => Some(Key::Num5), + "5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num5), + "^" => Some(Key::Num6), + "6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num6), + "&" => Some(Key::Num7), + "7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num7), + "*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8), + "8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8), + "(" => Some(Key::Num9), + "9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num9), + ":" => Some(Key::Semicolon), + ";" => Some(Key::Semicolon), + "+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal), + "=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal), + "A" => Some(Key::A), + "a" => Some(Key::A), + "B" => Some(Key::B), + "b" => Some(Key::B), + "C" => Some(Key::C), + "c" => Some(Key::C), + "D" => Some(Key::D), + "d" => Some(Key::D), + "E" => Some(Key::E), + "e" => Some(Key::E), + "F" => Some(Key::F), + "f" => Some(Key::F), + "G" => Some(Key::G), + "g" => Some(Key::G), + "H" => Some(Key::H), + "h" => Some(Key::H), + "I" => Some(Key::I), + "i" => Some(Key::I), + "J" => Some(Key::J), + "j" => Some(Key::J), + "K" => Some(Key::K), + "k" => Some(Key::K), + "L" => Some(Key::L), + "l" => Some(Key::L), + "M" => Some(Key::M), + "m" => Some(Key::M), + "N" => Some(Key::N), + "n" => Some(Key::N), + "O" => Some(Key::O), + "o" => Some(Key::O), + "P" => Some(Key::P), + "p" => Some(Key::P), + "Q" => Some(Key::Q), + "q" => Some(Key::Q), + "R" => Some(Key::R), + "r" => Some(Key::R), + "S" => Some(Key::S), + "s" => Some(Key::S), + "T" => Some(Key::T), + "t" => Some(Key::T), + "U" => Some(Key::U), + "u" => Some(Key::U), + "V" => Some(Key::V), + "v" => Some(Key::V), + "W" => Some(Key::W), + "w" => Some(Key::W), + "X" => Some(Key::X), + "x" => Some(Key::X), + "Y" => Some(Key::Y), + "y" => Some(Key::Y), + "Z" => Some(Key::Z), + "z" => Some(Key::Z), + "{" => Some(Key::LeftBracket), + "[" => Some(Key::LeftBracket), + "|" => Some(Key::Backslash), + "\\" => Some(Key::Backslash), + "}" => Some(Key::RightBracket), + "]" => Some(Key::RightBracket), + "Escape" => Some(Key::Escape), + "Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD + => Some(Key::Enter), + "Tab" => Some(Key::Tab), + "Backspace" => Some(Key::Backspace), + "Insert" => Some(Key::Insert), + "Delete" => Some(Key::Delete), + "ArrowRight" => Some(Key::Right), + "ArrowLeft" => Some(Key::Left), + "ArrowDown" => Some(Key::Down), + "ArrowUp" => Some(Key::Up), + "PageUp" => Some(Key::PageUp), + "PageDown" => Some(Key::PageDown), + "Home" => Some(Key::Home), + "End" => Some(Key::End), + "CapsLock" => Some(Key::CapsLock), + "ScrollLock" => Some(Key::ScrollLock), + "NumLock" => Some(Key::NumLock), + "PrintScreen" => Some(Key::PrintScreen), + "Pause" => Some(Key::Pause), + "F1" => Some(Key::F1), + "F2" => Some(Key::F2), + "F3" => Some(Key::F3), + "F4" => Some(Key::F4), + "F5" => Some(Key::F5), + "F6" => Some(Key::F6), + "F7" => Some(Key::F7), + "F8" => Some(Key::F8), + "F9" => Some(Key::F9), + "F10" => Some(Key::F10), + "F11" => Some(Key::F11), + "F12" => Some(Key::F12), + "F13" => Some(Key::F13), + "F14" => Some(Key::F14), + "F15" => Some(Key::F15), + "F16" => Some(Key::F16), + "F17" => Some(Key::F17), + "F18" => Some(Key::F18), + "F19" => Some(Key::F19), + "F20" => Some(Key::F20), + "F21" => Some(Key::F21), + "F22" => Some(Key::F22), + "F23" => Some(Key::F23), + "F24" => Some(Key::F24), + "F25" => Some(Key::F25), + "0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp0), + "1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp1), + "2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp2), + "3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp3), + "4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp4), + "5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp5), + "6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp6), + "7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp7), + "8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp8), + "9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp9), + "." if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDecimal), + "/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDivide), + "*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpMultiply), + "-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpSubtract), + "+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpAdd), + "Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD + => Some(Key::KpEnter), + "=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEqual), + "Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT + => Some(Key::LeftShift), + "Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT + => Some(Key::LeftControl), + "Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftAlt), + "Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT + => Some(Key::LeftSuper), + "Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT + => Some(Key::RightShift), + "Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT + => Some(Key::RightControl), + "Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightAlt), + "Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT + => Some(Key::RightSuper), + "ContextMenu" => Some(Key::Menu), + _ => None + } +} + +fn main() { }