]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | // Testing candidates | |
12 | // | |
13 | // After candidates have been simplified, the only match pairs that | |
14 | // remain are those that require some sort of test. The functions here | |
15 | // identify what tests are needed, perform the tests, and then filter | |
16 | // the candidates based on the result. | |
17 | ||
92a42be0 | 18 | use build::Builder; |
e9174d1e SL |
19 | use build::matches::{Candidate, MatchPair, Test, TestKind}; |
20 | use hair::*; | |
92a42be0 | 21 | use rustc_data_structures::fnv::FnvHashMap; |
54a0048b SL |
22 | use rustc::middle::const_val::ConstVal; |
23 | use rustc::ty::{self, Ty}; | |
92a42be0 | 24 | use rustc::mir::repr::*; |
b039eaaf | 25 | use syntax::codemap::Span; |
e9174d1e | 26 | |
b039eaaf | 27 | impl<'a,'tcx> Builder<'a,'tcx> { |
e9174d1e SL |
28 | /// Identifies what test is needed to decide if `match_pair` is applicable. |
29 | /// | |
30 | /// It is a bug to call this with a simplifyable pattern. | |
92a42be0 SL |
31 | pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { |
32 | match *match_pair.pattern.kind { | |
e9174d1e SL |
33 | PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => { |
34 | Test { | |
35 | span: match_pair.pattern.span, | |
36 | kind: TestKind::Switch { adt_def: adt_def.clone() }, | |
37 | } | |
38 | } | |
39 | ||
9cc50fc6 | 40 | PatternKind::Constant { .. } |
92a42be0 SL |
41 | if is_switch_ty(match_pair.pattern.ty) => { |
42 | // for integers, we use a SwitchInt match, which allows | |
43 | // us to handle more cases | |
44 | Test { | |
45 | span: match_pair.pattern.span, | |
46 | kind: TestKind::SwitchInt { | |
47 | switch_ty: match_pair.pattern.ty, | |
48 | ||
49 | // these maps are empty to start; cases are | |
50 | // added below in add_cases_to_switch | |
51 | options: vec![], | |
52 | indices: FnvHashMap(), | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
b039eaaf | 57 | PatternKind::Constant { ref value } => { |
e9174d1e SL |
58 | Test { |
59 | span: match_pair.pattern.span, | |
b039eaaf SL |
60 | kind: TestKind::Eq { |
61 | value: value.clone(), | |
9cc50fc6 | 62 | ty: match_pair.pattern.ty.clone() |
92a42be0 | 63 | } |
e9174d1e SL |
64 | } |
65 | } | |
66 | ||
67 | PatternKind::Range { ref lo, ref hi } => { | |
e9174d1e SL |
68 | Test { |
69 | span: match_pair.pattern.span, | |
b039eaaf SL |
70 | kind: TestKind::Range { |
71 | lo: lo.clone(), | |
72 | hi: hi.clone(), | |
73 | ty: match_pair.pattern.ty.clone(), | |
74 | }, | |
e9174d1e SL |
75 | } |
76 | } | |
77 | ||
54a0048b SL |
78 | PatternKind::Slice { ref prefix, ref slice, ref suffix } |
79 | if !match_pair.slice_len_checked => { | |
e9174d1e | 80 | let len = prefix.len() + suffix.len(); |
b039eaaf SL |
81 | let op = if slice.is_some() { |
82 | BinOp::Ge | |
83 | } else { | |
84 | BinOp::Eq | |
85 | }; | |
e9174d1e SL |
86 | Test { |
87 | span: match_pair.pattern.span, | |
54a0048b | 88 | kind: TestKind::Len { len: len as u64, op: op }, |
e9174d1e SL |
89 | } |
90 | } | |
91 | ||
92 | PatternKind::Array { .. } | | |
54a0048b | 93 | PatternKind::Slice { .. } | |
e9174d1e SL |
94 | PatternKind::Wild | |
95 | PatternKind::Binding { .. } | | |
96 | PatternKind::Leaf { .. } | | |
97 | PatternKind::Deref { .. } => { | |
98 | self.error_simplifyable(match_pair) | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
92a42be0 SL |
103 | pub fn add_cases_to_switch<'pat>(&mut self, |
104 | test_lvalue: &Lvalue<'tcx>, | |
105 | candidate: &Candidate<'pat, 'tcx>, | |
106 | switch_ty: Ty<'tcx>, | |
107 | options: &mut Vec<ConstVal>, | |
108 | indices: &mut FnvHashMap<ConstVal, usize>) | |
109 | -> bool | |
110 | { | |
111 | let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { | |
112 | Some(match_pair) => match_pair, | |
113 | _ => { return false; } | |
114 | }; | |
115 | ||
116 | match *match_pair.pattern.kind { | |
9cc50fc6 | 117 | PatternKind::Constant { ref value } => { |
92a42be0 SL |
118 | // if the lvalues match, the type should match |
119 | assert_eq!(match_pair.pattern.ty, switch_ty); | |
120 | ||
121 | indices.entry(value.clone()) | |
122 | .or_insert_with(|| { | |
123 | options.push(value.clone()); | |
124 | options.len() - 1 | |
125 | }); | |
126 | true | |
127 | } | |
128 | ||
129 | PatternKind::Range { .. } | | |
92a42be0 SL |
130 | PatternKind::Variant { .. } | |
131 | PatternKind::Slice { .. } | | |
132 | PatternKind::Array { .. } | | |
133 | PatternKind::Wild | | |
134 | PatternKind::Binding { .. } | | |
135 | PatternKind::Leaf { .. } | | |
136 | PatternKind::Deref { .. } => { | |
137 | // don't know how to add these patterns to a switch | |
138 | false | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
e9174d1e SL |
143 | /// Generates the code to perform a test. |
144 | pub fn perform_test(&mut self, | |
145 | block: BasicBlock, | |
b039eaaf SL |
146 | lvalue: &Lvalue<'tcx>, |
147 | test: &Test<'tcx>) | |
e9174d1e | 148 | -> Vec<BasicBlock> { |
54a0048b | 149 | let scope_id = self.innermost_scope_id(); |
92a42be0 | 150 | match test.kind { |
e9174d1e SL |
151 | TestKind::Switch { adt_def } => { |
152 | let num_enum_variants = self.hir.num_variants(adt_def); | |
153 | let target_blocks: Vec<_> = | |
154 | (0..num_enum_variants).map(|_| self.cfg.start_new_block()) | |
155 | .collect(); | |
54a0048b | 156 | self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch { |
e9174d1e | 157 | discr: lvalue.clone(), |
92a42be0 | 158 | adt_def: adt_def, |
e9174d1e SL |
159 | targets: target_blocks.clone() |
160 | }); | |
161 | target_blocks | |
162 | } | |
163 | ||
92a42be0 SL |
164 | TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { |
165 | let otherwise = self.cfg.start_new_block(); | |
166 | let targets: Vec<_> = | |
167 | options.iter() | |
168 | .map(|_| self.cfg.start_new_block()) | |
169 | .chain(Some(otherwise)) | |
170 | .collect(); | |
54a0048b SL |
171 | self.cfg.terminate(block, |
172 | scope_id, | |
173 | test.span, | |
174 | TerminatorKind::SwitchInt { | |
175 | discr: lvalue.clone(), | |
176 | switch_ty: switch_ty, | |
177 | values: options.clone(), | |
178 | targets: targets.clone(), | |
179 | }); | |
92a42be0 SL |
180 | targets |
181 | } | |
182 | ||
54a0048b SL |
183 | TestKind::Eq { ref value, mut ty } => { |
184 | let mut val = Operand::Consume(lvalue.clone()); | |
185 | ||
186 | // If we're using b"..." as a pattern, we need to insert an | |
187 | // unsizing coercion, as the byte string has the type &[u8; N]. | |
188 | let expect = if let ConstVal::ByteStr(ref bytes) = *value { | |
189 | let tcx = self.hir.tcx(); | |
190 | ||
191 | // Unsize the lvalue to &[u8], too, if necessary. | |
192 | if let ty::TyRef(region, mt) = ty.sty { | |
193 | if let ty::TyArray(_, _) = mt.ty.sty { | |
194 | ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); | |
195 | let val_slice = self.temp(ty); | |
196 | self.cfg.push_assign(block, scope_id, test.span, &val_slice, | |
197 | Rvalue::Cast(CastKind::Unsize, val, ty)); | |
198 | val = Operand::Consume(val_slice); | |
199 | } | |
200 | } | |
201 | ||
202 | assert!(ty.is_slice()); | |
203 | ||
204 | let array_ty = tcx.mk_array(tcx.types.u8, bytes.len()); | |
205 | let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty); | |
206 | let array = self.literal_operand(test.span, array_ref, Literal::Value { | |
207 | value: value.clone() | |
208 | }); | |
209 | ||
210 | let slice = self.temp(ty); | |
211 | self.cfg.push_assign(block, scope_id, test.span, &slice, | |
212 | Rvalue::Cast(CastKind::Unsize, array, ty)); | |
213 | Operand::Consume(slice) | |
214 | } else { | |
215 | self.literal_operand(test.span, ty, Literal::Value { | |
216 | value: value.clone() | |
217 | }) | |
218 | }; | |
219 | ||
220 | // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. | |
9cc50fc6 | 221 | let fail = self.cfg.start_new_block(); |
54a0048b SL |
222 | if let ty::TyRef(_, mt) = ty.sty { |
223 | assert!(ty.is_slice()); | |
224 | let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap(); | |
225 | let ty = mt.ty; | |
226 | let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, vec![ty]); | |
227 | ||
228 | let bool_ty = self.hir.bool_ty(); | |
229 | let eq_result = self.temp(bool_ty); | |
230 | let eq_block = self.cfg.start_new_block(); | |
231 | let cleanup = self.diverge_cleanup(); | |
232 | self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Call { | |
233 | func: Operand::Constant(Constant { | |
234 | span: test.span, | |
235 | ty: mty, | |
236 | literal: method | |
237 | }), | |
238 | args: vec![val, expect], | |
239 | destination: Some((eq_result.clone(), eq_block)), | |
240 | cleanup: cleanup, | |
241 | }); | |
242 | ||
243 | // check the result | |
244 | let block = self.cfg.start_new_block(); | |
245 | self.cfg.terminate(eq_block, scope_id, test.span, TerminatorKind::If { | |
246 | cond: Operand::Consume(eq_result), | |
247 | targets: (block, fail), | |
248 | }); | |
249 | ||
250 | vec![block, fail] | |
251 | } else { | |
252 | let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val); | |
253 | vec![block, fail] | |
254 | } | |
e9174d1e SL |
255 | } |
256 | ||
92a42be0 | 257 | TestKind::Range { ref lo, ref hi, ty } => { |
9cc50fc6 | 258 | // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. |
92a42be0 SL |
259 | let lo = self.literal_operand(test.span, ty.clone(), lo.clone()); |
260 | let hi = self.literal_operand(test.span, ty.clone(), hi.clone()); | |
9cc50fc6 | 261 | let val = Operand::Consume(lvalue.clone()); |
e9174d1e | 262 | |
9cc50fc6 SL |
263 | let fail = self.cfg.start_new_block(); |
264 | let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone()); | |
265 | let block = self.compare(block, fail, test.span, BinOp::Le, val, hi); | |
e9174d1e | 266 | |
9cc50fc6 | 267 | vec![block, fail] |
e9174d1e SL |
268 | } |
269 | ||
270 | TestKind::Len { len, op } => { | |
271 | let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty()); | |
272 | let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); | |
273 | ||
274 | // actual = len(lvalue) | |
54a0048b SL |
275 | self.cfg.push_assign(block, scope_id, test.span, |
276 | &actual, Rvalue::Len(lvalue.clone())); | |
e9174d1e SL |
277 | |
278 | // expected = <N> | |
54a0048b | 279 | let expected = self.push_usize(block, scope_id, test.span, len); |
e9174d1e SL |
280 | |
281 | // result = actual == expected OR result = actual < expected | |
b039eaaf | 282 | self.cfg.push_assign(block, |
54a0048b | 283 | scope_id, |
b039eaaf SL |
284 | test.span, |
285 | &result, | |
286 | Rvalue::BinaryOp(op, | |
287 | Operand::Consume(actual), | |
288 | Operand::Consume(expected))); | |
e9174d1e SL |
289 | |
290 | // branch based on result | |
291 | let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), | |
292 | self.cfg.start_new_block()]; | |
54a0048b | 293 | self.cfg.terminate(block, scope_id, test.span, TerminatorKind::If { |
e9174d1e | 294 | cond: Operand::Consume(result), |
9cc50fc6 | 295 | targets: (target_blocks[0], target_blocks[1]) |
e9174d1e SL |
296 | }); |
297 | ||
298 | target_blocks | |
299 | } | |
300 | } | |
301 | } | |
302 | ||
9cc50fc6 SL |
303 | fn compare(&mut self, |
304 | block: BasicBlock, | |
305 | fail_block: BasicBlock, | |
306 | span: Span, | |
307 | op: BinOp, | |
308 | left: Operand<'tcx>, | |
309 | right: Operand<'tcx>) -> BasicBlock { | |
e9174d1e | 310 | let bool_ty = self.hir.bool_ty(); |
9cc50fc6 SL |
311 | let result = self.temp(bool_ty); |
312 | ||
313 | // result = op(left, right) | |
54a0048b SL |
314 | let scope_id = self.innermost_scope_id(); |
315 | self.cfg.push_assign(block, scope_id, span, &result, | |
316 | Rvalue::BinaryOp(op, left, right)); | |
9cc50fc6 SL |
317 | |
318 | // branch based on result | |
319 | let target_block = self.cfg.start_new_block(); | |
54a0048b | 320 | self.cfg.terminate(block, scope_id, span, TerminatorKind::If { |
9cc50fc6 SL |
321 | cond: Operand::Consume(result), |
322 | targets: (target_block, fail_block) | |
323 | }); | |
324 | ||
325 | target_block | |
e9174d1e SL |
326 | } |
327 | ||
92a42be0 SL |
328 | /// Given that we are performing `test` against `test_lvalue`, |
329 | /// this job sorts out what the status of `candidate` will be | |
330 | /// after the test. The `resulting_candidates` vector stores, for | |
331 | /// each possible outcome of `test`, a vector of the candidates | |
332 | /// that will result. This fn should add a (possibly modified) | |
333 | /// clone of candidate into `resulting_candidates` wherever | |
334 | /// appropriate. | |
e9174d1e | 335 | /// |
92a42be0 SL |
336 | /// So, for example, if this candidate is `x @ Some(P0)` and the |
337 | /// test is a variant test, then we would add `(x as Option).0 @ | |
338 | /// P0` to the `resulting_candidates` entry corresponding to the | |
339 | /// variant `Some`. | |
340 | /// | |
341 | /// However, in some cases, the test may just not be relevant to | |
342 | /// candidate. For example, suppose we are testing whether `foo.x == 22`, | |
343 | /// but in one match arm we have `Foo { x: _, ... }`... in that case, | |
344 | /// the test for what value `x` has has no particular relevance | |
345 | /// to this candidate. In such cases, this function just returns false | |
346 | /// without doing anything. This is used by the overall `match_candidates` | |
347 | /// algorithm to structure the match as a whole. See `match_candidates` for | |
348 | /// more details. | |
349 | /// | |
350 | /// FIXME(#29623). In some cases, we have some tricky choices to | |
351 | /// make. for example, if we are testing that `x == 22`, but the | |
352 | /// candidate is `x @ 13..55`, what should we do? In the event | |
353 | /// that the test is true, we know that the candidate applies, but | |
354 | /// in the event of false, we don't know that it *doesn't* | |
355 | /// apply. For now, we return false, indicate that the test does | |
356 | /// not apply to this candidate, but it might be we can get | |
357 | /// tighter match code if we do something a bit different. | |
358 | pub fn sort_candidate<'pat>(&mut self, | |
359 | test_lvalue: &Lvalue<'tcx>, | |
360 | test: &Test<'tcx>, | |
361 | candidate: &Candidate<'pat, 'tcx>, | |
362 | resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>]) | |
363 | -> bool { | |
364 | // Find the match_pair for this lvalue (if any). At present, | |
365 | // afaik, there can be at most one. (In the future, if we | |
366 | // adopted a more general `@` operator, there might be more | |
367 | // than one, but it'd be very unusual to have two sides that | |
368 | // both require tests; you'd expect one side to be simplified | |
369 | // away.) | |
370 | let tested_match_pair = candidate.match_pairs.iter() | |
371 | .enumerate() | |
372 | .filter(|&(_, mp)| mp.lvalue == *test_lvalue) | |
373 | .next(); | |
374 | let (match_pair_index, match_pair) = match tested_match_pair { | |
375 | Some(pair) => pair, | |
376 | None => { | |
377 | // We are not testing this lvalue. Therefore, this | |
378 | // candidate applies to ALL outcomes. | |
379 | return false; | |
e9174d1e | 380 | } |
92a42be0 SL |
381 | }; |
382 | ||
383 | match test.kind { | |
384 | // If we are performing a variant switch, then this | |
385 | // informs variant patterns, but nothing else. | |
386 | TestKind::Switch { adt_def: tested_adt_def } => { | |
387 | match *match_pair.pattern.kind { | |
388 | PatternKind::Variant { adt_def, variant_index, ref subpatterns } => { | |
389 | assert_eq!(adt_def, tested_adt_def); | |
390 | let new_candidate = | |
391 | self.candidate_after_variant_switch(match_pair_index, | |
392 | adt_def, | |
393 | variant_index, | |
394 | subpatterns, | |
395 | candidate); | |
396 | resulting_candidates[variant_index].push(new_candidate); | |
397 | true | |
398 | } | |
399 | _ => { | |
400 | false | |
401 | } | |
e9174d1e SL |
402 | } |
403 | } | |
e9174d1e | 404 | |
92a42be0 SL |
405 | // If we are performing a switch over integers, then this informs integer |
406 | // equality, but nothing else. | |
407 | // | |
408 | // FIXME(#29623) we could use TestKind::Range to rule | |
409 | // things out here, in some cases. | |
410 | TestKind::SwitchInt { switch_ty: _, options: _, ref indices } => { | |
411 | match *match_pair.pattern.kind { | |
9cc50fc6 | 412 | PatternKind::Constant { ref value } |
92a42be0 SL |
413 | if is_switch_ty(match_pair.pattern.ty) => { |
414 | let index = indices[value]; | |
415 | let new_candidate = self.candidate_without_match_pair(match_pair_index, | |
416 | candidate); | |
417 | resulting_candidates[index].push(new_candidate); | |
418 | true | |
419 | } | |
420 | _ => { | |
421 | false | |
422 | } | |
e9174d1e | 423 | } |
e9174d1e SL |
424 | } |
425 | ||
54a0048b SL |
426 | // If we are performing a length check, then this |
427 | // informs slice patterns, but nothing else. | |
92a42be0 | 428 | TestKind::Len { .. } => { |
54a0048b SL |
429 | let pattern_test = self.test(&match_pair); |
430 | match *match_pair.pattern.kind { | |
431 | PatternKind::Slice { .. } if pattern_test.kind == test.kind => { | |
432 | let mut new_candidate = candidate.clone(); | |
433 | ||
434 | // Set up the MatchKind to simplify this like an array. | |
435 | new_candidate.match_pairs[match_pair_index] | |
436 | .slice_len_checked = true; | |
437 | resulting_candidates[0].push(new_candidate); | |
438 | true | |
439 | } | |
440 | _ => false | |
441 | } | |
442 | } | |
443 | ||
444 | TestKind::Eq { .. } | | |
445 | TestKind::Range { .. } => { | |
92a42be0 SL |
446 | // These are all binary tests. |
447 | // | |
448 | // FIXME(#29623) we can be more clever here | |
449 | let pattern_test = self.test(&match_pair); | |
450 | if pattern_test.kind == test.kind { | |
451 | let new_candidate = self.candidate_without_match_pair(match_pair_index, | |
452 | candidate); | |
453 | resulting_candidates[0].push(new_candidate); | |
454 | true | |
e9174d1e | 455 | } else { |
92a42be0 | 456 | false |
e9174d1e SL |
457 | } |
458 | } | |
92a42be0 SL |
459 | } |
460 | } | |
e9174d1e | 461 | |
92a42be0 SL |
462 | fn candidate_without_match_pair<'pat>(&mut self, |
463 | match_pair_index: usize, | |
464 | candidate: &Candidate<'pat, 'tcx>) | |
465 | -> Candidate<'pat, 'tcx> { | |
466 | let other_match_pairs = | |
467 | candidate.match_pairs.iter() | |
468 | .enumerate() | |
469 | .filter(|&(index, _)| index != match_pair_index) | |
470 | .map(|(_, mp)| mp.clone()) | |
471 | .collect(); | |
472 | Candidate { | |
54a0048b | 473 | span: candidate.span, |
92a42be0 SL |
474 | match_pairs: other_match_pairs, |
475 | bindings: candidate.bindings.clone(), | |
476 | guard: candidate.guard.clone(), | |
477 | arm_index: candidate.arm_index, | |
478 | } | |
479 | } | |
e9174d1e | 480 | |
92a42be0 SL |
481 | fn candidate_after_variant_switch<'pat>(&mut self, |
482 | match_pair_index: usize, | |
483 | adt_def: ty::AdtDef<'tcx>, | |
484 | variant_index: usize, | |
485 | subpatterns: &'pat [FieldPattern<'tcx>], | |
486 | candidate: &Candidate<'pat, 'tcx>) | |
487 | -> Candidate<'pat, 'tcx> { | |
488 | let match_pair = &candidate.match_pairs[match_pair_index]; | |
489 | ||
490 | // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, | |
491 | // we want to create a set of derived match-patterns like | |
492 | // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. | |
493 | let elem = ProjectionElem::Downcast(adt_def, variant_index); | |
494 | let downcast_lvalue = match_pair.lvalue.clone().elem(elem); // `(x as Variant)` | |
495 | let consequent_match_pairs = | |
496 | subpatterns.iter() | |
497 | .map(|subpattern| { | |
498 | // e.g., `(x as Variant).0` | |
7453a54e | 499 | let lvalue = downcast_lvalue.clone().field(subpattern.field, |
54a0048b | 500 | subpattern.pattern.ty); |
92a42be0 SL |
501 | // e.g., `(x as Variant).0 @ P1` |
502 | MatchPair::new(lvalue, &subpattern.pattern) | |
503 | }); | |
504 | ||
505 | // In addition, we need all the other match pairs from the old candidate. | |
506 | let other_match_pairs = | |
507 | candidate.match_pairs.iter() | |
508 | .enumerate() | |
509 | .filter(|&(index, _)| index != match_pair_index) | |
510 | .map(|(_, mp)| mp.clone()); | |
511 | ||
512 | let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect(); | |
513 | ||
514 | Candidate { | |
54a0048b | 515 | span: candidate.span, |
92a42be0 SL |
516 | match_pairs: all_match_pairs, |
517 | bindings: candidate.bindings.clone(), | |
518 | guard: candidate.guard.clone(), | |
519 | arm_index: candidate.arm_index, | |
e9174d1e SL |
520 | } |
521 | } | |
522 | ||
92a42be0 | 523 | fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { |
54a0048b SL |
524 | span_bug!(match_pair.pattern.span, |
525 | "simplifyable pattern found: {:?}", | |
526 | match_pair.pattern) | |
e9174d1e SL |
527 | } |
528 | } | |
92a42be0 SL |
529 | |
530 | fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool { | |
531 | ty.is_integral() || ty.is_char() || ty.is_bool() | |
532 | } |