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.
13 use rustc_data_structures
::fnv
::FnvHashMap
;
14 use rustc_const_eval
as const_eval
;
15 use rustc
::hir
::def
::Def
;
16 use rustc
::hir
::pat_util
::{pat_is_resolved_const, pat_is_binding}
;
17 use rustc
::ty
::{self, Ty}
;
18 use rustc
::mir
::repr
::*;
19 use rustc
::hir
::{self, PatKind}
;
21 use syntax
::codemap
::Span
;
24 /// When there are multiple patterns in a single arm, each one has its
25 /// own node-ids for the bindings. References to the variables always
26 /// use the node-ids from the first pattern in the arm, so we just
27 /// remap the ids for all subsequent bindings to the first one.
32 /// Test1(flavor /* def 1 */) |
33 /// Test2(flavor /* def 2 */) if flavor /* ref 1 */.is_tasty() => { ... }
37 struct PatCx
<'patcx
, 'cx
: 'patcx
, 'tcx
: 'cx
> {
38 cx
: &'patcx
mut Cx
<'cx
, 'tcx
>,
39 binding_map
: Option
<&'patcx FnvHashMap
<ast
::Name
, ast
::NodeId
>>,
42 impl<'cx
, 'tcx
> Cx
<'cx
, 'tcx
> {
43 pub fn irrefutable_pat(&mut self, pat
: &hir
::Pat
) -> Pattern
<'tcx
> {
44 PatCx
::new(self, None
).to_pattern(pat
)
47 pub fn refutable_pat(&mut self,
48 binding_map
: Option
<&FnvHashMap
<ast
::Name
, ast
::NodeId
>>,
51 PatCx
::new(self, binding_map
).to_pattern(pat
)
55 impl<'patcx
, 'cx
, 'tcx
> PatCx
<'patcx
, 'cx
, 'tcx
> {
56 fn new(cx
: &'patcx
mut Cx
<'cx
, 'tcx
>,
57 binding_map
: Option
<&'patcx FnvHashMap
<ast
::Name
, ast
::NodeId
>>)
58 -> PatCx
<'patcx
, 'cx
, 'tcx
> {
61 binding_map
: binding_map
,
65 fn to_pattern(&mut self, pat
: &hir
::Pat
) -> Pattern
<'tcx
> {
66 let mut ty
= self.cx
.tcx
.node_id_to_type(pat
.id
);
68 let kind
= match pat
.node
{
69 PatKind
::Wild
=> PatternKind
::Wild
,
71 PatKind
::Lit(ref value
) => {
72 let value
= const_eval
::eval_const_expr(self.cx
.tcx
, value
);
73 PatternKind
::Constant { value: value }
76 PatKind
::Range(ref lo
, ref hi
) => {
77 let lo
= const_eval
::eval_const_expr(self.cx
.tcx
, lo
);
78 let lo
= Literal
::Value { value: lo }
;
79 let hi
= const_eval
::eval_const_expr(self.cx
.tcx
, hi
);
80 let hi
= Literal
::Value { value: hi }
;
81 PatternKind
::Range { lo: lo, hi: hi }
84 PatKind
::Path(..) | PatKind
::Ident(..) | PatKind
::QPath(..)
85 if pat_is_resolved_const(&self.cx
.tcx
.def_map
.borrow(), pat
) =>
87 let def
= self.cx
.tcx
.def_map
.borrow().get(&pat
.id
).unwrap().full_def();
89 Def
::Const(def_id
) | Def
::AssociatedConst(def_id
) => {
90 let substs
= Some(self.cx
.tcx
.node_id_item_substs(pat
.id
).substs
);
91 match const_eval
::lookup_const_by_id(self.cx
.tcx
, def_id
, substs
) {
92 Some((const_expr
, _const_ty
)) => {
93 match const_eval
::const_expr_to_pat(self.cx
.tcx
,
98 return self.to_pattern(&pat
),
101 pat
.span
, "illegal constant"),
107 "cannot eval constant: {:?}",
115 "def not a constant: {:?}",
120 PatKind
::Ref(ref subpattern
, _
) |
121 PatKind
::Box(ref subpattern
) => {
122 PatternKind
::Deref { subpattern: self.to_pattern(subpattern) }
125 PatKind
::Vec(ref prefix
, ref slice
, ref suffix
) => {
126 let ty
= self.cx
.tcx
.node_id_to_type(pat
.id
);
130 subpattern
: Pattern
{
133 kind
: Box
::new(self.slice_or_array_pattern(pat
.span
, mt
.ty
, prefix
,
140 self.slice_or_array_pattern(pat
.span
, ty
, prefix
, slice
, suffix
),
145 "unexpanded type for vector pattern: {:?}",
150 PatKind
::Tup(ref subpatterns
) => {
154 .map(|(i
, subpattern
)| FieldPattern
{
155 field
: Field
::new(i
),
156 pattern
: self.to_pattern(subpattern
),
160 PatternKind
::Leaf { subpatterns: subpatterns }
163 PatKind
::Ident(bm
, ref ident
, ref sub
)
164 if pat_is_binding(&self.cx
.tcx
.def_map
.borrow(), pat
) =>
166 let id
= match self.binding_map
{
168 Some(ref map
) => map
[&ident
.node
.name
],
170 let var_ty
= self.cx
.tcx
.node_id_to_type(pat
.id
);
171 let region
= match var_ty
.sty
{
172 ty
::TyRef(&r
, _
) => Some(r
),
175 let (mutability
, mode
) = match bm
{
176 hir
::BindByValue(hir
::MutMutable
) =>
177 (Mutability
::Mut
, BindingMode
::ByValue
),
178 hir
::BindByValue(hir
::MutImmutable
) =>
179 (Mutability
::Not
, BindingMode
::ByValue
),
180 hir
::BindByRef(hir
::MutMutable
) =>
181 (Mutability
::Not
, BindingMode
::ByRef(region
.unwrap(), BorrowKind
::Mut
)),
182 hir
::BindByRef(hir
::MutImmutable
) =>
183 (Mutability
::Not
, BindingMode
::ByRef(region
.unwrap(), BorrowKind
::Shared
)),
186 // A ref x pattern is the same node used for x, and as such it has
187 // x's type, which is &T, where we want T (the type being matched).
188 if let hir
::BindByRef(_
) = bm
{
189 if let ty
::TyRef(_
, mt
) = ty
.sty
{
192 bug
!("`ref {}` has wrong type {}", ident
.node
, ty
);
196 PatternKind
::Binding
{
197 mutability
: mutability
,
199 name
: ident
.node
.name
,
202 subpattern
: self.to_opt_pattern(sub
),
206 PatKind
::Ident(..) | PatKind
::Path(..) => {
207 self.variant_or_leaf(pat
, vec
![])
210 PatKind
::TupleStruct(_
, ref opt_subpatterns
) => {
212 opt_subpatterns
.iter()
213 .flat_map(|v
| v
.iter())
215 .map(|(i
, field
)| FieldPattern
{
216 field
: Field
::new(i
),
217 pattern
: self.to_pattern(field
),
220 self.variant_or_leaf(pat
, subpatterns
)
223 PatKind
::Struct(_
, ref fields
, _
) => {
224 let pat_ty
= self.cx
.tcx
.node_id_to_type(pat
.id
);
225 let adt_def
= match pat_ty
.sty
{
226 ty
::TyStruct(adt_def
, _
) | ty
::TyEnum(adt_def
, _
) => adt_def
,
230 "struct pattern not applied to struct or enum");
234 let def
= self.cx
.tcx
.def_map
.borrow().get(&pat
.id
).unwrap().full_def();
235 let variant_def
= adt_def
.variant_of_def(def
);
240 let index
= variant_def
.index_of_field_named(field
.node
.name
);
241 let index
= index
.unwrap_or_else(|| {
244 "no field with name {:?}",
248 field
: Field
::new(index
),
249 pattern
: self.to_pattern(&field
.node
.pat
),
254 self.variant_or_leaf(pat
, subpatterns
)
257 PatKind
::QPath(..) => {
258 span_bug
!(pat
.span
, "unexpanded macro or bad constant etc");
265 kind
: Box
::new(kind
),
269 fn to_patterns(&mut self, pats
: &[P
<hir
::Pat
>]) -> Vec
<Pattern
<'tcx
>> {
270 pats
.iter().map(|p
| self.to_pattern(p
)).collect()
273 fn to_opt_pattern(&mut self, pat
: &Option
<P
<hir
::Pat
>>) -> Option
<Pattern
<'tcx
>> {
274 pat
.as_ref().map(|p
| self.to_pattern(p
))
277 fn slice_or_array_pattern(&mut self,
280 prefix
: &[P
<hir
::Pat
>],
281 slice
: &Option
<P
<hir
::Pat
>>,
282 suffix
: &[P
<hir
::Pat
>])
283 -> PatternKind
<'tcx
> {
286 // matching a slice or fixed-length array
288 prefix
: self.to_patterns(prefix
),
289 slice
: self.to_opt_pattern(slice
),
290 suffix
: self.to_patterns(suffix
),
294 ty
::TyArray(_
, len
) => {
295 // fixed-length array
296 assert
!(len
>= prefix
.len() + suffix
.len());
298 prefix
: self.to_patterns(prefix
),
299 slice
: self.to_opt_pattern(slice
),
300 suffix
: self.to_patterns(suffix
),
305 span_bug
!(span
, "unexpanded macro or bad constant etc");
310 fn variant_or_leaf(&mut self,
312 subpatterns
: Vec
<FieldPattern
<'tcx
>>)
313 -> PatternKind
<'tcx
> {
314 let def
= self.cx
.tcx
.def_map
.borrow().get(&pat
.id
).unwrap().full_def();
316 Def
::Variant(enum_id
, variant_id
) => {
317 let adt_def
= self.cx
.tcx
.lookup_adt_def(enum_id
);
318 if adt_def
.variants
.len() > 1 {
319 PatternKind
::Variant
{
321 variant_index
: adt_def
.variant_index_with_id(variant_id
),
322 subpatterns
: subpatterns
,
325 PatternKind
::Leaf { subpatterns: subpatterns }
329 Def
::Struct(..) | Def
::TyAlias(..) => {
330 PatternKind
::Leaf { subpatterns: subpatterns }
334 span_bug
!(pat
.span
, "inappropriate def for pattern: {:?}", def
);