1 // Copyright 2012-2014 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.
11 pub use self::Constructor
::*;
12 use self::Usefulness
::*;
13 use self::WitnessPreference
::*;
15 use dep_graph
::DepNode
;
16 use middle
::const_eval
::{compare_const_vals, ConstVal}
;
17 use middle
::const_eval
::{eval_const_expr, eval_const_expr_partial}
;
18 use middle
::const_eval
::{const_expr_to_pat, lookup_const_by_id}
;
19 use middle
::const_eval
::EvalHint
::ExprTypeChecked
;
21 use middle
::def_id
::{DefId}
;
22 use middle
::expr_use_visitor
::{ConsumeMode, Delegate, ExprUseVisitor}
;
23 use middle
::expr_use_visitor
::{LoanCause, MutateMode}
;
24 use middle
::expr_use_visitor
as euv
;
26 use middle
::mem_categorization
::{cmt}
;
27 use middle
::pat_util
::*;
30 use std
::cmp
::Ordering
;
32 use std
::iter
::{FromIterator, IntoIterator, repeat}
;
35 use rustc_front
::hir
::{Pat, PatKind}
;
36 use rustc_front
::intravisit
::{self, Visitor, FnKind}
;
37 use rustc_front
::util
as front_util
;
38 use rustc_back
::slice
;
40 use syntax
::ast
::{self, DUMMY_NODE_ID, NodeId}
;
42 use syntax
::codemap
::{Span, Spanned, DUMMY_SP}
;
43 use rustc_front
::fold
::{Folder, noop_fold_pat}
;
44 use rustc_front
::print
::pprust
::pat_to_string
;
46 use util
::nodemap
::FnvHashMap
;
48 pub const DUMMY_WILD_PAT
: &'
static Pat
= &Pat
{
54 struct Matrix
<'a
>(Vec
<Vec
<&'a Pat
>>);
56 /// Pretty-printer for matrices of patterns, example:
57 /// ++++++++++++++++++++++++++
59 /// ++++++++++++++++++++++++++
60 /// + true + [First] +
61 /// ++++++++++++++++++++++++++
62 /// + true + [Second(true)] +
63 /// ++++++++++++++++++++++++++
65 /// ++++++++++++++++++++++++++
66 /// + _ + [_, _, ..tail] +
67 /// ++++++++++++++++++++++++++
68 impl<'a
> fmt
::Debug
for Matrix
<'a
> {
69 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
70 try
!(write
!(f
, "\n"));
72 let &Matrix(ref m
) = self;
73 let pretty_printed_matrix
: Vec
<Vec
<String
>> = m
.iter().map(|row
| {
75 .map(|&pat
| pat_to_string(&pat
))
76 .collect
::<Vec
<String
>>()
79 let column_count
= m
.iter().map(|row
| row
.len()).max().unwrap_or(0);
80 assert
!(m
.iter().all(|row
| row
.len() == column_count
));
81 let column_widths
: Vec
<usize> = (0..column_count
).map(|col
| {
82 pretty_printed_matrix
.iter().map(|row
| row
[col
].len()).max().unwrap_or(0)
85 let total_width
= column_widths
.iter().cloned().sum
::<usize>() + column_count
* 3 + 1;
86 let br
= repeat('
+'
).take(total_width
).collect
::<String
>();
87 try
!(write
!(f
, "{}\n", br
));
88 for row
in pretty_printed_matrix
{
90 for (column
, pat_str
) in row
.into_iter().enumerate() {
92 try
!(write
!(f
, "{:1$}", pat_str
, column_widths
[column
]));
93 try
!(write
!(f
, " +"));
95 try
!(write
!(f
, "\n"));
96 try
!(write
!(f
, "{}\n", br
));
102 impl<'a
> FromIterator
<Vec
<&'a Pat
>> for Matrix
<'a
> {
103 fn from_iter
<T
: IntoIterator
<Item
=Vec
<&'a Pat
>>>(iter
: T
) -> Matrix
<'a
> {
104 Matrix(iter
.into_iter().collect())
108 //NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
109 pub struct MatchCheckCtxt
<'a
, 'tcx
: 'a
> {
110 pub tcx
: &'a ty
::ctxt
<'tcx
>,
111 pub param_env
: ParameterEnvironment
<'a
, 'tcx
>,
114 #[derive(Clone, PartialEq)]
115 pub enum Constructor
{
116 /// The constructor of all patterns that don't vary by constructor,
117 /// e.g. struct patterns and fixed-length arrays.
122 ConstantValue(ConstVal
),
123 /// Ranges of literal values (2..5).
124 ConstantRange(ConstVal
, ConstVal
),
125 /// Array patterns of length n.
127 /// Array patterns with a subslice.
128 SliceWithSubslice(usize, usize)
131 #[derive(Clone, PartialEq)]
134 UsefulWithWitness(Vec
<P
<Pat
>>),
138 #[derive(Copy, Clone)]
139 enum WitnessPreference
{
144 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for MatchCheckCtxt
<'a
, 'tcx
> {
145 fn visit_expr(&mut self, ex
: &hir
::Expr
) {
146 check_expr(self, ex
);
148 fn visit_local(&mut self, l
: &hir
::Local
) {
149 check_local(self, l
);
151 fn visit_fn(&mut self, fk
: FnKind
<'v
>, fd
: &'v hir
::FnDecl
,
152 b
: &'v hir
::Block
, s
: Span
, n
: NodeId
) {
153 check_fn(self, fk
, fd
, b
, s
, n
);
157 pub fn check_crate(tcx
: &ty
::ctxt
) {
158 tcx
.visit_all_items_in_krate(DepNode
::MatchCheck
, &mut MatchCheckCtxt
{
160 param_env
: tcx
.empty_parameter_environment(),
162 tcx
.sess
.abort_if_errors();
165 fn check_expr(cx
: &mut MatchCheckCtxt
, ex
: &hir
::Expr
) {
166 intravisit
::walk_expr(cx
, ex
);
168 hir
::ExprMatch(ref scrut
, ref arms
, source
) => {
170 // First, check legality of move bindings.
171 check_legality_of_move_bindings(cx
,
175 // Second, if there is a guard on each arm, make sure it isn't
176 // assigning or borrowing anything mutably.
178 Some(ref guard
) => check_for_mutation_in_guard(cx
, &guard
),
183 let mut static_inliner
= StaticInliner
::new(cx
.tcx
, None
);
184 let inlined_arms
= arms
.iter().map(|arm
| {
185 (arm
.pats
.iter().map(|pat
| {
186 static_inliner
.fold_pat((*pat
).clone())
187 }).collect(), arm
.guard
.as_ref().map(|e
| &**e
))
188 }).collect
::<Vec
<(Vec
<P
<Pat
>>, Option
<&hir
::Expr
>)>>();
190 // Bail out early if inlining failed.
191 if static_inliner
.failed
{
195 for pat
in inlined_arms
197 .flat_map(|&(ref pats
, _
)| pats
) {
198 // Third, check legality of move bindings.
199 check_legality_of_bindings_in_at_patterns(cx
, &pat
);
201 // Fourth, check if there are any references to NaN that we should warn about.
202 check_for_static_nan(cx
, &pat
);
204 // Fifth, check if for any of the patterns that match an enumerated type
205 // are bindings with the same name as one of the variants of said type.
206 check_for_bindings_named_the_same_as_variants(cx
, &pat
);
209 // Fourth, check for unreachable arms.
210 check_arms(cx
, &inlined_arms
[..], source
);
212 // Finally, check if the whole match expression is exhaustive.
213 // Check for empty enum, because is_useful only works on inhabited types.
214 let pat_ty
= cx
.tcx
.node_id_to_type(scrut
.id
);
215 if inlined_arms
.is_empty() {
216 if !pat_ty
.is_empty(cx
.tcx
) {
217 // We know the type is inhabited, so this must be wrong
218 let mut err
= struct_span_err
!(cx
.tcx
.sess
, ex
.span
, E0002
,
219 "non-exhaustive patterns: type {} is non-empty",
221 span_help
!(&mut err
, ex
.span
,
222 "Please ensure that all possible cases are being handled; \
223 possibly adding wildcards or more match arms.");
226 // If the type *is* empty, it's vacuously exhaustive
230 let matrix
: Matrix
= inlined_arms
232 .filter(|&&(_
, guard
)| guard
.is_none())
233 .flat_map(|arm
| &arm
.0)
234 .map(|pat
| vec
![&**pat
])
236 check_exhaustive(cx
, ex
.span
, &matrix
, source
);
242 fn check_for_bindings_named_the_same_as_variants(cx
: &MatchCheckCtxt
, pat
: &Pat
) {
243 front_util
::walk_pat(pat
, |p
| {
245 PatKind
::Ident(hir
::BindByValue(hir
::MutImmutable
), ident
, None
) => {
246 let pat_ty
= cx
.tcx
.pat_ty(p
);
247 if let ty
::TyEnum(edef
, _
) = pat_ty
.sty
{
248 let def
= cx
.tcx
.def_map
.borrow().get(&p
.id
).map(|d
| d
.full_def());
249 if let Some(Def
::Local(..)) = def
{
250 if edef
.variants
.iter().any(|variant
|
251 variant
.name
== ident
.node
.unhygienic_name
252 && variant
.kind() == VariantKind
::Unit
254 let ty_path
= cx
.tcx
.item_path_str(edef
.did
);
255 let mut err
= struct_span_warn
!(cx
.tcx
.sess
, p
.span
, E0170
,
256 "pattern binding `{}` is named the same as one \
257 of the variants of the type `{}`",
258 ident
.node
, ty_path
);
259 fileline_help
!(err
, p
.span
,
260 "if you meant to match on a variant, \
261 consider making the path in the pattern qualified: `{}::{}`",
262 ty_path
, ident
.node
);
274 // Check that we do not match against a static NaN (#6804)
275 fn check_for_static_nan(cx
: &MatchCheckCtxt
, pat
: &Pat
) {
276 front_util
::walk_pat(pat
, |p
| {
277 if let PatKind
::Lit(ref expr
) = p
.node
{
278 match eval_const_expr_partial(cx
.tcx
, &expr
, ExprTypeChecked
, None
) {
279 Ok(ConstVal
::Float(f
)) if f
.is_nan() => {
280 span_warn
!(cx
.tcx
.sess
, p
.span
, E0003
,
281 "unmatchable NaN in pattern, \
282 use the is_nan method in a guard instead");
287 let mut diag
= struct_span_err
!(cx
.tcx
.sess
, err
.span
, E0471
,
288 "constant evaluation error: {}",
290 if !p
.span
.contains(err
.span
) {
291 diag
.span_note(p
.span
, "in pattern here");
301 // Check for unreachable patterns
302 fn check_arms(cx
: &MatchCheckCtxt
,
303 arms
: &[(Vec
<P
<Pat
>>, Option
<&hir
::Expr
>)],
304 source
: hir
::MatchSource
) {
305 let mut seen
= Matrix(vec
![]);
306 let mut printed_if_let_err
= false;
307 for &(ref pats
, guard
) in arms
{
309 let v
= vec
![&**pat
];
311 match is_useful(cx
, &seen
, &v
[..], LeaveOutWitness
) {
314 hir
::MatchSource
::IfLetDesugar { .. }
=> {
315 if printed_if_let_err
{
316 // we already printed an irrefutable if-let pattern error.
317 // We don't want two, that's just confusing.
319 // find the first arm pattern so we can use its span
320 let &(ref first_arm_pats
, _
) = &arms
[0];
321 let first_pat
= &first_arm_pats
[0];
322 let span
= first_pat
.span
;
323 span_err
!(cx
.tcx
.sess
, span
, E0162
, "irrefutable if-let pattern");
324 printed_if_let_err
= true;
328 hir
::MatchSource
::WhileLetDesugar
=> {
329 // find the first arm pattern so we can use its span
330 let &(ref first_arm_pats
, _
) = &arms
[0];
331 let first_pat
= &first_arm_pats
[0];
332 let span
= first_pat
.span
;
333 span_err
!(cx
.tcx
.sess
, span
, E0165
, "irrefutable while-let pattern");
336 hir
::MatchSource
::ForLoopDesugar
=> {
337 // this is a bug, because on `match iter.next()` we cover
338 // `Some(<head>)` and `None`. It's impossible to have an unreachable
340 // (see libsyntax/ext/expand.rs for the full expansion of a for loop)
341 cx
.tcx
.sess
.span_bug(pat
.span
, "unreachable for-loop pattern")
344 hir
::MatchSource
::Normal
=> {
345 span_err
!(cx
.tcx
.sess
, pat
.span
, E0001
, "unreachable pattern")
350 UsefulWithWitness(_
) => unreachable
!()
353 let Matrix(mut rows
) = seen
;
361 fn raw_pat
<'a
>(p
: &'a Pat
) -> &'a Pat
{
363 PatKind
::Ident(_
, _
, Some(ref s
)) => raw_pat(&s
),
368 fn check_exhaustive(cx
: &MatchCheckCtxt
, sp
: Span
, matrix
: &Matrix
, source
: hir
::MatchSource
) {
369 match is_useful(cx
, matrix
, &[DUMMY_WILD_PAT
], ConstructWitness
) {
370 UsefulWithWitness(pats
) => {
371 let witnesses
= if pats
.is_empty() {
374 pats
.iter().map(|w
| &**w
).collect()
377 hir
::MatchSource
::ForLoopDesugar
=> {
378 // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
379 let witness
= match witnesses
[0].node
{
380 PatKind
::TupleStruct(_
, Some(ref pats
)) => match &pats
[..] {
386 span_err
!(cx
.tcx
.sess
, sp
, E0297
,
387 "refutable pattern in `for` loop binding: \
389 pat_to_string(witness
));
392 let pattern_strings
: Vec
<_
> = witnesses
.iter().map(|w
| {
395 const LIMIT
: usize = 3;
396 let joined_patterns
= match pattern_strings
.len() {
398 1 => format
!("`{}`", pattern_strings
[0]),
400 let (tail
, head
) = pattern_strings
.split_last().unwrap();
401 format
!("`{}`", head
.join("`, `") + "` and `" + tail
)
404 let (head
, tail
) = pattern_strings
.split_at(LIMIT
);
405 format
!("`{}` and {} more", head
.join("`, `"), tail
.len())
408 span_err
!(cx
.tcx
.sess
, sp
, E0004
,
409 "non-exhaustive patterns: {} not covered",
416 // This is good, wildcard pattern isn't reachable
422 fn const_val_to_expr(value
: &ConstVal
) -> P
<hir
::Expr
> {
423 let node
= match value
{
424 &ConstVal
::Bool(b
) => ast
::LitKind
::Bool(b
),
429 node
: hir
::ExprLit(P(Spanned { node: node, span: DUMMY_SP }
)),
435 pub struct StaticInliner
<'a
, 'tcx
: 'a
> {
436 pub tcx
: &'a ty
::ctxt
<'tcx
>,
438 pub renaming_map
: Option
<&'a
mut FnvHashMap
<(NodeId
, Span
), NodeId
>>,
441 impl<'a
, 'tcx
> StaticInliner
<'a
, 'tcx
> {
442 pub fn new
<'b
>(tcx
: &'b ty
::ctxt
<'tcx
>,
443 renaming_map
: Option
<&'b
mut FnvHashMap
<(NodeId
, Span
), NodeId
>>)
444 -> StaticInliner
<'b
, 'tcx
> {
448 renaming_map
: renaming_map
453 struct RenamingRecorder
<'map
> {
454 substituted_node_id
: NodeId
,
456 renaming_map
: &'map
mut FnvHashMap
<(NodeId
, Span
), NodeId
>
459 impl<'map
> ast_util
::IdVisitingOperation
for RenamingRecorder
<'map
> {
460 fn visit_id(&mut self, node_id
: NodeId
) {
461 let key
= (node_id
, self.origin_span
);
462 self.renaming_map
.insert(key
, self.substituted_node_id
);
466 impl<'a
, 'tcx
> Folder
for StaticInliner
<'a
, 'tcx
> {
467 fn fold_pat(&mut self, pat
: P
<Pat
>) -> P
<Pat
> {
468 return match pat
.node
{
469 PatKind
::Ident(..) | PatKind
::Path(..) | PatKind
::QPath(..) => {
470 let def
= self.tcx
.def_map
.borrow().get(&pat
.id
).map(|d
| d
.full_def());
472 Some(Def
::AssociatedConst(did
)) |
473 Some(Def
::Const(did
)) => match lookup_const_by_id(self.tcx
, did
,
474 Some(pat
.id
), None
) {
475 Some(const_expr
) => {
476 const_expr_to_pat(self.tcx
, const_expr
, pat
.span
).map(|new_pat
| {
478 if let Some(ref mut renaming_map
) = self.renaming_map
{
479 // Record any renamings we do here
480 record_renamings(const_expr
, &pat
, renaming_map
);
488 span_err
!(self.tcx
.sess
, pat
.span
, E0158
,
489 "statics cannot be referenced in patterns");
493 _
=> noop_fold_pat(pat
, self)
496 _
=> noop_fold_pat(pat
, self)
499 fn record_renamings(const_expr
: &hir
::Expr
,
500 substituted_pat
: &hir
::Pat
,
501 renaming_map
: &mut FnvHashMap
<(NodeId
, Span
), NodeId
>) {
502 let mut renaming_recorder
= RenamingRecorder
{
503 substituted_node_id
: substituted_pat
.id
,
504 origin_span
: substituted_pat
.span
,
505 renaming_map
: renaming_map
,
508 let mut id_visitor
= front_util
::IdVisitor
::new(&mut renaming_recorder
);
510 id_visitor
.visit_expr(const_expr
);
515 /// Constructs a partial witness for a pattern given a list of
516 /// patterns expanded by the specialization step.
518 /// When a pattern P is discovered to be useful, this function is used bottom-up
519 /// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
520 /// of values, V, where each value in that set is not covered by any previously
521 /// used patterns and is covered by the pattern P'. Examples:
523 /// left_ty: tuple of 3 elements
524 /// pats: [10, 20, _] => (10, 20, _)
526 /// left_ty: struct X { a: (bool, &'static str), b: usize}
527 /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
528 fn construct_witness
<'a
,'tcx
>(cx
: &MatchCheckCtxt
<'a
,'tcx
>, ctor
: &Constructor
,
529 pats
: Vec
<&Pat
>, left_ty
: Ty
<'tcx
>) -> P
<Pat
> {
530 let pats_len
= pats
.len();
531 let mut pats
= pats
.into_iter().map(|p
| P((*p
).clone()));
532 let pat
= match left_ty
.sty
{
533 ty
::TyTuple(_
) => PatKind
::Tup(pats
.collect()),
535 ty
::TyEnum(adt
, _
) | ty
::TyStruct(adt
, _
) => {
536 let v
= adt
.variant_of_ctor(ctor
);
538 VariantKind
::Struct
=> {
539 let field_pats
: hir
::HirVec
<_
> = v
.fields
.iter()
541 .filter(|&(_
, ref pat
)| pat
.node
!= PatKind
::Wild
)
542 .map(|(field
, pat
)| Spanned
{
544 node
: hir
::FieldPat
{
550 let has_more_fields
= field_pats
.len() < pats_len
;
551 PatKind
::Struct(def_to_path(cx
.tcx
, v
.did
), field_pats
, has_more_fields
)
553 VariantKind
::Tuple
=> {
554 PatKind
::TupleStruct(def_to_path(cx
.tcx
, v
.did
), Some(pats
.collect()))
556 VariantKind
::Unit
=> {
557 PatKind
::Path(def_to_path(cx
.tcx
, v
.did
))
562 ty
::TyRef(_
, ty
::TypeAndMut { ty, mutbl }
) => {
564 ty
::TyArray(_
, n
) => match ctor
{
566 assert_eq
!(pats_len
, n
);
567 PatKind
::Vec(pats
.collect(), None
, hir
::HirVec
::new())
571 ty
::TySlice(_
) => match ctor
{
573 assert_eq
!(pats_len
, n
);
574 PatKind
::Vec(pats
.collect(), None
, hir
::HirVec
::new())
578 ty
::TyStr
=> PatKind
::Wild
,
581 assert_eq
!(pats_len
, 1);
582 PatKind
::Ref(pats
.nth(0).unwrap(), mutbl
)
587 ty
::TyArray(_
, len
) => {
588 assert_eq
!(pats_len
, len
);
589 PatKind
::Vec(pats
.collect(), None
, hir
::HirVec
::new())
594 ConstantValue(ref v
) => PatKind
::Lit(const_val_to_expr(v
)),
607 impl<'tcx
, 'container
> ty
::AdtDefData
<'tcx
, 'container
> {
608 fn variant_of_ctor(&self,
610 -> &VariantDefData
<'tcx
, 'container
> {
612 &Variant(vid
) => self.variant_with_id(vid
),
613 _
=> self.struct_variant()
618 fn missing_constructors(cx
: &MatchCheckCtxt
, &Matrix(ref rows
): &Matrix
,
619 left_ty
: Ty
, max_slice_length
: usize) -> Vec
<Constructor
> {
620 let used_constructors
: Vec
<Constructor
> = rows
.iter()
621 .flat_map(|row
| pat_constructors(cx
, row
[0], left_ty
, max_slice_length
))
623 all_constructors(cx
, left_ty
, max_slice_length
)
625 .filter(|c
| !used_constructors
.contains(c
))
629 /// This determines the set of all possible constructors of a pattern matching
630 /// values of type `left_ty`. For vectors, this would normally be an infinite set
631 /// but is instead bounded by the maximum fixed length of slice patterns in
632 /// the column of patterns being analyzed.
633 fn all_constructors(_cx
: &MatchCheckCtxt
, left_ty
: Ty
,
634 max_slice_length
: usize) -> Vec
<Constructor
> {
637 [true, false].iter().map(|b
| ConstantValue(ConstVal
::Bool(*b
))).collect(),
639 ty
::TyRef(_
, ty
::TypeAndMut { ty, .. }
) => match ty
.sty
{
641 (0..max_slice_length
+1).map(|length
| Slice(length
)).collect(),
645 ty
::TyEnum(def
, _
) => def
.variants
.iter().map(|v
| Variant(v
.did
)).collect(),
650 // Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
652 // Whether a vector `v` of patterns is 'useful' in relation to a set of such
653 // vectors `m` is defined as there being a set of inputs that will match `v`
654 // but not any of the sets in `m`.
656 // This is used both for reachability checking (if a pattern isn't useful in
657 // relation to preceding patterns, it is not reachable) and exhaustiveness
658 // checking (if a wildcard pattern is useful in relation to a matrix, the
659 // matrix isn't exhaustive).
661 // Note: is_useful doesn't work on empty types, as the paper notes.
662 // So it assumes that v is non-empty.
663 fn is_useful(cx
: &MatchCheckCtxt
,
666 witness
: WitnessPreference
)
668 let &Matrix(ref rows
) = matrix
;
669 debug
!("{:?}", matrix
);
671 return match witness
{
672 ConstructWitness
=> UsefulWithWitness(vec
!()),
673 LeaveOutWitness
=> Useful
676 if rows
[0].is_empty() {
679 assert
!(rows
.iter().all(|r
| r
.len() == v
.len()));
680 let real_pat
= match rows
.iter().find(|r
| (*r
)[0].id
!= DUMMY_NODE_ID
) {
681 Some(r
) => raw_pat(r
[0]),
682 None
if v
.is_empty() => return NotUseful
,
685 let left_ty
= if real_pat
.id
== DUMMY_NODE_ID
{
688 let left_ty
= cx
.tcx
.pat_ty(&real_pat
);
690 match real_pat
.node
{
691 PatKind
::Ident(hir
::BindByRef(..), _
, _
) => {
692 left_ty
.builtin_deref(false, NoPreference
).unwrap().ty
698 let max_slice_length
= rows
.iter().filter_map(|row
| match row
[0].node
{
699 PatKind
::Vec(ref before
, _
, ref after
) => Some(before
.len() + after
.len()),
701 }).max().map_or(0, |v
| v
+ 1);
703 let constructors
= pat_constructors(cx
, v
[0], left_ty
, max_slice_length
);
704 if constructors
.is_empty() {
705 let constructors
= missing_constructors(cx
, matrix
, left_ty
, max_slice_length
);
706 if constructors
.is_empty() {
707 all_constructors(cx
, left_ty
, max_slice_length
).into_iter().map(|c
| {
708 match is_useful_specialized(cx
, matrix
, v
, c
.clone(), left_ty
, witness
) {
709 UsefulWithWitness(pats
) => UsefulWithWitness({
710 let arity
= constructor_arity(cx
, &c
, left_ty
);
712 let pat_slice
= &pats
[..];
713 let subpats
: Vec
<_
> = (0..arity
).map(|i
| {
714 pat_slice
.get(i
).map_or(DUMMY_WILD_PAT
, |p
| &**p
)
716 vec
![construct_witness(cx
, &c
, subpats
, left_ty
)]
718 result
.extend(pats
.into_iter().skip(arity
));
723 }).find(|result
| result
!= &NotUseful
).unwrap_or(NotUseful
)
725 let matrix
= rows
.iter().filter_map(|r
| {
726 if pat_is_binding_or_wild(&cx
.tcx
.def_map
.borrow(), raw_pat(r
[0])) {
727 Some(r
[1..].to_vec())
732 match is_useful(cx
, &matrix
, &v
[1..], witness
) {
733 UsefulWithWitness(pats
) => {
734 let mut new_pats
: Vec
<_
> = constructors
.into_iter().map(|constructor
| {
735 let arity
= constructor_arity(cx
, &constructor
, left_ty
);
736 let wild_pats
= vec
![DUMMY_WILD_PAT
; arity
];
737 construct_witness(cx
, &constructor
, wild_pats
, left_ty
)
739 new_pats
.extend(pats
);
740 UsefulWithWitness(new_pats
)
746 constructors
.into_iter().map(|c
|
747 is_useful_specialized(cx
, matrix
, v
, c
.clone(), left_ty
, witness
)
748 ).find(|result
| result
!= &NotUseful
).unwrap_or(NotUseful
)
752 fn is_useful_specialized(cx
: &MatchCheckCtxt
, &Matrix(ref m
): &Matrix
,
753 v
: &[&Pat
], ctor
: Constructor
, lty
: Ty
,
754 witness
: WitnessPreference
) -> Usefulness
{
755 let arity
= constructor_arity(cx
, &ctor
, lty
);
756 let matrix
= Matrix(m
.iter().filter_map(|r
| {
757 specialize(cx
, &r
[..], &ctor
, 0, arity
)
759 match specialize(cx
, v
, &ctor
, 0, arity
) {
760 Some(v
) => is_useful(cx
, &matrix
, &v
[..], witness
),
765 /// Determines the constructors that the given pattern can be specialized to.
767 /// In most cases, there's only one constructor that a specific pattern
768 /// represents, such as a specific enum variant or a specific literal value.
769 /// Slice patterns, however, can match slices of different lengths. For instance,
770 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
772 /// On the other hand, a wild pattern and an identifier pattern cannot be
773 /// specialized in any way.
774 fn pat_constructors(cx
: &MatchCheckCtxt
, p
: &Pat
,
775 left_ty
: Ty
, max_slice_length
: usize) -> Vec
<Constructor
> {
776 let pat
= raw_pat(p
);
778 PatKind
::Struct(..) | PatKind
::TupleStruct(..) | PatKind
::Path(..) | PatKind
::Ident(..) =>
779 match cx
.tcx
.def_map
.borrow().get(&pat
.id
).unwrap().full_def() {
780 Def
::Const(..) | Def
::AssociatedConst(..) =>
781 cx
.tcx
.sess
.span_bug(pat
.span
, "const pattern should've \
783 Def
::Struct(..) | Def
::TyAlias(..) => vec
![Single
],
784 Def
::Variant(_
, id
) => vec
![Variant(id
)],
785 Def
::Local(..) => vec
![],
786 def
=> cx
.tcx
.sess
.span_bug(pat
.span
, &format
!("pat_constructors: unexpected \
787 definition {:?}", def
)),
789 PatKind
::QPath(..) =>
790 cx
.tcx
.sess
.span_bug(pat
.span
, "const pattern should've \
792 PatKind
::Lit(ref expr
) =>
793 vec
!(ConstantValue(eval_const_expr(cx
.tcx
, &expr
))),
794 PatKind
::Range(ref lo
, ref hi
) =>
795 vec
!(ConstantRange(eval_const_expr(cx
.tcx
, &lo
), eval_const_expr(cx
.tcx
, &hi
))),
796 PatKind
::Vec(ref before
, ref slice
, ref after
) =>
798 ty
::TyArray(_
, _
) => vec
!(Single
),
799 _
=> if slice
.is_some() {
800 (before
.len() + after
.len()..max_slice_length
+1)
801 .map(|length
| Slice(length
))
804 vec
!(Slice(before
.len() + after
.len()))
807 PatKind
::Box(_
) | PatKind
::Tup(_
) | PatKind
::Ref(..) =>
814 /// This computes the arity of a constructor. The arity of a constructor
815 /// is how many subpattern patterns of that constructor should be expanded to.
817 /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
818 /// A struct pattern's arity is the number of fields it contains, etc.
819 pub fn constructor_arity(_cx
: &MatchCheckCtxt
, ctor
: &Constructor
, ty
: Ty
) -> usize {
821 ty
::TyTuple(ref fs
) => fs
.len(),
823 ty
::TyRef(_
, ty
::TypeAndMut { ty, .. }
) => match ty
.sty
{
824 ty
::TySlice(_
) => match *ctor
{
825 Slice(length
) => length
,
826 ConstantValue(_
) => 0,
832 ty
::TyEnum(adt
, _
) | ty
::TyStruct(adt
, _
) => {
833 adt
.variant_of_ctor(ctor
).fields
.len()
835 ty
::TyArray(_
, n
) => n
,
840 fn range_covered_by_constructor(ctor
: &Constructor
,
841 from
: &ConstVal
, to
: &ConstVal
) -> Option
<bool
> {
842 let (c_from
, c_to
) = match *ctor
{
843 ConstantValue(ref value
) => (value
, value
),
844 ConstantRange(ref from
, ref to
) => (from
, to
),
845 Single
=> return Some(true),
848 let cmp_from
= compare_const_vals(c_from
, from
);
849 let cmp_to
= compare_const_vals(c_to
, to
);
850 match (cmp_from
, cmp_to
) {
851 (Some(cmp_from
), Some(cmp_to
)) => {
852 Some(cmp_from
!= Ordering
::Less
&& cmp_to
!= Ordering
::Greater
)
858 /// This is the main specialization step. It expands the first pattern in the given row
859 /// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
860 /// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
862 /// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple
863 /// different patterns.
864 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
865 /// fields filled with wild patterns.
866 pub fn specialize
<'a
>(cx
: &MatchCheckCtxt
, r
: &[&'a Pat
],
867 constructor
: &Constructor
, col
: usize, arity
: usize) -> Option
<Vec
<&'a Pat
>> {
869 id
: pat_id
, ref node
, span
: pat_span
871 let head
: Option
<Vec
<&Pat
>> = match *node
{
873 Some(vec
![DUMMY_WILD_PAT
; arity
]),
875 PatKind
::Path(..) | PatKind
::Ident(..) => {
876 let def
= cx
.tcx
.def_map
.borrow().get(&pat_id
).unwrap().full_def();
878 Def
::Const(..) | Def
::AssociatedConst(..) =>
879 cx
.tcx
.sess
.span_bug(pat_span
, "const pattern should've \
881 Def
::Variant(_
, id
) if *constructor
!= Variant(id
) => None
,
882 Def
::Variant(..) | Def
::Struct(..) => Some(Vec
::new()),
883 Def
::Local(..) => Some(vec
![DUMMY_WILD_PAT
; arity
]),
884 _
=> cx
.tcx
.sess
.span_bug(pat_span
, &format
!("specialize: unexpected \
885 definition {:?}", def
)),
889 PatKind
::TupleStruct(_
, ref args
) => {
890 let def
= cx
.tcx
.def_map
.borrow().get(&pat_id
).unwrap().full_def();
892 Def
::Const(..) | Def
::AssociatedConst(..) =>
893 cx
.tcx
.sess
.span_bug(pat_span
, "const pattern should've \
895 Def
::Variant(_
, id
) if *constructor
!= Variant(id
) => None
,
896 Def
::Variant(..) | Def
::Struct(..) => {
898 &Some(ref args
) => args
.iter().map(|p
| &**p
).collect(),
899 &None
=> vec
![DUMMY_WILD_PAT
; arity
],
906 PatKind
::QPath(_
, _
) => {
907 cx
.tcx
.sess
.span_bug(pat_span
, "const pattern should've \
911 PatKind
::Struct(_
, ref pattern_fields
, _
) => {
912 let def
= cx
.tcx
.def_map
.borrow().get(&pat_id
).unwrap().full_def();
913 let adt
= cx
.tcx
.node_id_to_type(pat_id
).ty_adt_def().unwrap();
914 let variant
= adt
.variant_of_ctor(constructor
);
915 let def_variant
= adt
.variant_of_def(def
);
916 if variant
.did
== def_variant
.did
{
917 Some(variant
.fields
.iter().map(|sf
| {
918 match pattern_fields
.iter().find(|f
| f
.node
.name
== sf
.name
) {
919 Some(ref f
) => &*f
.node
.pat
,
928 PatKind
::Tup(ref args
) =>
929 Some(args
.iter().map(|p
| &**p
).collect()),
931 PatKind
::Box(ref inner
) | PatKind
::Ref(ref inner
, _
) =>
932 Some(vec
![&**inner
]),
934 PatKind
::Lit(ref expr
) => {
935 let expr_value
= eval_const_expr(cx
.tcx
, &expr
);
936 match range_covered_by_constructor(constructor
, &expr_value
, &expr_value
) {
937 Some(true) => Some(vec
![]),
940 span_err
!(cx
.tcx
.sess
, pat_span
, E0298
, "mismatched types between arms");
946 PatKind
::Range(ref from
, ref to
) => {
947 let from_value
= eval_const_expr(cx
.tcx
, &from
);
948 let to_value
= eval_const_expr(cx
.tcx
, &to
);
949 match range_covered_by_constructor(constructor
, &from_value
, &to_value
) {
950 Some(true) => Some(vec
![]),
953 span_err
!(cx
.tcx
.sess
, pat_span
, E0299
, "mismatched types between arms");
959 PatKind
::Vec(ref before
, ref slice
, ref after
) => {
961 // Fixed-length vectors.
963 let mut pats
: Vec
<&Pat
> = before
.iter().map(|p
| &**p
).collect();
964 pats
.extend(repeat(DUMMY_WILD_PAT
).take(arity
- before
.len() - after
.len()));
965 pats
.extend(after
.iter().map(|p
| &**p
));
968 Slice(length
) if before
.len() + after
.len() <= length
&& slice
.is_some() => {
969 let mut pats
: Vec
<&Pat
> = before
.iter().map(|p
| &**p
).collect();
970 pats
.extend(repeat(DUMMY_WILD_PAT
).take(arity
- before
.len() - after
.len()));
971 pats
.extend(after
.iter().map(|p
| &**p
));
974 Slice(length
) if before
.len() + after
.len() == length
=> {
975 let mut pats
: Vec
<&Pat
> = before
.iter().map(|p
| &**p
).collect();
976 pats
.extend(after
.iter().map(|p
| &**p
));
979 SliceWithSubslice(prefix
, suffix
)
980 if before
.len() == prefix
981 && after
.len() == suffix
982 && slice
.is_some() => {
983 let mut pats
: Vec
<&Pat
> = before
.iter().map(|p
| &**p
).collect();
984 pats
.extend(after
.iter().map(|p
| &**p
));
991 head
.map(|mut head
| {
992 head
.extend_from_slice(&r
[..col
]);
993 head
.extend_from_slice(&r
[col
+ 1..]);
998 fn check_local(cx
: &mut MatchCheckCtxt
, loc
: &hir
::Local
) {
999 intravisit
::walk_local(cx
, loc
);
1001 let pat
= StaticInliner
::new(cx
.tcx
, None
).fold_pat(loc
.pat
.clone());
1002 check_irrefutable(cx
, &pat
, false);
1004 // Check legality of move bindings and `@` patterns.
1005 check_legality_of_move_bindings(cx
, false, slice
::ref_slice(&loc
.pat
));
1006 check_legality_of_bindings_in_at_patterns(cx
, &loc
.pat
);
1009 fn check_fn(cx
: &mut MatchCheckCtxt
,
1016 FnKind
::Closure
=> {}
1017 _
=> cx
.param_env
= ParameterEnvironment
::for_item(cx
.tcx
, fn_id
),
1020 intravisit
::walk_fn(cx
, kind
, decl
, body
, sp
);
1022 for input
in &decl
.inputs
{
1023 check_irrefutable(cx
, &input
.pat
, true);
1024 check_legality_of_move_bindings(cx
, false, slice
::ref_slice(&input
.pat
));
1025 check_legality_of_bindings_in_at_patterns(cx
, &input
.pat
);
1029 fn check_irrefutable(cx
: &MatchCheckCtxt
, pat
: &Pat
, is_fn_arg
: bool
) {
1030 let origin
= if is_fn_arg
{
1036 is_refutable(cx
, pat
, |uncovered_pat
| {
1037 span_err
!(cx
.tcx
.sess
, pat
.span
, E0005
,
1038 "refutable pattern in {}: `{}` not covered",
1040 pat_to_string(uncovered_pat
),
1045 fn is_refutable
<A
, F
>(cx
: &MatchCheckCtxt
, pat
: &Pat
, refutable
: F
) -> Option
<A
> where
1046 F
: FnOnce(&Pat
) -> A
,
1048 let pats
= Matrix(vec
!(vec
!(pat
)));
1049 match is_useful(cx
, &pats
, &[DUMMY_WILD_PAT
], ConstructWitness
) {
1050 UsefulWithWitness(pats
) => Some(refutable(&pats
[0])),
1052 Useful
=> unreachable
!()
1056 // Legality of move bindings checking
1057 fn check_legality_of_move_bindings(cx
: &MatchCheckCtxt
,
1061 let def_map
= &tcx
.def_map
;
1062 let mut by_ref_span
= None
;
1064 pat_bindings(def_map
, &pat
, |bm
, _
, span
, _path
| {
1066 hir
::BindByRef(_
) => {
1067 by_ref_span
= Some(span
);
1069 hir
::BindByValue(_
) => {
1075 let check_move
= |p
: &Pat
, sub
: Option
<&Pat
>| {
1076 // check legality of moving out of the enum
1078 // x @ Foo(..) is legal, but x @ Foo(y) isn't.
1079 if sub
.map_or(false, |p
| pat_contains_bindings(&def_map
.borrow(), &p
)) {
1080 span_err
!(cx
.tcx
.sess
, p
.span
, E0007
, "cannot bind by-move with sub-bindings");
1081 } else if has_guard
{
1082 span_err
!(cx
.tcx
.sess
, p
.span
, E0008
, "cannot bind by-move into a pattern guard");
1083 } else if by_ref_span
.is_some() {
1084 let mut err
= struct_span_err
!(cx
.tcx
.sess
, p
.span
, E0009
,
1085 "cannot bind by-move and by-ref in the same pattern");
1086 span_note
!(&mut err
, by_ref_span
.unwrap(), "by-ref binding occurs here");
1092 front_util
::walk_pat(&pat
, |p
| {
1093 if pat_is_binding(&def_map
.borrow(), &p
) {
1095 PatKind
::Ident(hir
::BindByValue(_
), _
, ref sub
) => {
1096 let pat_ty
= tcx
.node_id_to_type(p
.id
);
1097 //FIXME: (@jroesch) this code should be floated up as well
1098 let infcx
= infer
::new_infer_ctxt(cx
.tcx
,
1100 Some(cx
.param_env
.clone()));
1101 if infcx
.type_moves_by_default(pat_ty
, pat
.span
) {
1102 check_move(p
, sub
.as_ref().map(|p
| &**p
));
1105 PatKind
::Ident(hir
::BindByRef(_
), _
, _
) => {
1108 cx
.tcx
.sess
.span_bug(
1110 &format
!("binding pattern {} is not an \
1122 /// Ensures that a pattern guard doesn't borrow by mutable reference or
1124 fn check_for_mutation_in_guard
<'a
, 'tcx
>(cx
: &'a MatchCheckCtxt
<'a
, 'tcx
>,
1125 guard
: &hir
::Expr
) {
1126 let mut checker
= MutationChecker
{
1130 let infcx
= infer
::new_infer_ctxt(cx
.tcx
,
1132 Some(checker
.cx
.param_env
.clone()));
1134 let mut visitor
= ExprUseVisitor
::new(&mut checker
, &infcx
);
1135 visitor
.walk_expr(guard
);
1138 struct MutationChecker
<'a
, 'tcx
: 'a
> {
1139 cx
: &'a MatchCheckCtxt
<'a
, 'tcx
>,
1142 impl<'a
, 'tcx
> Delegate
<'tcx
> for MutationChecker
<'a
, 'tcx
> {
1143 fn matched_pat(&mut self, _
: &Pat
, _
: cmt
, _
: euv
::MatchMode
) {}
1144 fn consume(&mut self, _
: NodeId
, _
: Span
, _
: cmt
, _
: ConsumeMode
) {}
1145 fn consume_pat(&mut self, _
: &Pat
, _
: cmt
, _
: ConsumeMode
) {}
1146 fn borrow(&mut self,
1155 span_err
!(self.cx
.tcx
.sess
, span
, E0301
,
1156 "cannot mutably borrow in a pattern guard")
1158 ImmBorrow
| UniqueImmBorrow
=> {}
1161 fn decl_without_init(&mut self, _
: NodeId
, _
: Span
) {}
1162 fn mutate(&mut self, _
: NodeId
, span
: Span
, _
: cmt
, mode
: MutateMode
) {
1164 MutateMode
::JustWrite
| MutateMode
::WriteAndRead
=> {
1165 span_err
!(self.cx
.tcx
.sess
, span
, E0302
, "cannot assign in a pattern guard")
1167 MutateMode
::Init
=> {}
1172 /// Forbids bindings in `@` patterns. This is necessary for memory safety,
1173 /// because of the way rvalues are handled in the borrow check. (See issue
1175 fn check_legality_of_bindings_in_at_patterns(cx
: &MatchCheckCtxt
, pat
: &Pat
) {
1176 AtBindingPatternVisitor { cx: cx, bindings_allowed: true }
.visit_pat(pat
);
1179 struct AtBindingPatternVisitor
<'a
, 'b
:'a
, 'tcx
:'b
> {
1180 cx
: &'a MatchCheckCtxt
<'b
, 'tcx
>,
1181 bindings_allowed
: bool
1184 impl<'a
, 'b
, 'tcx
, 'v
> Visitor
<'v
> for AtBindingPatternVisitor
<'a
, 'b
, 'tcx
> {
1185 fn visit_pat(&mut self, pat
: &Pat
) {
1186 if !self.bindings_allowed
&& pat_is_binding(&self.cx
.tcx
.def_map
.borrow(), pat
) {
1187 span_err
!(self.cx
.tcx
.sess
, pat
.span
, E0303
,
1188 "pattern bindings are not allowed \
1193 PatKind
::Ident(_
, _
, Some(_
)) => {
1194 let bindings_were_allowed
= self.bindings_allowed
;
1195 self.bindings_allowed
= false;
1196 intravisit
::walk_pat(self, pat
);
1197 self.bindings_allowed
= bindings_were_allowed
;
1199 _
=> intravisit
::walk_pat(self, pat
),