]>
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::*; | |
476ff2be | 21 | use rustc_data_structures::fx::FxHashMap; |
3157f602 | 22 | use rustc_data_structures::bitvec::BitVector; |
54a0048b SL |
23 | use rustc::middle::const_val::ConstVal; |
24 | use rustc::ty::{self, Ty}; | |
c30ab7b3 | 25 | use rustc::mir::*; |
3157f602 XL |
26 | use syntax_pos::Span; |
27 | use std::cmp::Ordering; | |
e9174d1e | 28 | |
a7813a04 | 29 | impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { |
e9174d1e SL |
30 | /// Identifies what test is needed to decide if `match_pair` is applicable. |
31 | /// | |
32 | /// It is a bug to call this with a simplifyable pattern. | |
92a42be0 SL |
33 | pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { |
34 | match *match_pair.pattern.kind { | |
e9174d1e SL |
35 | PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => { |
36 | Test { | |
37 | span: match_pair.pattern.span, | |
3157f602 XL |
38 | kind: TestKind::Switch { |
39 | adt_def: adt_def.clone(), | |
40 | variants: BitVector::new(self.hir.num_variants(adt_def)), | |
41 | }, | |
e9174d1e SL |
42 | } |
43 | } | |
44 | ||
9cc50fc6 | 45 | PatternKind::Constant { .. } |
92a42be0 SL |
46 | if is_switch_ty(match_pair.pattern.ty) => { |
47 | // for integers, we use a SwitchInt match, which allows | |
48 | // us to handle more cases | |
49 | Test { | |
50 | span: match_pair.pattern.span, | |
51 | kind: TestKind::SwitchInt { | |
52 | switch_ty: match_pair.pattern.ty, | |
53 | ||
54 | // these maps are empty to start; cases are | |
55 | // added below in add_cases_to_switch | |
56 | options: vec![], | |
476ff2be | 57 | indices: FxHashMap(), |
92a42be0 SL |
58 | } |
59 | } | |
60 | } | |
61 | ||
b039eaaf | 62 | PatternKind::Constant { ref value } => { |
e9174d1e SL |
63 | Test { |
64 | span: match_pair.pattern.span, | |
b039eaaf SL |
65 | kind: TestKind::Eq { |
66 | value: value.clone(), | |
9cc50fc6 | 67 | ty: match_pair.pattern.ty.clone() |
92a42be0 | 68 | } |
e9174d1e SL |
69 | } |
70 | } | |
71 | ||
72 | PatternKind::Range { ref lo, ref hi } => { | |
e9174d1e SL |
73 | Test { |
74 | span: match_pair.pattern.span, | |
b039eaaf | 75 | kind: TestKind::Range { |
c30ab7b3 SL |
76 | lo: Literal::Value { value: lo.clone() }, |
77 | hi: Literal::Value { value: hi.clone() }, | |
b039eaaf SL |
78 | ty: match_pair.pattern.ty.clone(), |
79 | }, | |
e9174d1e SL |
80 | } |
81 | } | |
82 | ||
54a0048b SL |
83 | PatternKind::Slice { ref prefix, ref slice, ref suffix } |
84 | if !match_pair.slice_len_checked => { | |
e9174d1e | 85 | let len = prefix.len() + suffix.len(); |
b039eaaf SL |
86 | let op = if slice.is_some() { |
87 | BinOp::Ge | |
88 | } else { | |
89 | BinOp::Eq | |
90 | }; | |
e9174d1e SL |
91 | Test { |
92 | span: match_pair.pattern.span, | |
54a0048b | 93 | kind: TestKind::Len { len: len as u64, op: op }, |
e9174d1e SL |
94 | } |
95 | } | |
96 | ||
97 | PatternKind::Array { .. } | | |
54a0048b | 98 | PatternKind::Slice { .. } | |
e9174d1e SL |
99 | PatternKind::Wild | |
100 | PatternKind::Binding { .. } | | |
101 | PatternKind::Leaf { .. } | | |
102 | PatternKind::Deref { .. } => { | |
103 | self.error_simplifyable(match_pair) | |
104 | } | |
105 | } | |
106 | } | |
107 | ||
92a42be0 SL |
108 | pub fn add_cases_to_switch<'pat>(&mut self, |
109 | test_lvalue: &Lvalue<'tcx>, | |
110 | candidate: &Candidate<'pat, 'tcx>, | |
111 | switch_ty: Ty<'tcx>, | |
112 | options: &mut Vec<ConstVal>, | |
476ff2be | 113 | indices: &mut FxHashMap<ConstVal, usize>) |
92a42be0 SL |
114 | -> bool |
115 | { | |
116 | let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { | |
117 | Some(match_pair) => match_pair, | |
118 | _ => { return false; } | |
119 | }; | |
120 | ||
121 | match *match_pair.pattern.kind { | |
9cc50fc6 | 122 | PatternKind::Constant { ref value } => { |
92a42be0 SL |
123 | // if the lvalues match, the type should match |
124 | assert_eq!(match_pair.pattern.ty, switch_ty); | |
125 | ||
126 | indices.entry(value.clone()) | |
127 | .or_insert_with(|| { | |
128 | options.push(value.clone()); | |
129 | options.len() - 1 | |
130 | }); | |
131 | true | |
132 | } | |
3157f602 XL |
133 | PatternKind::Variant { .. } => { |
134 | panic!("you should have called add_variants_to_switch instead!"); | |
135 | } | |
92a42be0 | 136 | PatternKind::Range { .. } | |
92a42be0 SL |
137 | PatternKind::Slice { .. } | |
138 | PatternKind::Array { .. } | | |
139 | PatternKind::Wild | | |
140 | PatternKind::Binding { .. } | | |
141 | PatternKind::Leaf { .. } | | |
142 | PatternKind::Deref { .. } => { | |
143 | // don't know how to add these patterns to a switch | |
144 | false | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
3157f602 XL |
149 | pub fn add_variants_to_switch<'pat>(&mut self, |
150 | test_lvalue: &Lvalue<'tcx>, | |
151 | candidate: &Candidate<'pat, 'tcx>, | |
152 | variants: &mut BitVector) | |
153 | -> bool | |
154 | { | |
155 | let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { | |
156 | Some(match_pair) => match_pair, | |
157 | _ => { return false; } | |
158 | }; | |
159 | ||
160 | match *match_pair.pattern.kind { | |
161 | PatternKind::Variant { adt_def: _ , variant_index, .. } => { | |
162 | // We have a pattern testing for variant `variant_index` | |
163 | // set the corresponding index to true | |
164 | variants.insert(variant_index); | |
165 | true | |
166 | } | |
167 | _ => { | |
168 | // don't know how to add these patterns to a switch | |
169 | false | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
e9174d1e SL |
174 | /// Generates the code to perform a test. |
175 | pub fn perform_test(&mut self, | |
176 | block: BasicBlock, | |
b039eaaf SL |
177 | lvalue: &Lvalue<'tcx>, |
178 | test: &Test<'tcx>) | |
e9174d1e | 179 | -> Vec<BasicBlock> { |
3157f602 | 180 | let source_info = self.source_info(test.span); |
92a42be0 | 181 | match test.kind { |
3157f602 | 182 | TestKind::Switch { adt_def, ref variants } => { |
e9174d1e | 183 | let num_enum_variants = self.hir.num_variants(adt_def); |
3157f602 XL |
184 | let mut otherwise_block = None; |
185 | let target_blocks: Vec<_> = (0..num_enum_variants).map(|i| { | |
186 | if variants.contains(i) { | |
187 | self.cfg.start_new_block() | |
188 | } else { | |
189 | if otherwise_block.is_none() { | |
190 | otherwise_block = Some(self.cfg.start_new_block()); | |
191 | } | |
192 | otherwise_block.unwrap() | |
193 | } | |
194 | }).collect(); | |
195 | debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}", | |
196 | num_enum_variants, variants.iter().count(), variants); | |
197 | self.cfg.terminate(block, source_info, TerminatorKind::Switch { | |
e9174d1e | 198 | discr: lvalue.clone(), |
92a42be0 | 199 | adt_def: adt_def, |
e9174d1e SL |
200 | targets: target_blocks.clone() |
201 | }); | |
202 | target_blocks | |
203 | } | |
204 | ||
92a42be0 | 205 | TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { |
3157f602 XL |
206 | let (targets, term) = match switch_ty.sty { |
207 | // If we're matching on boolean we can | |
208 | // use the If TerminatorKind instead | |
209 | ty::TyBool => { | |
210 | assert!(options.len() > 0 && options.len() <= 2); | |
211 | ||
212 | let (true_bb, else_bb) = | |
213 | (self.cfg.start_new_block(), | |
214 | self.cfg.start_new_block()); | |
215 | ||
216 | let targets = match &options[0] { | |
217 | &ConstVal::Bool(true) => vec![true_bb, else_bb], | |
218 | &ConstVal::Bool(false) => vec![else_bb, true_bb], | |
219 | v => span_bug!(test.span, "expected boolean value but got {:?}", v) | |
220 | }; | |
221 | ||
222 | (targets, | |
223 | TerminatorKind::If { | |
224 | cond: Operand::Consume(lvalue.clone()), | |
225 | targets: (true_bb, else_bb) | |
226 | }) | |
227 | ||
228 | } | |
229 | _ => { | |
230 | // The switch may be inexhaustive so we | |
231 | // add a catch all block | |
232 | let otherwise = self.cfg.start_new_block(); | |
233 | let targets: Vec<_> = | |
234 | options.iter() | |
235 | .map(|_| self.cfg.start_new_block()) | |
236 | .chain(Some(otherwise)) | |
237 | .collect(); | |
238 | ||
239 | (targets.clone(), | |
240 | TerminatorKind::SwitchInt { | |
241 | discr: lvalue.clone(), | |
242 | switch_ty: switch_ty, | |
243 | values: options.clone(), | |
244 | targets: targets | |
245 | }) | |
246 | } | |
247 | }; | |
248 | ||
249 | self.cfg.terminate(block, source_info, term); | |
92a42be0 SL |
250 | targets |
251 | } | |
252 | ||
54a0048b SL |
253 | TestKind::Eq { ref value, mut ty } => { |
254 | let mut val = Operand::Consume(lvalue.clone()); | |
255 | ||
256 | // If we're using b"..." as a pattern, we need to insert an | |
257 | // unsizing coercion, as the byte string has the type &[u8; N]. | |
258 | let expect = if let ConstVal::ByteStr(ref bytes) = *value { | |
259 | let tcx = self.hir.tcx(); | |
260 | ||
261 | // Unsize the lvalue to &[u8], too, if necessary. | |
262 | if let ty::TyRef(region, mt) = ty.sty { | |
263 | if let ty::TyArray(_, _) = mt.ty.sty { | |
264 | ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); | |
265 | let val_slice = self.temp(ty); | |
3157f602 | 266 | self.cfg.push_assign(block, source_info, &val_slice, |
54a0048b SL |
267 | Rvalue::Cast(CastKind::Unsize, val, ty)); |
268 | val = Operand::Consume(val_slice); | |
269 | } | |
270 | } | |
271 | ||
272 | assert!(ty.is_slice()); | |
273 | ||
274 | let array_ty = tcx.mk_array(tcx.types.u8, bytes.len()); | |
275 | let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty); | |
276 | let array = self.literal_operand(test.span, array_ref, Literal::Value { | |
277 | value: value.clone() | |
278 | }); | |
279 | ||
280 | let slice = self.temp(ty); | |
3157f602 | 281 | self.cfg.push_assign(block, source_info, &slice, |
54a0048b SL |
282 | Rvalue::Cast(CastKind::Unsize, array, ty)); |
283 | Operand::Consume(slice) | |
284 | } else { | |
285 | self.literal_operand(test.span, ty, Literal::Value { | |
286 | value: value.clone() | |
287 | }) | |
288 | }; | |
289 | ||
290 | // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. | |
9cc50fc6 | 291 | let fail = self.cfg.start_new_block(); |
54a0048b SL |
292 | if let ty::TyRef(_, mt) = ty.sty { |
293 | assert!(ty.is_slice()); | |
294 | let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap(); | |
295 | let ty = mt.ty; | |
9e0c209e | 296 | let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); |
54a0048b SL |
297 | |
298 | let bool_ty = self.hir.bool_ty(); | |
299 | let eq_result = self.temp(bool_ty); | |
300 | let eq_block = self.cfg.start_new_block(); | |
301 | let cleanup = self.diverge_cleanup(); | |
3157f602 | 302 | self.cfg.terminate(block, source_info, TerminatorKind::Call { |
54a0048b SL |
303 | func: Operand::Constant(Constant { |
304 | span: test.span, | |
305 | ty: mty, | |
306 | literal: method | |
307 | }), | |
308 | args: vec![val, expect], | |
309 | destination: Some((eq_result.clone(), eq_block)), | |
310 | cleanup: cleanup, | |
311 | }); | |
312 | ||
313 | // check the result | |
314 | let block = self.cfg.start_new_block(); | |
3157f602 | 315 | self.cfg.terminate(eq_block, source_info, TerminatorKind::If { |
54a0048b SL |
316 | cond: Operand::Consume(eq_result), |
317 | targets: (block, fail), | |
318 | }); | |
319 | ||
320 | vec![block, fail] | |
321 | } else { | |
322 | let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val); | |
323 | vec![block, fail] | |
324 | } | |
e9174d1e SL |
325 | } |
326 | ||
92a42be0 | 327 | TestKind::Range { ref lo, ref hi, ty } => { |
9cc50fc6 | 328 | // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. |
92a42be0 SL |
329 | let lo = self.literal_operand(test.span, ty.clone(), lo.clone()); |
330 | let hi = self.literal_operand(test.span, ty.clone(), hi.clone()); | |
9cc50fc6 | 331 | let val = Operand::Consume(lvalue.clone()); |
e9174d1e | 332 | |
9cc50fc6 SL |
333 | let fail = self.cfg.start_new_block(); |
334 | let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone()); | |
335 | let block = self.compare(block, fail, test.span, BinOp::Le, val, hi); | |
e9174d1e | 336 | |
9cc50fc6 | 337 | vec![block, fail] |
e9174d1e SL |
338 | } |
339 | ||
340 | TestKind::Len { len, op } => { | |
341 | let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty()); | |
342 | let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); | |
343 | ||
344 | // actual = len(lvalue) | |
3157f602 | 345 | self.cfg.push_assign(block, source_info, |
54a0048b | 346 | &actual, Rvalue::Len(lvalue.clone())); |
e9174d1e SL |
347 | |
348 | // expected = <N> | |
3157f602 | 349 | let expected = self.push_usize(block, source_info, len); |
e9174d1e SL |
350 | |
351 | // result = actual == expected OR result = actual < expected | |
3157f602 | 352 | self.cfg.push_assign(block, source_info, &result, |
b039eaaf SL |
353 | Rvalue::BinaryOp(op, |
354 | Operand::Consume(actual), | |
355 | Operand::Consume(expected))); | |
e9174d1e SL |
356 | |
357 | // branch based on result | |
358 | let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), | |
359 | self.cfg.start_new_block()]; | |
3157f602 | 360 | self.cfg.terminate(block, source_info, TerminatorKind::If { |
e9174d1e | 361 | cond: Operand::Consume(result), |
9cc50fc6 | 362 | targets: (target_blocks[0], target_blocks[1]) |
e9174d1e SL |
363 | }); |
364 | ||
365 | target_blocks | |
366 | } | |
367 | } | |
368 | } | |
369 | ||
9cc50fc6 SL |
370 | fn compare(&mut self, |
371 | block: BasicBlock, | |
372 | fail_block: BasicBlock, | |
373 | span: Span, | |
374 | op: BinOp, | |
375 | left: Operand<'tcx>, | |
376 | right: Operand<'tcx>) -> BasicBlock { | |
e9174d1e | 377 | let bool_ty = self.hir.bool_ty(); |
9cc50fc6 SL |
378 | let result = self.temp(bool_ty); |
379 | ||
380 | // result = op(left, right) | |
3157f602 XL |
381 | let source_info = self.source_info(span); |
382 | self.cfg.push_assign(block, source_info, &result, | |
54a0048b | 383 | Rvalue::BinaryOp(op, left, right)); |
9cc50fc6 SL |
384 | |
385 | // branch based on result | |
386 | let target_block = self.cfg.start_new_block(); | |
3157f602 | 387 | self.cfg.terminate(block, source_info, TerminatorKind::If { |
9cc50fc6 SL |
388 | cond: Operand::Consume(result), |
389 | targets: (target_block, fail_block) | |
390 | }); | |
391 | ||
392 | target_block | |
e9174d1e SL |
393 | } |
394 | ||
92a42be0 SL |
395 | /// Given that we are performing `test` against `test_lvalue`, |
396 | /// this job sorts out what the status of `candidate` will be | |
397 | /// after the test. The `resulting_candidates` vector stores, for | |
398 | /// each possible outcome of `test`, a vector of the candidates | |
399 | /// that will result. This fn should add a (possibly modified) | |
400 | /// clone of candidate into `resulting_candidates` wherever | |
401 | /// appropriate. | |
e9174d1e | 402 | /// |
92a42be0 SL |
403 | /// So, for example, if this candidate is `x @ Some(P0)` and the |
404 | /// test is a variant test, then we would add `(x as Option).0 @ | |
405 | /// P0` to the `resulting_candidates` entry corresponding to the | |
406 | /// variant `Some`. | |
407 | /// | |
408 | /// However, in some cases, the test may just not be relevant to | |
409 | /// candidate. For example, suppose we are testing whether `foo.x == 22`, | |
410 | /// but in one match arm we have `Foo { x: _, ... }`... in that case, | |
411 | /// the test for what value `x` has has no particular relevance | |
412 | /// to this candidate. In such cases, this function just returns false | |
413 | /// without doing anything. This is used by the overall `match_candidates` | |
414 | /// algorithm to structure the match as a whole. See `match_candidates` for | |
415 | /// more details. | |
416 | /// | |
417 | /// FIXME(#29623). In some cases, we have some tricky choices to | |
418 | /// make. for example, if we are testing that `x == 22`, but the | |
419 | /// candidate is `x @ 13..55`, what should we do? In the event | |
420 | /// that the test is true, we know that the candidate applies, but | |
421 | /// in the event of false, we don't know that it *doesn't* | |
422 | /// apply. For now, we return false, indicate that the test does | |
423 | /// not apply to this candidate, but it might be we can get | |
424 | /// tighter match code if we do something a bit different. | |
425 | pub fn sort_candidate<'pat>(&mut self, | |
426 | test_lvalue: &Lvalue<'tcx>, | |
427 | test: &Test<'tcx>, | |
428 | candidate: &Candidate<'pat, 'tcx>, | |
429 | resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>]) | |
430 | -> bool { | |
431 | // Find the match_pair for this lvalue (if any). At present, | |
432 | // afaik, there can be at most one. (In the future, if we | |
433 | // adopted a more general `@` operator, there might be more | |
434 | // than one, but it'd be very unusual to have two sides that | |
435 | // both require tests; you'd expect one side to be simplified | |
436 | // away.) | |
437 | let tested_match_pair = candidate.match_pairs.iter() | |
438 | .enumerate() | |
439 | .filter(|&(_, mp)| mp.lvalue == *test_lvalue) | |
440 | .next(); | |
441 | let (match_pair_index, match_pair) = match tested_match_pair { | |
442 | Some(pair) => pair, | |
443 | None => { | |
444 | // We are not testing this lvalue. Therefore, this | |
445 | // candidate applies to ALL outcomes. | |
446 | return false; | |
e9174d1e | 447 | } |
92a42be0 SL |
448 | }; |
449 | ||
3157f602 | 450 | match (&test.kind, &*match_pair.pattern.kind) { |
92a42be0 SL |
451 | // If we are performing a variant switch, then this |
452 | // informs variant patterns, but nothing else. | |
3157f602 XL |
453 | (&TestKind::Switch { adt_def: tested_adt_def, .. }, |
454 | &PatternKind::Variant { adt_def, variant_index, ref subpatterns }) => { | |
455 | assert_eq!(adt_def, tested_adt_def); | |
456 | let new_candidate = | |
457 | self.candidate_after_variant_switch(match_pair_index, | |
458 | adt_def, | |
459 | variant_index, | |
460 | subpatterns, | |
461 | candidate); | |
462 | resulting_candidates[variant_index].push(new_candidate); | |
463 | true | |
e9174d1e | 464 | } |
3157f602 | 465 | (&TestKind::Switch { .. }, _) => false, |
e9174d1e | 466 | |
92a42be0 SL |
467 | // If we are performing a switch over integers, then this informs integer |
468 | // equality, but nothing else. | |
469 | // | |
3157f602 | 470 | // FIXME(#29623) we could use PatternKind::Range to rule |
92a42be0 | 471 | // things out here, in some cases. |
3157f602 XL |
472 | (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices }, |
473 | &PatternKind::Constant { ref value }) | |
474 | if is_switch_ty(match_pair.pattern.ty) => { | |
475 | let index = indices[value]; | |
476 | let new_candidate = self.candidate_without_match_pair(match_pair_index, | |
477 | candidate); | |
478 | resulting_candidates[index].push(new_candidate); | |
479 | true | |
480 | } | |
481 | (&TestKind::SwitchInt { .. }, _) => false, | |
482 | ||
483 | ||
484 | (&TestKind::Len { len: test_len, op: BinOp::Eq }, | |
485 | &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => { | |
486 | let pat_len = (prefix.len() + suffix.len()) as u64; | |
487 | match (test_len.cmp(&pat_len), slice) { | |
488 | (Ordering::Equal, &None) => { | |
489 | // on true, min_len = len = $actual_length, | |
490 | // on false, len != $actual_length | |
491 | resulting_candidates[0].push( | |
492 | self.candidate_after_slice_test(match_pair_index, | |
493 | candidate, | |
494 | prefix, | |
495 | slice.as_ref(), | |
496 | suffix) | |
497 | ); | |
92a42be0 SL |
498 | true |
499 | } | |
3157f602 XL |
500 | (Ordering::Less, _) => { |
501 | // test_len < pat_len. If $actual_len = test_len, | |
502 | // then $actual_len < pat_len and we don't have | |
503 | // enough elements. | |
504 | resulting_candidates[1].push(candidate.clone()); | |
505 | true | |
506 | } | |
507 | (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => { | |
508 | // This can match both if $actual_len = test_len >= pat_len, | |
509 | // and if $actual_len > test_len. We can't advance. | |
92a42be0 SL |
510 | false |
511 | } | |
3157f602 XL |
512 | (Ordering::Greater, &None) => { |
513 | // test_len != pat_len, so if $actual_len = test_len, then | |
514 | // $actual_len != pat_len. | |
515 | resulting_candidates[1].push(candidate.clone()); | |
516 | true | |
517 | } | |
e9174d1e | 518 | } |
e9174d1e SL |
519 | } |
520 | ||
3157f602 XL |
521 | (&TestKind::Len { len: test_len, op: BinOp::Ge }, |
522 | &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => { | |
523 | // the test is `$actual_len >= test_len` | |
524 | let pat_len = (prefix.len() + suffix.len()) as u64; | |
525 | match (test_len.cmp(&pat_len), slice) { | |
526 | (Ordering::Equal, &Some(_)) => { | |
527 | // $actual_len >= test_len = pat_len, | |
528 | // so we can match. | |
529 | resulting_candidates[0].push( | |
530 | self.candidate_after_slice_test(match_pair_index, | |
531 | candidate, | |
532 | prefix, | |
533 | slice.as_ref(), | |
534 | suffix) | |
535 | ); | |
536 | true | |
537 | } | |
538 | (Ordering::Less, _) | (Ordering::Equal, &None) => { | |
539 | // test_len <= pat_len. If $actual_len < test_len, | |
540 | // then it is also < pat_len, so the test passing is | |
541 | // necessary (but insufficient). | |
542 | resulting_candidates[0].push(candidate.clone()); | |
54a0048b SL |
543 | true |
544 | } | |
3157f602 XL |
545 | (Ordering::Greater, &None) => { |
546 | // test_len > pat_len. If $actual_len >= test_len > pat_len, | |
547 | // then we know we won't have a match. | |
548 | resulting_candidates[1].push(candidate.clone()); | |
549 | true | |
550 | } | |
551 | (Ordering::Greater, &Some(_)) => { | |
552 | // test_len < pat_len, and is therefore less | |
553 | // strict. This can still go both ways. | |
554 | false | |
555 | } | |
54a0048b SL |
556 | } |
557 | } | |
558 | ||
3157f602 XL |
559 | (&TestKind::Eq { .. }, _) | |
560 | (&TestKind::Range { .. }, _) | | |
561 | (&TestKind::Len { .. }, _) => { | |
92a42be0 SL |
562 | // These are all binary tests. |
563 | // | |
564 | // FIXME(#29623) we can be more clever here | |
565 | let pattern_test = self.test(&match_pair); | |
566 | if pattern_test.kind == test.kind { | |
567 | let new_candidate = self.candidate_without_match_pair(match_pair_index, | |
568 | candidate); | |
569 | resulting_candidates[0].push(new_candidate); | |
570 | true | |
e9174d1e | 571 | } else { |
92a42be0 | 572 | false |
e9174d1e SL |
573 | } |
574 | } | |
92a42be0 SL |
575 | } |
576 | } | |
e9174d1e | 577 | |
92a42be0 SL |
578 | fn candidate_without_match_pair<'pat>(&mut self, |
579 | match_pair_index: usize, | |
580 | candidate: &Candidate<'pat, 'tcx>) | |
581 | -> Candidate<'pat, 'tcx> { | |
582 | let other_match_pairs = | |
583 | candidate.match_pairs.iter() | |
584 | .enumerate() | |
585 | .filter(|&(index, _)| index != match_pair_index) | |
586 | .map(|(_, mp)| mp.clone()) | |
587 | .collect(); | |
588 | Candidate { | |
54a0048b | 589 | span: candidate.span, |
92a42be0 SL |
590 | match_pairs: other_match_pairs, |
591 | bindings: candidate.bindings.clone(), | |
592 | guard: candidate.guard.clone(), | |
593 | arm_index: candidate.arm_index, | |
594 | } | |
595 | } | |
e9174d1e | 596 | |
3157f602 XL |
597 | fn candidate_after_slice_test<'pat>(&mut self, |
598 | match_pair_index: usize, | |
599 | candidate: &Candidate<'pat, 'tcx>, | |
600 | prefix: &'pat [Pattern<'tcx>], | |
601 | opt_slice: Option<&'pat Pattern<'tcx>>, | |
602 | suffix: &'pat [Pattern<'tcx>]) | |
603 | -> Candidate<'pat, 'tcx> { | |
604 | let mut new_candidate = | |
605 | self.candidate_without_match_pair(match_pair_index, candidate); | |
606 | self.prefix_slice_suffix( | |
607 | &mut new_candidate.match_pairs, | |
608 | &candidate.match_pairs[match_pair_index].lvalue, | |
609 | prefix, | |
610 | opt_slice, | |
611 | suffix); | |
612 | ||
613 | new_candidate | |
614 | } | |
615 | ||
92a42be0 SL |
616 | fn candidate_after_variant_switch<'pat>(&mut self, |
617 | match_pair_index: usize, | |
476ff2be | 618 | adt_def: &'tcx ty::AdtDef, |
92a42be0 SL |
619 | variant_index: usize, |
620 | subpatterns: &'pat [FieldPattern<'tcx>], | |
621 | candidate: &Candidate<'pat, 'tcx>) | |
622 | -> Candidate<'pat, 'tcx> { | |
623 | let match_pair = &candidate.match_pairs[match_pair_index]; | |
624 | ||
625 | // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, | |
626 | // we want to create a set of derived match-patterns like | |
627 | // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. | |
628 | let elem = ProjectionElem::Downcast(adt_def, variant_index); | |
629 | let downcast_lvalue = match_pair.lvalue.clone().elem(elem); // `(x as Variant)` | |
630 | let consequent_match_pairs = | |
631 | subpatterns.iter() | |
632 | .map(|subpattern| { | |
633 | // e.g., `(x as Variant).0` | |
7453a54e | 634 | let lvalue = downcast_lvalue.clone().field(subpattern.field, |
54a0048b | 635 | subpattern.pattern.ty); |
92a42be0 SL |
636 | // e.g., `(x as Variant).0 @ P1` |
637 | MatchPair::new(lvalue, &subpattern.pattern) | |
638 | }); | |
639 | ||
640 | // In addition, we need all the other match pairs from the old candidate. | |
641 | let other_match_pairs = | |
642 | candidate.match_pairs.iter() | |
643 | .enumerate() | |
644 | .filter(|&(index, _)| index != match_pair_index) | |
645 | .map(|(_, mp)| mp.clone()); | |
646 | ||
647 | let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect(); | |
648 | ||
649 | Candidate { | |
54a0048b | 650 | span: candidate.span, |
92a42be0 SL |
651 | match_pairs: all_match_pairs, |
652 | bindings: candidate.bindings.clone(), | |
653 | guard: candidate.guard.clone(), | |
654 | arm_index: candidate.arm_index, | |
e9174d1e SL |
655 | } |
656 | } | |
657 | ||
92a42be0 | 658 | fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { |
54a0048b SL |
659 | span_bug!(match_pair.pattern.span, |
660 | "simplifyable pattern found: {:?}", | |
661 | match_pair.pattern) | |
e9174d1e SL |
662 | } |
663 | } | |
92a42be0 SL |
664 | |
665 | fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool { | |
666 | ty.is_integral() || ty.is_char() || ty.is_bool() | |
667 | } |