]>
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 | //! Simplifying Candidates | |
12 | //! | |
13 | //! *Simplifying* a match pair `lvalue @ pattern` means breaking it down | |
14 | //! into bindings or other, simpler match pairs. For example: | |
15 | //! | |
16 | //! - `lvalue @ (P1, P2)` can be simplified to `[lvalue.0 @ P1, lvalue.1 @ P2]` | |
17 | //! - `lvalue @ x` can be simplified to `[]` by binding `x` to `lvalue` | |
18 | //! | |
19 | //! The `simplify_candidate` routine just repeatedly applies these | |
20 | //! sort of simplifications until there is nothing left to | |
21 | //! simplify. Match pairs cannot be simplified if they require some | |
22 | //! sort of test: for example, testing which variant an enum is, or | |
23 | //! testing a value against a constant. | |
24 | ||
92a42be0 | 25 | use build::{BlockAnd, BlockAndExtension, Builder}; |
e9174d1e SL |
26 | use build::matches::{Binding, MatchPair, Candidate}; |
27 | use hair::*; | |
c30ab7b3 | 28 | use rustc::mir::*; |
8bb4bdeb | 29 | use rustc_data_structures::fx::FxHashMap; |
e9174d1e SL |
30 | |
31 | use std::mem; | |
32 | ||
a7813a04 | 33 | impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { |
92a42be0 | 34 | pub fn simplify_candidate<'pat>(&mut self, |
3157f602 | 35 | block: BasicBlock, |
92a42be0 SL |
36 | candidate: &mut Candidate<'pat, 'tcx>) |
37 | -> BlockAnd<()> { | |
e9174d1e SL |
38 | // repeatedly simplify match pairs until fixed point is reached |
39 | loop { | |
40 | let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]); | |
41 | let mut progress = match_pairs.len(); // count how many were simplified | |
42 | for match_pair in match_pairs { | |
3157f602 XL |
43 | match self.simplify_match_pair(match_pair, candidate) { |
44 | Ok(()) => {} | |
e9174d1e SL |
45 | Err(match_pair) => { |
46 | candidate.match_pairs.push(match_pair); | |
47 | progress -= 1; // this one was not simplified | |
48 | } | |
49 | } | |
50 | } | |
51 | if progress == 0 { | |
52 | return block.unit(); // if we were not able to simplify any, done. | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
57 | /// Tries to simplify `match_pair`, returning true if | |
58 | /// successful. If successful, new match pairs and bindings will | |
b039eaaf SL |
59 | /// have been pushed into the candidate. If no simplification is |
60 | /// possible, Err is returned and no changes are made to | |
61 | /// candidate. | |
92a42be0 | 62 | fn simplify_match_pair<'pat>(&mut self, |
92a42be0 SL |
63 | match_pair: MatchPair<'pat, 'tcx>, |
64 | candidate: &mut Candidate<'pat, 'tcx>) | |
3157f602 | 65 | -> Result<(), MatchPair<'pat, 'tcx>> { |
92a42be0 SL |
66 | match *match_pair.pattern.kind { |
67 | PatternKind::Wild => { | |
e9174d1e | 68 | // nothing left to do |
3157f602 | 69 | Ok(()) |
e9174d1e SL |
70 | } |
71 | ||
92a42be0 | 72 | PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => { |
e9174d1e SL |
73 | candidate.bindings.push(Binding { |
74 | name: name, | |
75 | mutability: mutability, | |
76 | span: match_pair.pattern.span, | |
77 | source: match_pair.lvalue.clone(), | |
78 | var_id: var, | |
79 | var_ty: ty, | |
80 | binding_mode: mode, | |
81 | }); | |
82 | ||
92a42be0 | 83 | if let Some(subpattern) = subpattern.as_ref() { |
e9174d1e | 84 | // this is the `x @ P` case; have to keep matching against `P` now |
e9174d1e SL |
85 | candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern)); |
86 | } | |
87 | ||
3157f602 | 88 | Ok(()) |
e9174d1e SL |
89 | } |
90 | ||
91 | PatternKind::Constant { .. } => { | |
92 | // FIXME normalize patterns when possible | |
93 | Err(match_pair) | |
94 | } | |
95 | ||
54a0048b | 96 | PatternKind::Range { .. } | |
3157f602 | 97 | PatternKind::Slice { .. } => { |
54a0048b SL |
98 | Err(match_pair) |
99 | } | |
100 | ||
32a655c1 SL |
101 | PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { |
102 | if self.hir.tcx().sess.features.borrow().never_type { | |
103 | let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { | |
104 | i == variant_index || { | |
8bb4bdeb | 105 | let mut visited = FxHashMap::default(); |
32a655c1 SL |
106 | let node_set = v.uninhabited_from(&mut visited, |
107 | self.hir.tcx(), | |
108 | substs, | |
109 | adt_def.adt_kind()); | |
110 | !node_set.is_empty() | |
111 | } | |
112 | }); | |
113 | if irrefutable { | |
114 | let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); | |
115 | candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); | |
116 | Ok(()) | |
117 | } else { | |
118 | Err(match_pair) | |
119 | } | |
120 | } else { | |
121 | Err(match_pair) | |
122 | } | |
123 | }, | |
124 | ||
3157f602 XL |
125 | PatternKind::Array { ref prefix, ref slice, ref suffix } => { |
126 | self.prefix_slice_suffix(&mut candidate.match_pairs, | |
127 | &match_pair.lvalue, | |
128 | prefix, | |
129 | slice.as_ref(), | |
130 | suffix); | |
131 | Ok(()) | |
e9174d1e SL |
132 | } |
133 | ||
92a42be0 | 134 | PatternKind::Leaf { ref subpatterns } => { |
e9174d1e | 135 | // tuple struct, match subpats (if any) |
b039eaaf SL |
136 | candidate.match_pairs |
137 | .extend(self.field_match_pairs(match_pair.lvalue, subpatterns)); | |
3157f602 | 138 | Ok(()) |
e9174d1e SL |
139 | } |
140 | ||
92a42be0 | 141 | PatternKind::Deref { ref subpattern } => { |
e9174d1e | 142 | let lvalue = match_pair.lvalue.deref(); |
e9174d1e | 143 | candidate.match_pairs.push(MatchPair::new(lvalue, subpattern)); |
3157f602 | 144 | Ok(()) |
e9174d1e SL |
145 | } |
146 | } | |
147 | } | |
148 | } |