]> git.proxmox.com Git - rustc.git/blame - src/librustc_const_eval/check_match.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / librustc_const_eval / check_match.rs
CommitLineData
54a0048b 1// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
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
c30ab7b3 11use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
c30ab7b3
SL
12use _match::Usefulness::*;
13use _match::WitnessPreference::*;
14
32a655c1 15use pattern::{Pattern, PatternContext, PatternError, PatternKind};
223e47cc 16
54a0048b
SL
17use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
18use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
19use rustc::middle::expr_use_visitor as euv;
54a0048b 20use rustc::middle::mem_categorization::{cmt};
7cac9316 21use rustc::middle::region::RegionMaps;
c30ab7b3 22use rustc::session::Session;
32a655c1
SL
23use rustc::ty::{self, Ty, TyCtxt};
24use rustc::lint;
25use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
e9174d1e 26
c30ab7b3 27use rustc::hir::def::*;
476ff2be 28use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
c30ab7b3 29use rustc::hir::{self, Pat, PatKind};
1a4d82fc 30
c30ab7b3 31use rustc_back::slice;
1a4d82fc 32
c30ab7b3
SL
33use syntax::ast;
34use syntax::ptr::P;
32a655c1 35use syntax_pos::{Span, DUMMY_SP};
1a4d82fc 36
c30ab7b3 37struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
1a4d82fc 38
476ff2be
SL
39impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
40 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
32a655c1 41 NestedVisitorMap::OnlyBodies(&self.tcx.hir)
223e47cc 42 }
1a4d82fc 43
476ff2be 44 fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
32a655c1
SL
45 b: hir::BodyId, s: Span, id: ast::NodeId) {
46 intravisit::walk_fn(self, fk, fd, b, s, id);
c30ab7b3 47
7cac9316
XL
48 let def_id = self.tcx.hir.local_def_id(id);
49
c30ab7b3
SL
50 MatchVisitor {
51 tcx: self.tcx,
32a655c1 52 tables: self.tcx.body_tables(b),
7cac9316
XL
53 region_maps: &self.tcx.region_maps(def_id),
54 param_env: self.tcx.param_env(def_id)
32a655c1 55 }.visit_body(self.tcx.hir.body(b));
c30ab7b3 56 }
1a4d82fc
JJ
57}
58
c30ab7b3 59pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
cc61c64b 60 tcx.hir.krate().visit_all_item_likes(&mut OuterVisitor { tcx: tcx }.as_deep_visitor());
c30ab7b3 61 tcx.sess.abort_if_errors();
1a4d82fc 62}
223e47cc 63
c30ab7b3
SL
64fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> {
65 struct_span_err!(sess, sp, E0004, "{}", &error_message)
223e47cc
LB
66}
67
c30ab7b3
SL
68struct MatchVisitor<'a, 'tcx: 'a> {
69 tcx: TyCtxt<'a, 'tcx, 'tcx>,
32a655c1 70 tables: &'a ty::TypeckTables<'tcx>,
7cac9316
XL
71 param_env: ty::ParamEnv<'tcx>,
72 region_maps: &'a RegionMaps,
1a4d82fc
JJ
73}
74
476ff2be
SL
75impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
76 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
32a655c1 77 NestedVisitorMap::None
476ff2be
SL
78 }
79
80 fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
c30ab7b3
SL
81 intravisit::walk_expr(self, ex);
82
83 match ex.node {
84 hir::ExprMatch(ref scrut, ref arms, source) => {
32a655c1 85 self.check_match(scrut, arms, source);
c30ab7b3
SL
86 }
87 _ => {}
88 }
1a4d82fc 89 }
c30ab7b3 90
476ff2be 91 fn visit_local(&mut self, loc: &'tcx hir::Local) {
c30ab7b3
SL
92 intravisit::walk_local(self, loc);
93
7cac9316
XL
94 self.check_irrefutable(&loc.pat, match loc.source {
95 hir::LocalSource::Normal => "local binding",
96 hir::LocalSource::ForLoopDesugar => "`for` loop binding",
97 });
c30ab7b3
SL
98
99 // Check legality of move bindings and `@` patterns.
100 self.check_patterns(false, slice::ref_slice(&loc.pat));
1a4d82fc 101 }
c30ab7b3 102
32a655c1
SL
103 fn visit_body(&mut self, body: &'tcx hir::Body) {
104 intravisit::walk_body(self, body);
1a4d82fc 105
32a655c1 106 for arg in &body.arguments {
7cac9316 107 self.check_irrefutable(&arg.pat, "function argument");
32a655c1 108 self.check_patterns(false, slice::ref_slice(&arg.pat));
c30ab7b3
SL
109 }
110 }
1a4d82fc
JJ
111}
112
cc61c64b
XL
113impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
114 fn report_inlining_errors(&self, pat_span: Span) {
115 for error in &self.errors {
116 match *error {
c30ab7b3
SL
117 PatternError::StaticInPattern(span) => {
118 span_err!(self.tcx.sess, span, E0158,
119 "statics cannot be referenced in patterns");
120 }
cc61c64b
XL
121 PatternError::ConstEval(ref err) => {
122 err.report(self.tcx, pat_span, "pattern");
1a4d82fc
JJ
123 }
124 }
c30ab7b3
SL
125 }
126 }
cc61c64b
XL
127}
128
129impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
130 fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
131 check_legality_of_move_bindings(self, has_guard, pats);
132 for pat in pats {
133 check_legality_of_bindings_in_at_patterns(self, pat);
134 }
135 }
1a4d82fc 136
c30ab7b3
SL
137 fn check_match(
138 &self,
139 scrut: &hir::Expr,
140 arms: &[hir::Arm],
32a655c1 141 source: hir::MatchSource)
c30ab7b3
SL
142 {
143 for arm in arms {
144 // First, check legality of move bindings.
145 self.check_patterns(arm.guard.is_some(), &arm.pats);
146
147 // Second, if there is a guard on each arm, make sure it isn't
148 // assigning or borrowing anything mutably.
149 if let Some(ref guard) = arm.guard {
150 check_for_mutation_in_guard(self, &guard);
151 }
1a4d82fc 152
c30ab7b3
SL
153 // Third, perform some lints.
154 for pat in &arm.pats {
155 check_for_bindings_named_the_same_as_variants(self, pat);
1a4d82fc 156 }
c30ab7b3 157 }
1a4d82fc 158
7cac9316 159 let module = self.tcx.hir.get_module_parent(scrut.id);
32a655c1 160 MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
c30ab7b3 161 let mut have_errors = false;
1a4d82fc 162
c30ab7b3
SL
163 let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
164 arm.pats.iter().map(|pat| {
32a655c1 165 let mut patcx = PatternContext::new(self.tcx, self.tables);
c30ab7b3
SL
166 let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
167 if !patcx.errors.is_empty() {
cc61c64b 168 patcx.report_inlining_errors(pat.span);
c30ab7b3
SL
169 have_errors = true;
170 }
171 (pattern, &**pat)
172 }).collect(),
173 arm.guard.as_ref().map(|e| &**e)
174 )).collect();
1a4d82fc 175
c30ab7b3
SL
176 // Bail out early if inlining failed.
177 if have_errors {
178 return;
1a4d82fc
JJ
179 }
180
181 // Fourth, check for unreachable arms.
c30ab7b3 182 check_arms(cx, &inlined_arms, source);
223e47cc 183
32a655c1
SL
184 // Then, if the match has no arms, check whether the scrutinee
185 // is uninhabited.
186 let pat_ty = self.tables.node_id_to_type(scrut.id);
7cac9316 187 let module = self.tcx.hir.get_module_parent(scrut.id);
1a4d82fc 188 if inlined_arms.is_empty() {
32a655c1
SL
189 let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
190 pat_ty.is_uninhabited_from(module, self.tcx)
191 } else {
192 self.conservative_is_uninhabited(pat_ty)
193 };
194 if !scrutinee_is_uninhabited {
1a4d82fc 195 // We know the type is inhabited, so this must be wrong
32a655c1 196 let mut err = create_e0004(self.tcx.sess, scrut.span,
c30ab7b3
SL
197 format!("non-exhaustive patterns: type {} \
198 is non-empty",
199 pat_ty));
32a655c1 200 span_help!(&mut err, scrut.span,
c30ab7b3
SL
201 "Please ensure that all possible cases are being handled; \
202 possibly adding wildcards or more match arms.");
9cc50fc6 203 err.emit();
1a4d82fc 204 }
5bcae85e 205 // If the type *is* uninhabited, it's vacuously exhaustive
1a4d82fc 206 return;
223e47cc 207 }
1a4d82fc
JJ
208
209 let matrix: Matrix = inlined_arms
210 .iter()
211 .filter(|&&(_, guard)| guard.is_none())
62682a34 212 .flat_map(|arm| &arm.0)
c30ab7b3 213 .map(|pat| vec![pat.0])
1a4d82fc 214 .collect();
32a655c1 215 let scrut_ty = self.tables.node_id_to_type(scrut.id);
7cac9316 216 check_exhaustive(cx, scrut_ty, scrut.span, &matrix);
c30ab7b3
SL
217 })
218 }
219
32a655c1
SL
220 fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
221 // "rustc-1.0-style" uncontentious uninhabitableness check
222 match scrutinee_ty.sty {
223 ty::TyNever => true,
224 ty::TyAdt(def, _) => def.variants.is_empty(),
225 _ => false
226 }
227 }
228
7cac9316
XL
229 fn check_irrefutable(&self, pat: &Pat, origin: &str) {
230 let module = self.tcx.hir.get_module_parent(pat.id);
32a655c1
SL
231 MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
232 let mut patcx = PatternContext::new(self.tcx, self.tables);
233 let pattern = patcx.lower_pattern(pat);
234 let pattern_ty = pattern.ty;
c30ab7b3 235 let pats : Matrix = vec![vec![
32a655c1 236 expand_pattern(cx, pattern)
c30ab7b3
SL
237 ]].into_iter().collect();
238
32a655c1
SL
239 let wild_pattern = Pattern {
240 ty: pattern_ty,
241 span: DUMMY_SP,
242 kind: box PatternKind::Wild,
243 };
244 let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) {
c30ab7b3
SL
245 UsefulWithWitness(witness) => witness,
246 NotUseful => return,
247 Useful => bug!()
248 };
249
32a655c1 250 let pattern_string = witness[0].single_pattern().to_string();
c30ab7b3
SL
251 let mut diag = struct_span_err!(
252 self.tcx.sess, pat.span, E0005,
253 "refutable pattern in {}: `{}` not covered",
254 origin, pattern_string
255 );
7cac9316 256 diag.span_label(pat.span, format!("pattern `{}` not covered", pattern_string));
c30ab7b3
SL
257 diag.emit();
258 });
1a4d82fc
JJ
259 }
260}
261
c30ab7b3 262fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
54a0048b 263 pat.walk(|p| {
476ff2be 264 if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), _, name, None) = p.node {
32a655c1 265 let pat_ty = cx.tables.pat_ty(p);
9e0c209e 266 if let ty::TyAdt(edef, _) = pat_ty.sty {
476ff2be
SL
267 if edef.is_enum() && edef.variants.iter().any(|variant| {
268 variant.name == name.node && variant.ctor_kind == CtorKind::Const
269 }) {
270 let ty_path = cx.tcx.item_path_str(edef.did);
271 let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
272 "pattern binding `{}` is named the same as one \
273 of the variants of the type `{}`",
274 name.node, ty_path);
275 help!(err,
276 "if you meant to match on a variant, \
277 consider making the path in the pattern qualified: `{}::{}`",
278 ty_path, name.node);
279 err.emit();
1a4d82fc
JJ
280 }
281 }
1a4d82fc
JJ
282 }
283 true
284 });
285}
286
c30ab7b3 287/// Checks for common cases of "catchall" patterns that may not be intended as such.
476ff2be 288fn pat_is_catchall(pat: &Pat) -> bool {
c30ab7b3
SL
289 match pat.node {
290 PatKind::Binding(.., None) => true,
476ff2be
SL
291 PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
292 PatKind::Ref(ref s, _) => pat_is_catchall(s),
c30ab7b3 293 PatKind::Tuple(ref v, _) => v.iter().all(|p| {
476ff2be 294 pat_is_catchall(&p)
c30ab7b3
SL
295 }),
296 _ => false
297 }
1a4d82fc
JJ
298}
299
223e47cc 300// Check for unreachable patterns
c30ab7b3
SL
301fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
302 arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
303 source: hir::MatchSource)
304{
305 let mut seen = Matrix::empty();
306 let mut catchall = None;
1a4d82fc 307 let mut printed_if_let_err = false;
32a655c1 308 for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
c30ab7b3
SL
309 for &(pat, hir_pat) in pats {
310 let v = vec![pat];
1a4d82fc 311
cc61c64b 312 match is_useful(cx, &seen, &v, LeaveOutWitness) {
1a4d82fc
JJ
313 NotUseful => {
314 match source {
e9174d1e 315 hir::MatchSource::IfLetDesugar { .. } => {
1a4d82fc
JJ
316 if printed_if_let_err {
317 // we already printed an irrefutable if-let pattern error.
318 // We don't want two, that's just confusing.
319 } else {
320 // find the first arm pattern so we can use its span
321 let &(ref first_arm_pats, _) = &arms[0];
322 let first_pat = &first_arm_pats[0];
c30ab7b3 323 let span = first_pat.0.span;
5bcae85e
SL
324 struct_span_err!(cx.tcx.sess, span, E0162,
325 "irrefutable if-let pattern")
7cac9316 326 .span_label(span, "irrefutable pattern")
5bcae85e 327 .emit();
1a4d82fc
JJ
328 printed_if_let_err = true;
329 }
330 },
331
e9174d1e 332 hir::MatchSource::WhileLetDesugar => {
1a4d82fc
JJ
333 // find the first arm pattern so we can use its span
334 let &(ref first_arm_pats, _) = &arms[0];
335 let first_pat = &first_arm_pats[0];
c30ab7b3 336 let span = first_pat.0.span;
1a4d82fc 337
32a655c1
SL
338 // check which arm we're on.
339 match arm_index {
340 // The arm with the user-specified pattern.
341 0 => {
342 let mut diagnostic = Diagnostic::new(Level::Warning,
343 "unreachable pattern");
344 diagnostic.set_span(pat.span);
345 cx.tcx.sess.add_lint_diagnostic(
346 lint::builtin::UNREACHABLE_PATTERNS,
347 hir_pat.id, diagnostic);
348 },
349 // The arm with the wildcard pattern.
350 1 => {
351 struct_span_err!(cx.tcx.sess, span, E0165,
352 "irrefutable while-let pattern")
7cac9316 353 .span_label(span, "irrefutable pattern")
32a655c1
SL
354 .emit();
355 },
356 _ => bug!(),
357 }
85aaf69f
SL
358 },
359
32a655c1 360 hir::MatchSource::ForLoopDesugar |
e9174d1e 361 hir::MatchSource::Normal => {
32a655c1
SL
362 let mut diagnostic = Diagnostic::new(Level::Warning,
363 "unreachable pattern");
364 diagnostic.set_span(pat.span);
a7813a04 365 // if we had a catchall pattern, hint at that
c30ab7b3 366 if let Some(catchall) = catchall {
7cac9316 367 diagnostic.span_label(pat.span, "this is an unreachable pattern");
32a655c1 368 diagnostic.span_note(catchall, "this pattern matches any value");
a7813a04 369 }
32a655c1
SL
370 cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS,
371 hir_pat.id, diagnostic);
1a4d82fc 372 },
54a0048b 373
32a655c1
SL
374 // Unreachable patterns in try expressions occur when one of the arms
375 // are an uninhabited type. Which is OK.
376 hir::MatchSource::TryDesugar => {}
1a4d82fc
JJ
377 }
378 }
379 Useful => (),
54a0048b 380 UsefulWithWitness(_) => bug!()
1a4d82fc
JJ
381 }
382 if guard.is_none() {
c30ab7b3 383 seen.push(v);
476ff2be 384 if catchall.is_none() && pat_is_catchall(hir_pat) {
c30ab7b3
SL
385 catchall = Some(pat.span);
386 }
223e47cc 387 }
223e47cc
LB
388 }
389 }
390}
391
c30ab7b3 392fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
32a655c1 393 scrut_ty: Ty<'tcx>,
3157f602 394 sp: Span,
7cac9316 395 matrix: &Matrix<'a, 'tcx>) {
32a655c1
SL
396 let wild_pattern = Pattern {
397 ty: scrut_ty,
398 span: DUMMY_SP,
399 kind: box PatternKind::Wild,
400 };
401 match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
1a4d82fc 402 UsefulWithWitness(pats) => {
7453a54e 403 let witnesses = if pats.is_empty() {
32a655c1 404 vec![&wild_pattern]
7453a54e 405 } else {
c30ab7b3 406 pats.iter().map(|w| w.single_pattern()).collect()
1a4d82fc 407 };
7cac9316
XL
408
409 const LIMIT: usize = 3;
410 let joined_patterns = match witnesses.len() {
411 0 => bug!(),
412 1 => format!("`{}`", witnesses[0]),
413 2...LIMIT => {
414 let (tail, head) = witnesses.split_last().unwrap();
415 let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
416 format!("`{}` and `{}`", head.join("`, `"), tail)
85aaf69f
SL
417 },
418 _ => {
7cac9316
XL
419 let (head, tail) = witnesses.split_at(LIMIT);
420 let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
421 format!("`{}` and {} more", head.join("`, `"), tail.len())
422 }
423 };
424
425 let label_text = match witnesses.len() {
426 1 => format!("pattern {} not covered", joined_patterns),
427 _ => format!("patterns {} not covered", joined_patterns)
428 };
429 create_e0004(cx.tcx.sess, sp,
430 format!("non-exhaustive patterns: {} not covered",
431 joined_patterns))
432 .span_label(sp, label_text)
433 .emit();
1a4d82fc
JJ
434 }
435 NotUseful => {
223e47cc 436 // This is good, wildcard pattern isn't reachable
1a4d82fc 437 },
54a0048b 438 _ => bug!()
1a4d82fc
JJ
439 }
440}
441
1a4d82fc 442// Legality of move bindings checking
c30ab7b3 443fn check_legality_of_move_bindings(cx: &MatchVisitor,
1a4d82fc
JJ
444 has_guard: bool,
445 pats: &[P<Pat>]) {
223e47cc 446 let mut by_ref_span = None;
85aaf69f 447 for pat in pats {
476ff2be 448 pat.each_binding(|bm, _, span, _path| {
3157f602
XL
449 if let hir::BindByRef(..) = bm {
450 by_ref_span = Some(span);
223e47cc 451 }
1a4d82fc 452 })
223e47cc
LB
453 }
454
85aaf69f 455 let check_move = |p: &Pat, sub: Option<&Pat>| {
223e47cc 456 // check legality of moving out of the enum
1a4d82fc
JJ
457
458 // x @ Foo(..) is legal, but x @ Foo(y) isn't.
476ff2be 459 if sub.map_or(false, |p| p.contains_bindings()) {
5bcae85e
SL
460 struct_span_err!(cx.tcx.sess, p.span, E0007,
461 "cannot bind by-move with sub-bindings")
7cac9316 462 .span_label(p.span, "binds an already bound by-move value by moving it")
5bcae85e 463 .emit();
223e47cc 464 } else if has_guard {
5bcae85e
SL
465 struct_span_err!(cx.tcx.sess, p.span, E0008,
466 "cannot bind by-move into a pattern guard")
7cac9316 467 .span_label(p.span, "moves value into pattern guard")
5bcae85e 468 .emit();
223e47cc 469 } else if by_ref_span.is_some() {
9e0c209e
SL
470 struct_span_err!(cx.tcx.sess, p.span, E0009,
471 "cannot bind by-move and by-ref in the same pattern")
7cac9316
XL
472 .span_label(p.span, "by-move pattern here")
473 .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
9e0c209e 474 .emit();
223e47cc
LB
475 }
476 };
477
85aaf69f 478 for pat in pats {
54a0048b 479 pat.walk(|p| {
476ff2be 480 if let PatKind::Binding(hir::BindByValue(..), _, _, ref sub) = p.node {
32a655c1 481 let pat_ty = cx.tables.node_id_to_type(p.id);
c30ab7b3
SL
482 if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
483 check_move(p, sub.as_ref().map(|p| &**p));
484 }
223e47cc 485 }
1a4d82fc
JJ
486 true
487 });
488 }
489}
490
491/// Ensures that a pattern guard doesn't borrow by mutable reference or
492/// assign.
c30ab7b3
SL
493///
494/// FIXME: this should be done by borrowck.
495fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
041b39d2
XL
496 let mut checker = MutationChecker {
497 cx: cx,
498 };
499 ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_maps, cx.tables)
500 .walk_expr(guard);
1a4d82fc
JJ
501}
502
041b39d2
XL
503struct MutationChecker<'a, 'tcx: 'a> {
504 cx: &'a MatchVisitor<'a, 'tcx>,
1a4d82fc
JJ
505}
506
041b39d2 507impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
1a4d82fc 508 fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
c30ab7b3 509 fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {}
1a4d82fc
JJ
510 fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
511 fn borrow(&mut self,
c30ab7b3 512 _: ast::NodeId,
1a4d82fc
JJ
513 span: Span,
514 _: cmt,
7cac9316 515 _: ty::Region<'tcx>,
9e0c209e 516 kind:ty:: BorrowKind,
1a4d82fc
JJ
517 _: LoanCause) {
518 match kind {
9e0c209e 519 ty::MutBorrow => {
5bcae85e 520 struct_span_err!(self.cx.tcx.sess, span, E0301,
85aaf69f 521 "cannot mutably borrow in a pattern guard")
7cac9316 522 .span_label(span, "borrowed mutably in pattern guard")
5bcae85e 523 .emit();
1a4d82fc 524 }
9e0c209e 525 ty::ImmBorrow | ty::UniqueImmBorrow => {}
1a4d82fc
JJ
526 }
527 }
c30ab7b3
SL
528 fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {}
529 fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) {
1a4d82fc 530 match mode {
9cc50fc6 531 MutateMode::JustWrite | MutateMode::WriteAndRead => {
5bcae85e 532 struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
7cac9316 533 .span_label(span, "assignment in pattern guard")
5bcae85e 534 .emit();
1a4d82fc 535 }
9cc50fc6 536 MutateMode::Init => {}
1a4d82fc
JJ
537 }
538 }
539}
540
541/// Forbids bindings in `@` patterns. This is necessary for memory safety,
542/// because of the way rvalues are handled in the borrow check. (See issue
543/// #14587.)
c30ab7b3 544fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor, pat: &Pat) {
1a4d82fc
JJ
545 AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat);
546}
547
548struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
c30ab7b3 549 cx: &'a MatchVisitor<'b, 'tcx>,
1a4d82fc
JJ
550 bindings_allowed: bool
551}
552
553impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
476ff2be
SL
554 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
555 NestedVisitorMap::None
556 }
557
1a4d82fc 558 fn visit_pat(&mut self, pat: &Pat) {
1a4d82fc 559 match pat.node {
9e0c209e 560 PatKind::Binding(.., ref subpat) => {
3157f602 561 if !self.bindings_allowed {
c30ab7b3
SL
562 struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
563 "pattern bindings are not allowed after an `@`")
7cac9316 564 .span_label(pat.span, "not allowed after `@`")
c30ab7b3 565 .emit();
3157f602
XL
566 }
567
568 if subpat.is_some() {
569 let bindings_were_allowed = self.bindings_allowed;
570 self.bindings_allowed = false;
571 intravisit::walk_pat(self, pat);
572 self.bindings_allowed = bindings_were_allowed;
573 }
1a4d82fc 574 }
92a42be0 575 _ => intravisit::walk_pat(self, pat),
223e47cc 576 }
223e47cc
LB
577 }
578}