1 // Copyright 2012 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.
12 use middle
::def_id
::DefId
;
14 use util
::nodemap
::FnvHashMap
;
17 use rustc_front
::hir
::{self, PatKind}
;
18 use rustc_front
::util
::walk_pat
;
19 use syntax
::codemap
::{respan, Span, Spanned, DUMMY_SP}
;
21 use std
::cell
::RefCell
;
23 pub type PatIdMap
= FnvHashMap
<ast
::Name
, ast
::NodeId
>;
25 // This is used because same-named variables in alternative patterns need to
26 // use the NodeId of their namesake in the first pattern.
27 pub fn pat_id_map(dm
: &RefCell
<DefMap
>, pat
: &hir
::Pat
) -> PatIdMap
{
28 let mut map
= FnvHashMap();
29 pat_bindings(dm
, pat
, |_bm
, p_id
, _s
, path1
| {
30 map
.insert(path1
.node
, p_id
);
35 pub fn pat_is_refutable(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
37 PatKind
::Lit(_
) | PatKind
::Range(_
, _
) | PatKind
::QPath(..) => true,
38 PatKind
::TupleStruct(..) |
40 PatKind
::Ident(_
, _
, None
) |
41 PatKind
::Struct(..) => {
42 match dm
.get(&pat
.id
).map(|d
| d
.full_def()) {
43 Some(Def
::Variant(..)) => true,
47 PatKind
::Vec(_
, _
, _
) => true,
52 pub fn pat_is_variant_or_struct(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
54 PatKind
::TupleStruct(..) |
56 PatKind
::Ident(_
, _
, None
) |
57 PatKind
::Struct(..) => {
58 match dm
.get(&pat
.id
).map(|d
| d
.full_def()) {
59 Some(Def
::Variant(..)) | Some(Def
::Struct(..)) | Some(Def
::TyAlias(..)) => true,
67 pub fn pat_is_const(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
69 PatKind
::Ident(_
, _
, None
) | PatKind
::Path(..) | PatKind
::QPath(..) => {
70 match dm
.get(&pat
.id
).map(|d
| d
.full_def()) {
71 Some(Def
::Const(..)) | Some(Def
::AssociatedConst(..)) => true,
79 // Same as above, except that partially-resolved defs cause `false` to be
80 // returned instead of a panic.
81 pub fn pat_is_resolved_const(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
83 PatKind
::Ident(_
, _
, None
) | PatKind
::Path(..) | PatKind
::QPath(..) => {
85 .and_then(|d
| if d
.depth
== 0 { Some(d.base_def) }
87 Some(Def
::Const(..)) | Some(Def
::AssociatedConst(..)) => true,
95 pub fn pat_is_binding(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
97 PatKind
::Ident(..) => {
98 !pat_is_variant_or_struct(dm
, pat
) &&
99 !pat_is_const(dm
, pat
)
105 pub fn pat_is_binding_or_wild(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
107 PatKind
::Ident(..) => pat_is_binding(dm
, pat
),
108 PatKind
::Wild
=> true,
113 /// Call `it` on every "binding" in a pattern, e.g., on `a` in
114 /// `match foo() { Some(a) => (), None => () }`
115 pub fn pat_bindings
<I
>(dm
: &RefCell
<DefMap
>, pat
: &hir
::Pat
, mut it
: I
) where
116 I
: FnMut(hir
::BindingMode
, ast
::NodeId
, Span
, &Spanned
<ast
::Name
>),
120 PatKind
::Ident(binding_mode
, ref pth
, _
) if pat_is_binding(&dm
.borrow(), p
) => {
121 it(binding_mode
, p
.id
, p
.span
, &respan(pth
.span
, pth
.node
.name
));
128 pub fn pat_bindings_ident
<I
>(dm
: &RefCell
<DefMap
>, pat
: &hir
::Pat
, mut it
: I
) where
129 I
: FnMut(hir
::BindingMode
, ast
::NodeId
, Span
, &Spanned
<hir
::Ident
>),
133 PatKind
::Ident(binding_mode
, ref pth
, _
) if pat_is_binding(&dm
.borrow(), p
) => {
134 it(binding_mode
, p
.id
, p
.span
, &respan(pth
.span
, pth
.node
));
142 /// Checks if the pattern contains any patterns that bind something to
143 /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
144 pub fn pat_contains_bindings(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
145 let mut contains_bindings
= false;
147 if pat_is_binding(dm
, p
) {
148 contains_bindings
= true;
149 false // there's at least one binding, can short circuit now.
157 /// Checks if the pattern contains any `ref` or `ref mut` bindings,
158 /// and if yes whether its containing mutable ones or just immutables ones.
159 pub fn pat_contains_ref_binding(dm
: &RefCell
<DefMap
>, pat
: &hir
::Pat
) -> Option
<hir
::Mutability
> {
160 let mut result
= None
;
161 pat_bindings(dm
, pat
, |mode
, _
, _
, _
| {
163 hir
::BindingMode
::BindByRef(m
) => {
164 // Pick Mutable as maximum
166 None
| Some(hir
::MutImmutable
) => result
= Some(m
),
170 hir
::BindingMode
::BindByValue(_
) => { }
176 /// Checks if the patterns for this arm contain any `ref` or `ref mut`
177 /// bindings, and if yes whether its containing mutable ones or just immutables ones.
178 pub fn arm_contains_ref_binding(dm
: &RefCell
<DefMap
>, arm
: &hir
::Arm
) -> Option
<hir
::Mutability
> {
180 .filter_map(|pat
| pat_contains_ref_binding(dm
, pat
))
181 .max_by_key(|m
| match *m
{
182 hir
::MutMutable
=> 1,
183 hir
::MutImmutable
=> 0,
187 /// Checks if the pattern contains any patterns that bind something to
188 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
189 pub fn pat_contains_bindings_or_wild(dm
: &DefMap
, pat
: &hir
::Pat
) -> bool
{
190 let mut contains_bindings
= false;
192 if pat_is_binding_or_wild(dm
, p
) {
193 contains_bindings
= true;
194 false // there's at least one binding/wildcard, can short circuit now.
202 pub fn simple_name
<'a
>(pat
: &'a hir
::Pat
) -> Option
<ast
::Name
> {
204 PatKind
::Ident(hir
::BindByValue(_
), ref path1
, None
) => {
205 Some(path1
.node
.name
)
213 pub fn def_to_path(tcx
: &ty
::ctxt
, id
: DefId
) -> hir
::Path
{
214 tcx
.with_path(id
, |path
| hir
::Path
{
216 segments
: path
.last().map(|elem
| hir
::PathSegment
{
217 identifier
: hir
::Ident
::from_name(elem
.name()),
218 parameters
: hir
::PathParameters
::none(),
219 }).into_iter().collect(),
224 /// Return variants that are necessary to exist for the pattern to match.
225 pub fn necessary_variants(dm
: &DefMap
, pat
: &hir
::Pat
) -> Vec
<DefId
> {
226 let mut variants
= vec
![];
229 PatKind
::TupleStruct(..) |
231 PatKind
::Ident(_
, _
, None
) |
232 PatKind
::Struct(..) => {
233 match dm
.get(&p
.id
) {
234 Some(&PathResolution { base_def: Def::Variant(_, id), .. }
) => {