mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #29795 - Manishearth:rollup, r=Manishearth
- Successful merges: #29776, #29785, #29786, #29787 - Failed merges:
This commit is contained in:
commit
afd4a5420c
@ -79,8 +79,11 @@ use core::cmp::Ordering;
|
|||||||
use core::mem::{align_of_val, size_of_val};
|
use core::mem::{align_of_val, size_of_val};
|
||||||
use core::intrinsics::abort;
|
use core::intrinsics::abort;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::{Deref, CoerceUnsized};
|
use core::ops::Deref;
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
use core::ops::CoerceUnsized;
|
||||||
use core::ptr::{self, Shared};
|
use core::ptr::{self, Shared};
|
||||||
|
#[cfg(not(stage0))]
|
||||||
use core::marker::Unsize;
|
use core::marker::Unsize;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::{usize, isize};
|
use core::{usize, isize};
|
||||||
|
@ -161,9 +161,13 @@ use core::cmp::Ordering;
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{Hasher, Hash};
|
use core::hash::{Hasher, Hash};
|
||||||
use core::intrinsics::{assume, abort};
|
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::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 core::ptr::{self, Shared};
|
||||||
|
|
||||||
use heap::deallocate;
|
use heap::deallocate;
|
||||||
|
@ -456,7 +456,7 @@ impl<T, E> Result<T, E> {
|
|||||||
// Transforming contained values
|
// Transforming contained values
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Maps a `Result<T, E>` to `Result<U, E>` by applying a function to an
|
/// Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a
|
||||||
/// contained `Ok` value, leaving an `Err` value untouched.
|
/// contained `Ok` value, leaving an `Err` value untouched.
|
||||||
///
|
///
|
||||||
/// This function can be used to compose the results of two functions.
|
/// This function can be used to compose the results of two functions.
|
||||||
@ -484,7 +484,7 @@ impl<T, E> Result<T, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to an
|
/// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a
|
||||||
/// contained `Err` value, leaving an `Ok` value untouched.
|
/// contained `Err` value, leaving an `Ok` value untouched.
|
||||||
///
|
///
|
||||||
/// This function can be used to pass through a successful result while handling
|
/// This function can be used to pass through a successful result while handling
|
||||||
|
@ -85,7 +85,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
|
|
||||||
// this will generate code to test discriminant_lvalue and
|
// this will generate code to test discriminant_lvalue and
|
||||||
// branch to the appropriate arm block
|
// 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
|
// all the arm blocks will rejoin here
|
||||||
let end_block = self.cfg.start_new_block();
|
let end_block = self.cfg.start_new_block();
|
||||||
@ -279,11 +287,32 @@ struct Test<'tcx> {
|
|||||||
// Main matching algorithm
|
// Main matching algorithm
|
||||||
|
|
||||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
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,
|
fn match_candidates<'pat>(&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
arm_blocks: &mut ArmBlocks,
|
arm_blocks: &mut ArmBlocks,
|
||||||
mut candidates: Vec<Candidate<'pat, 'tcx>>,
|
mut candidates: Vec<Candidate<'pat, 'tcx>>,
|
||||||
mut block: BasicBlock)
|
mut block: BasicBlock)
|
||||||
|
-> Vec<BasicBlock>
|
||||||
{
|
{
|
||||||
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
|
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
|
||||||
span, block, candidates);
|
span, block, candidates);
|
||||||
@ -311,17 +340,127 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
// if None is returned, then any remaining candidates
|
// if None is returned, then any remaining candidates
|
||||||
// are unreachable (at least not through this path).
|
// are unreachable (at least not through this path).
|
||||||
return;
|
return vec![];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no candidates that still need testing, we're done.
|
// If there are no candidates that still need testing, we're done.
|
||||||
// Since all matches are exhaustive, execution should never reach this point.
|
// Since all matches are exhaustive, execution should never reach this point.
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
return self.panic(block);
|
return vec![block];
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, extract the next match pair and construct tests
|
// 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, 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>)
|
||||||
|
-> 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<BasicBlock>, usize)
|
||||||
|
{
|
||||||
|
// extract the match-pair from the highest priority candidate
|
||||||
let match_pair = &candidates.last().unwrap().match_pairs[0];
|
let match_pair = &candidates.last().unwrap().match_pairs[0];
|
||||||
let mut test = self.test(match_pair);
|
let mut test = self.test(match_pair);
|
||||||
|
|
||||||
@ -331,35 +470,57 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
// available
|
// available
|
||||||
match test.kind {
|
match test.kind {
|
||||||
TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
|
TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
|
||||||
for candidate in &candidates {
|
for candidate in candidates.iter().rev() {
|
||||||
self.add_cases_to_switch(&match_pair.lvalue,
|
if !self.add_cases_to_switch(&match_pair.lvalue,
|
||||||
candidate,
|
candidate,
|
||||||
switch_ty,
|
switch_ty,
|
||||||
options,
|
options,
|
||||||
indices);
|
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);
|
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
|
||||||
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
|
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
|
||||||
|
|
||||||
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
|
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
|
||||||
|
|
||||||
for candidate in &candidates {
|
// Sort the candidates into the appropriate vector in
|
||||||
self.sort_candidate(&match_pair.lvalue,
|
// `target_candidates`. Note that at some point we may
|
||||||
&test,
|
// encounter a candidate where the test is not relevant; at
|
||||||
candidate,
|
// that point, we stop sorting.
|
||||||
&mut target_candidates);
|
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 (target_block, target_candidates) in
|
// 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()
|
target_blocks.into_iter()
|
||||||
.zip(target_candidates.into_iter())
|
.zip(target_candidates)
|
||||||
{
|
.flat_map(|(target_block, target_candidates)| {
|
||||||
self.match_candidates(span, arm_blocks, target_candidates, target_block);
|
self.match_candidates(span,
|
||||||
}
|
arm_blocks,
|
||||||
|
target_candidates,
|
||||||
|
target_block)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(otherwise, tested_candidates)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes each of the bindings from the candidate by
|
/// Initializes each of the bindings from the candidate by
|
||||||
|
@ -105,10 +105,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
switch_ty: Ty<'tcx>,
|
switch_ty: Ty<'tcx>,
|
||||||
options: &mut Vec<ConstVal>,
|
options: &mut Vec<ConstVal>,
|
||||||
indices: &mut FnvHashMap<ConstVal, usize>)
|
indices: &mut FnvHashMap<ConstVal, usize>)
|
||||||
|
-> bool
|
||||||
{
|
{
|
||||||
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
|
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
|
||||||
Some(match_pair) => match_pair,
|
Some(match_pair) => match_pair,
|
||||||
_ => { return; }
|
_ => { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
match *match_pair.pattern.kind {
|
match *match_pair.pattern.kind {
|
||||||
@ -121,11 +122,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
options.push(value.clone());
|
options.push(value.clone());
|
||||||
options.len() - 1
|
options.len() - 1
|
||||||
});
|
});
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
PatternKind::Range { .. } => {
|
PatternKind::Range { .. } |
|
||||||
}
|
|
||||||
|
|
||||||
PatternKind::Constant { .. } |
|
PatternKind::Constant { .. } |
|
||||||
PatternKind::Variant { .. } |
|
PatternKind::Variant { .. } |
|
||||||
PatternKind::Slice { .. } |
|
PatternKind::Slice { .. } |
|
||||||
@ -134,6 +134,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
PatternKind::Binding { .. } |
|
PatternKind::Binding { .. } |
|
||||||
PatternKind::Leaf { .. } |
|
PatternKind::Leaf { .. } |
|
||||||
PatternKind::Deref { .. } => {
|
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
|
/// P0` to the `resulting_candidates` entry corresponding to the
|
||||||
/// variant `Some`.
|
/// variant `Some`.
|
||||||
///
|
///
|
||||||
/// In many cases we will add the `candidate` to more than one
|
/// However, in some cases, the test may just not be relevant to
|
||||||
/// outcome. For example, say that the test is `x == 22`, but the
|
/// candidate. For example, suppose we are testing whether `foo.x == 22`,
|
||||||
/// candidate is `x @ 13..55`. In that case, if the test is true,
|
/// but in one match arm we have `Foo { x: _, ... }`... in that case,
|
||||||
/// then we know that the candidate applies (without this match
|
/// the test for what value `x` has has no particular relevance
|
||||||
/// pair, potentially, though we don't optimize this due to
|
/// to this candidate. In such cases, this function just returns false
|
||||||
/// #29623). If the test is false, the candidate may also apply
|
/// without doing anything. This is used by the overall `match_candidates`
|
||||||
/// (with the match pair, still).
|
/// 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,
|
pub fn sort_candidate<'pat>(&mut self,
|
||||||
test_lvalue: &Lvalue<'tcx>,
|
test_lvalue: &Lvalue<'tcx>,
|
||||||
test: &Test<'tcx>,
|
test: &Test<'tcx>,
|
||||||
candidate: &Candidate<'pat, 'tcx>,
|
candidate: &Candidate<'pat, 'tcx>,
|
||||||
resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>]) {
|
resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>])
|
||||||
|
-> bool {
|
||||||
// Find the match_pair for this lvalue (if any). At present,
|
// Find the match_pair for this lvalue (if any). At present,
|
||||||
// afaik, there can be at most one. (In the future, if we
|
// afaik, there can be at most one. (In the future, if we
|
||||||
// adopted a more general `@` operator, there might be more
|
// adopted a more general `@` operator, there might be more
|
||||||
@ -311,7 +324,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
None => {
|
None => {
|
||||||
// We are not testing this lvalue. Therefore, this
|
// We are not testing this lvalue. Therefore, this
|
||||||
// candidate applies to ALL outcomes.
|
// 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,
|
subpatterns,
|
||||||
candidate);
|
candidate);
|
||||||
resulting_candidates[variant_index].push(new_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,
|
let new_candidate = self.candidate_without_match_pair(match_pair_index,
|
||||||
candidate);
|
candidate);
|
||||||
resulting_candidates[index].push(new_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,
|
let new_candidate = self.candidate_without_match_pair(match_pair_index,
|
||||||
candidate);
|
candidate);
|
||||||
resulting_candidates[0].push(new_candidate);
|
resulting_candidates[0].push(new_candidate);
|
||||||
|
true
|
||||||
} else {
|
} 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<Candidate<'pat, 'tcx>>]) {
|
|
||||||
for resulting_candidate in resulting_candidates {
|
|
||||||
resulting_candidate.push(candidate.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn candidate_after_variant_switch<'pat>(&mut self,
|
fn candidate_after_variant_switch<'pat>(&mut self,
|
||||||
match_pair_index: usize,
|
match_pair_index: usize,
|
||||||
adt_def: ty::AdtDef<'tcx>,
|
adt_def: ty::AdtDef<'tcx>,
|
||||||
@ -447,5 +455,5 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
|
fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
|
||||||
ty.is_integral() || ty.is_char()
|
ty.is_integral() || ty.is_char() || ty.is_bool()
|
||||||
}
|
}
|
||||||
|
@ -10,119 +10,136 @@
|
|||||||
|
|
||||||
//! The Rust Prelude
|
//! The Rust Prelude
|
||||||
//!
|
//!
|
||||||
//! Because `std` is required by most serious Rust software, it is
|
//! Rust comes with a variety of things in its standard library. However, if
|
||||||
//! imported at the topmost level of every crate by default, as if
|
//! you had to manually import every single thing that you used, it would be
|
||||||
//! each crate contains the following:
|
//! 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
|
//! ```ignore
|
||||||
//! extern crate std;
|
//! extern crate std;
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! This means that the contents of std can be accessed from any context
|
//! into the crate root of every crate, and
|
||||||
//! 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
|
|
||||||
//!
|
//!
|
||||||
//! ```ignore
|
//! ```ignore
|
||||||
//! use std::prelude::v1::*;
|
//! use std::prelude::v1::*;
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The prelude is primarily concerned with exporting *traits* that
|
//! into every module.
|
||||||
//! are so pervasive that they would be onerous to import for every use,
|
//!
|
||||||
//! particularly those that are commonly mentioned in [generic type
|
//! # Other preludes
|
||||||
//! bounds][book-traits].
|
//!
|
||||||
|
//! 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
|
//! 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::`{
|
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`]}. The marker
|
||||||
//! [`Copy`](../marker/trait.Copy.html),
|
//! traits indicate fundamental properties of types.
|
||||||
//! [`Send`](../marker/trait.Send.html),
|
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
|
||||||
//! [`Sized`](../marker/trait.Sized.html),
|
//! operations for both destuctors and overloading `()`.
|
||||||
//! [`Sync`](../marker/trait.Sync.html)
|
//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a
|
||||||
//! }.
|
//! value.
|
||||||
//! The marker traits indicate fundamental properties of types.
|
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
|
||||||
//! * `std::ops::`{
|
//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
|
||||||
//! [`Drop`](../ops/trait.Drop.html),
|
//! [`to_owned()`], the generic method for creating an owned type from a
|
||||||
//! [`Fn`](../ops/trait.Fn.html),
|
//! borrowed type.
|
||||||
//! [`FnMut`](../ops/trait.FnMut.html),
|
//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`],
|
||||||
//! [`FnOnce`](../ops/trait.FnOnce.html)
|
//! the method for producing a copy of a value.
|
||||||
//! }.
|
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
|
||||||
//! The [destructor][book-dtor] trait and the
|
//! comparison traits, which implement the comparison operators and are often
|
||||||
//! [closure][book-closures] traits, reexported from the same
|
//! seen in trait bounds.
|
||||||
//! [module that also defines overloaded
|
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic
|
||||||
//! operators](../ops/index.html).
|
//! conversions, used by savvy API authors to create overloaded methods.
|
||||||
//! * `std::mem::`[`drop`](../mem/fn.drop.html).
|
//! * [`std::default`]::[`Default`], types that have default values.
|
||||||
//! A convenience function for explicitly dropping a value.
|
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
|
||||||
//! * `std::boxed::`[`Box`](../boxed/struct.Box.html).
|
//! [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various
|
||||||
//! The owned heap pointer.
|
//! kinds.
|
||||||
//! * `std::borrow::`[`ToOwned`](../borrow/trait.ToOwned.html).
|
//! * [`std::option`]::[`Option`]::{`self`, `Some`, `None`}. A type which
|
||||||
//! The conversion trait that defines `to_owned`, the generic method
|
//! expresses the presence or absence of a value. This type is so commonly
|
||||||
//! for creating an owned type from a borrowed type.
|
//! used, its variants are also exported.
|
||||||
//! * `std::clone::`[`Clone`](../clone/trait.Clone.html).
|
//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions
|
||||||
//! The ubiquitous trait that defines `clone`, the method for
|
//! that may succeed or fail. Like [`Option`], its variants are exported as
|
||||||
//! producing copies of values that are consider expensive to copy.
|
//! well.
|
||||||
//! * `std::cmp::`{
|
//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical
|
||||||
//! [`PartialEq`](../cmp/trait.PartialEq.html),
|
//! reasons, but shouldn't have to exist. It provides a few useful methods on
|
||||||
//! [`PartialOrd`](../cmp/trait.PartialOrd.html),
|
//! slices.
|
||||||
//! [`Eq`](../cmp/trait.Eq.html),
|
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
|
||||||
//! [`Ord`](../cmp/trait.Ord.html)
|
//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated
|
||||||
//! }.
|
//! vector.
|
||||||
//! 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.
|
|
||||||
//!
|
//!
|
||||||
//! [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-closures]: ../../book/closures.html
|
||||||
//! [book-dtor]: ../../book/drop.html
|
//! [book-dtor]: ../../book/drop.html
|
||||||
//! [book-iter]: ../../book/iterators.html
|
|
||||||
//! [book-enums]: ../../book/enums.html
|
//! [book-enums]: ../../book/enums.html
|
||||||
|
//! [book-iter]: ../../book/iterators.html
|
||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! The first version of the prelude of The Rust Standard Library.
|
//! 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")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
326
src/test/run-pass/issue-29740.rs
Normal file
326
src/test/run-pass/issue-29740.rs
Normal file
@ -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 <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.
|
||||||
|
|
||||||
|
// 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<Key> {
|
||||||
|
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() { }
|
Loading…
Reference in New Issue
Block a user