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.
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.
14 use rustc_data_structures::fnv::FnvHashMap;
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;
23 use tcx::syntax::ptr::P;
24 use tcx::to_ref::ToRef;
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.
34 /// Test1(flavor /* def 1 */) |
35 /// Test2(flavor /* def 2 */) if flavor /* ref 1 */.is_tasty() => { ... }
39 #[derive(Clone, Debug)]
40 pub struct PatNode<'tcx> {
42 binding_map: Option<Rc<FnvHashMap<ast::Ident, ast::NodeId>>>
45 impl<'tcx> PatNode<'tcx> {
46 pub fn new(pat: &'tcx hir::Pat,
47 binding_map: Option<Rc<FnvHashMap<ast::Ident, ast::NodeId>>>)
51 binding_map: binding_map,
55 pub fn irrefutable(pat: &'tcx hir::Pat)
57 PatNode::new(pat, None)
60 fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<Cx<'a,'tcx>> {
61 PatNode::new(pat, self.binding_map.clone()).to_ref()
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()
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))
72 fn slice_or_array_pattern<'a>(&self,
73 cx: &mut Cx<'a, '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>>
82 // matching a slice or fixed-length array
84 prefix: self.pat_refs(prefix),
85 slice: self.opt_pat_ref(slice),
86 suffix: self.pat_refs(suffix),
89 ty::TyArray(_, len) => {
91 assert!(len >= prefix.len() + suffix.len());
93 prefix: self.pat_refs(prefix),
94 slice: self.opt_pat_ref(slice),
95 suffix: self.pat_refs(suffix),
100 cx.tcx.sess.span_bug(
102 "unexpanded macro or bad constant etc");
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>>
112 let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_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 }
121 PatternKind::Leaf { subpatterns: subpatterns }
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 }
132 cx.tcx.sess.span_bug(
134 &format!("inappropriate def for pattern: {:?}", def));
140 impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
141 type Output = Pattern<Cx<'a,'tcx>>;
143 fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Pattern<Cx<'a,'tcx>> {
144 let kind = match self.pat.node {
148 hir::PatLit(ref lt) =>
149 PatternKind::Constant { expr: lt.to_ref() },
151 hir::PatRange(ref begin, ref end) =>
152 PatternKind::Range { lo: begin.to_ref(),
155 hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..)
156 if pat_is_resolved_const(&cx.tcx.def_map, self.pat) =>
158 let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
160 def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
161 match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
163 PatternKind::Constant { expr: const_expr.to_ref() },
165 cx.tcx.sess.span_bug(
167 &format!("cannot eval constant: {:?}", def_id)),
170 cx.tcx.sess.span_bug(
172 &format!("def not a constant: {:?}", def)),
176 hir::PatRegion(ref subpattern, _) |
177 hir::PatBox(ref subpattern) => {
178 PatternKind::Deref { subpattern: self.pat_ref(subpattern) }
181 hir::PatVec(ref prefix, ref slice, ref suffix) => {
182 let ty = cx.tcx.node_id_to_type(self.pat.id);
186 subpattern: Pattern {
189 kind: self.slice_or_array_pattern(cx, mt.ty, prefix,
196 self.slice_or_array_pattern(cx, ty, prefix, slice, suffix),
199 cx.tcx.sess.span_bug(
201 &format!("unexpanded type for vector pattern: {:?}", sty)),
205 hir::PatTup(ref subpatterns) => {
209 .map(|(i, subpattern)| FieldPatternRef {
210 field: Field::Indexed(i),
211 pattern: self.pat_ref(subpattern),
215 PatternKind::Leaf { subpatterns: subpatterns }
218 hir::PatIdent(bm, ref ident, ref sub)
219 if pat_is_binding(&cx.tcx.def_map, self.pat) =>
221 let id = match self.binding_map {
223 Some(ref map) => map[&ident.node],
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),
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)),
240 PatternKind::Binding {
241 mutability: mutability,
246 subpattern: self.opt_pat_ref(sub),
250 hir::PatIdent(..) => {
251 self.variant_or_leaf(cx, vec![])
254 hir::PatEnum(_, ref opt_subpatterns) => {
256 opt_subpatterns.iter()
257 .flat_map(|v| v.iter())
259 .map(|(i, field)| FieldPatternRef {
260 field: Field::Indexed(i),
261 pattern: self.pat_ref(field),
264 self.variant_or_leaf(cx, subpatterns)
267 hir::PatStruct(_, ref fields, _) => {
270 .map(|field| FieldPatternRef {
271 field: Field::Named(field.node.name),
272 pattern: self.pat_ref(&field.node.pat),
275 self.variant_or_leaf(cx, subpatterns)
278 hir::PatQPath(..) => {
279 cx.tcx.sess.span_bug(
281 "unexpanded macro or bad constant etc");
285 let ty = cx.tcx.node_id_to_type(self.pat.id);
287 Pattern { span: self.pat.span,