]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/tcx/pattern.rs
Auto merge of #27893 - nikomatsakis:mir, r=nrc
[rust.git] / src / librustc_mir / tcx / pattern.rs
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 use hair::*;
12 use repr::*;
13
14 use rustc_data_structures::fnv::FnvHashMap;
15 use std::rc::Rc;
16 use tcx::Cx;
17 use tcx::rustc::middle::const_eval::lookup_const_by_id;
18 use tcx::rustc::middle::def;
19 use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
20 use tcx::rustc::middle::ty::{self, Ty};
21 use tcx::rustc_front::hir;
22 use tcx::syntax::ast;
23 use tcx::syntax::ptr::P;
24 use tcx::to_ref::ToRef;
25
26 /// When there are multiple patterns in a single arm, each one has its
27 /// own node-ids for the bindings.  References to the variables always
28 /// use the node-ids from the first pattern in the arm, so we just
29 /// remap the ids for all subsequent bindings to the first one.
30 ///
31 /// Example:
32 /// ```
33 /// match foo {
34 ///    Test1(flavor /* def 1 */) |
35 ///    Test2(flavor /* def 2 */) if flavor /* ref 1 */.is_tasty() => { ... }
36 ///    _ => { ... }
37 /// }
38 /// ```
39 #[derive(Clone, Debug)]
40 pub struct PatNode<'tcx> {
41     pat: &'tcx hir::Pat,
42     binding_map: Option<Rc<FnvHashMap<ast::Ident, ast::NodeId>>>
43 }
44
45 impl<'tcx> PatNode<'tcx> {
46     pub fn new(pat: &'tcx hir::Pat,
47                binding_map: Option<Rc<FnvHashMap<ast::Ident, ast::NodeId>>>)
48                -> PatNode<'tcx> {
49         PatNode {
50             pat: pat,
51             binding_map: binding_map,
52         }
53     }
54
55     pub fn irrefutable(pat: &'tcx hir::Pat)
56                        -> PatNode<'tcx> {
57         PatNode::new(pat, None)
58     }
59
60     fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<Cx<'a,'tcx>> {
61         PatNode::new(pat, self.binding_map.clone()).to_ref()
62     }
63
64     fn pat_refs<'a>(&self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<PatternRef<Cx<'a,'tcx>>> {
65         pats.iter().map(|p| self.pat_ref(p)).collect()
66     }
67
68     fn opt_pat_ref<'a>(&self, pat: &'tcx Option<P<hir::Pat>>) -> Option<PatternRef<Cx<'a,'tcx>>> {
69         pat.as_ref().map(|p| self.pat_ref(p))
70     }
71
72     fn slice_or_array_pattern<'a>(&self,
73                                   cx: &mut Cx<'a, 'tcx>,
74                                   ty: Ty<'tcx>,
75                                   prefix: &'tcx Vec<P<hir::Pat>>,
76                                   slice: &'tcx Option<P<hir::Pat>>,
77                                   suffix: &'tcx Vec<P<hir::Pat>>)
78                                   -> PatternKind<Cx<'a,'tcx>>
79     {
80         match ty.sty {
81             ty::TySlice(..) =>
82                 // matching a slice or fixed-length array
83                 PatternKind::Slice {
84                     prefix: self.pat_refs(prefix),
85                     slice: self.opt_pat_ref(slice),
86                     suffix: self.pat_refs(suffix),
87                 },
88
89             ty::TyArray(_, len) => {
90                 // fixed-length array
91                 assert!(len >= prefix.len() + suffix.len());
92                 PatternKind::Array {
93                     prefix: self.pat_refs(prefix),
94                     slice: self.opt_pat_ref(slice),
95                     suffix: self.pat_refs(suffix),
96                 }
97             }
98
99             _ => {
100                 cx.tcx.sess.span_bug(
101                     self.pat.span,
102                     "unexpanded macro or bad constant etc");
103             }
104         }
105     }
106
107     fn variant_or_leaf<'a>(&self,
108                            cx: &mut Cx<'a, 'tcx>,
109                            subpatterns: Vec<FieldPatternRef<Cx<'a,'tcx>>>)
110                            -> PatternKind<Cx<'a,'tcx>>
111     {
112         let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
113         match def {
114             def::DefVariant(enum_id, variant_id, _) => {
115                 let adt_def = cx.tcx.lookup_adt_def(enum_id);
116                 if adt_def.variants.len() > 1 {
117                     PatternKind::Variant { adt_def: adt_def,
118                                            variant_index: adt_def.variant_index_with_id(variant_id),
119                                            subpatterns: subpatterns }
120                 } else {
121                     PatternKind::Leaf { subpatterns: subpatterns }
122                 }
123             }
124
125             // NB: resolving to DefStruct means the struct *constructor*,
126             // not the struct as a type.
127             def::DefStruct(..) | def::DefTy(..) => {
128                 PatternKind::Leaf { subpatterns: subpatterns }
129             }
130
131             _ => {
132                 cx.tcx.sess.span_bug(
133                     self.pat.span,
134                     &format!("inappropriate def for pattern: {:?}", def));
135             }
136         }
137     }
138 }
139
140 impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
141     type Output = Pattern<Cx<'a,'tcx>>;
142
143     fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Pattern<Cx<'a,'tcx>> {
144         let kind = match self.pat.node {
145             hir::PatWild(..) =>
146                 PatternKind::Wild,
147
148             hir::PatLit(ref lt) =>
149                 PatternKind::Constant { expr: lt.to_ref() },
150
151             hir::PatRange(ref begin, ref end) =>
152                 PatternKind::Range { lo: begin.to_ref(),
153                                      hi: end.to_ref() },
154
155             hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..)
156                 if pat_is_resolved_const(&cx.tcx.def_map, self.pat) =>
157             {
158                 let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
159                 match def {
160                     def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
161                         match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
162                             Some(const_expr) =>
163                                 PatternKind::Constant { expr: const_expr.to_ref() },
164                             None =>
165                                 cx.tcx.sess.span_bug(
166                                     self.pat.span,
167                                     &format!("cannot eval constant: {:?}", def_id)),
168                         },
169                     _ =>
170                         cx.tcx.sess.span_bug(
171                             self.pat.span,
172                             &format!("def not a constant: {:?}", def)),
173                 }
174             }
175
176             hir::PatRegion(ref subpattern, _) |
177             hir::PatBox(ref subpattern) => {
178                 PatternKind::Deref { subpattern: self.pat_ref(subpattern) }
179             }
180
181             hir::PatVec(ref prefix, ref slice, ref suffix) => {
182                 let ty = cx.tcx.node_id_to_type(self.pat.id);
183                 match ty.sty {
184                     ty::TyRef(_, mt) =>
185                         PatternKind::Deref {
186                             subpattern: Pattern {
187                                 ty: mt.ty,
188                                 span: self.pat.span,
189                                 kind: self.slice_or_array_pattern(cx, mt.ty, prefix,
190                                                                   slice, suffix),
191                             }.to_ref()
192                         },
193
194                     ty::TySlice(..) |
195                     ty::TyArray(..) =>
196                         self.slice_or_array_pattern(cx, ty, prefix, slice, suffix),
197
198                     ref sty =>
199                         cx.tcx.sess.span_bug(
200                             self.pat.span,
201                             &format!("unexpanded type for vector pattern: {:?}", sty)),
202                 }
203             }
204
205             hir::PatTup(ref subpatterns) => {
206                 let subpatterns =
207                     subpatterns.iter()
208                                .enumerate()
209                                .map(|(i, subpattern)| FieldPatternRef {
210                                    field: Field::Indexed(i),
211                                    pattern: self.pat_ref(subpattern),
212                                })
213                                .collect();
214
215                 PatternKind::Leaf { subpatterns: subpatterns }
216             }
217
218             hir::PatIdent(bm, ref ident, ref sub)
219                 if pat_is_binding(&cx.tcx.def_map, self.pat) =>
220             {
221                 let id = match self.binding_map {
222                     None => self.pat.id,
223                     Some(ref map) => map[&ident.node],
224                 };
225                 let var_ty = cx.tcx.node_id_to_type(self.pat.id);
226                 let region = match var_ty.sty {
227                     ty::TyRef(&r, _) => Some(r),
228                     _ => None,
229                 };
230                 let (mutability, mode) = match bm {
231                     hir::BindByValue(hir::MutMutable) =>
232                         (Mutability::Mut, BindingMode::ByValue),
233                     hir::BindByValue(hir::MutImmutable) =>
234                         (Mutability::Not, BindingMode::ByValue),
235                     hir::BindByRef(hir::MutMutable) =>
236                         (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)),
237                     hir::BindByRef(hir::MutImmutable) =>
238                         (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)),
239                 };
240                 PatternKind::Binding {
241                     mutability: mutability,
242                     mode: mode,
243                     name: ident.node,
244                     var: id,
245                     ty: var_ty,
246                     subpattern: self.opt_pat_ref(sub),
247                 }
248             }
249
250             hir::PatIdent(..) => {
251                 self.variant_or_leaf(cx, vec![])
252             }
253
254             hir::PatEnum(_, ref opt_subpatterns) => {
255                 let subpatterns =
256                     opt_subpatterns.iter()
257                                    .flat_map(|v| v.iter())
258                                    .enumerate()
259                                    .map(|(i, field)| FieldPatternRef {
260                                        field: Field::Indexed(i),
261                                        pattern: self.pat_ref(field),
262                                    })
263                                    .collect();
264                 self.variant_or_leaf(cx, subpatterns)
265             }
266
267             hir::PatStruct(_, ref fields, _) => {
268                 let subpatterns =
269                     fields.iter()
270                           .map(|field| FieldPatternRef {
271                               field: Field::Named(field.node.ident.name),
272                               pattern: self.pat_ref(&field.node.pat),
273                           })
274                           .collect();
275                 self.variant_or_leaf(cx, subpatterns)
276             }
277
278             hir::PatQPath(..) => {
279                 cx.tcx.sess.span_bug(
280                     self.pat.span,
281                     "unexpanded macro or bad constant etc");
282             }
283         };
284
285         let ty = cx.tcx.node_id_to_type(self.pat.id);
286
287         Pattern { span: self.pat.span,
288                   ty: ty,
289                   kind: kind }
290     }
291 }