2014-02-10 08:36:31 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-06 02:05:53 -06:00
|
|
|
pub use self::Constructor::*;
|
|
|
|
use self::Usefulness::*;
|
|
|
|
use self::WitnessPreference::*;
|
|
|
|
|
2014-11-09 09:14:15 -06:00
|
|
|
use middle::const_eval::{compare_const_vals, const_bool, const_float, const_val};
|
2014-07-13 08:12:47 -05:00
|
|
|
use middle::const_eval::{const_expr_to_pat, eval_const_expr, lookup_const_by_id};
|
2014-05-14 14:31:30 -05:00
|
|
|
use middle::def::*;
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
|
|
|
|
use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
|
|
|
|
use middle::expr_use_visitor::{WriteAndRead};
|
2014-09-16 08:24:56 -05:00
|
|
|
use middle::expr_use_visitor as euv;
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
use middle::mem_categorization::cmt;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::pat_util::*;
|
|
|
|
use middle::ty::*;
|
2014-12-14 22:03:00 -06:00
|
|
|
use middle::ty;
|
2015-01-29 05:40:14 -06:00
|
|
|
use std::cmp::Ordering;
|
2014-06-25 12:07:37 -05:00
|
|
|
use std::fmt;
|
2015-02-18 12:06:21 -06:00
|
|
|
use std::iter::{range_inclusive, AdditiveIterator, FromIterator, IntoIterator, repeat};
|
2014-11-09 23:26:10 -06:00
|
|
|
use std::num::Float;
|
2014-09-07 12:09:06 -05:00
|
|
|
use std::slice;
|
2015-01-03 21:42:21 -06:00
|
|
|
use syntax::ast::{self, DUMMY_NODE_ID, NodeId, Pat};
|
2015-02-05 11:26:58 -06:00
|
|
|
use syntax::ast_util;
|
2014-06-07 07:17:01 -05:00
|
|
|
use syntax::codemap::{Span, Spanned, DUMMY_SP};
|
2014-07-13 08:12:47 -05:00
|
|
|
use syntax::fold::{Folder, noop_fold_pat};
|
2014-06-21 05:39:03 -05:00
|
|
|
use syntax::print::pprust::pat_to_string;
|
2014-07-13 08:12:47 -05:00
|
|
|
use syntax::parse::token;
|
2014-09-07 12:09:06 -05:00
|
|
|
use syntax::ptr::P;
|
2015-01-03 21:42:21 -06:00
|
|
|
use syntax::visit::{self, Visitor, FnKind};
|
2014-06-21 05:39:03 -05:00
|
|
|
use util::ppaux::ty_to_string;
|
2015-02-05 11:26:58 -06:00
|
|
|
use util::nodemap::FnvHashMap;
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-10-10 10:49:12 -05:00
|
|
|
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
|
2014-09-07 12:09:06 -05:00
|
|
|
id: DUMMY_NODE_ID,
|
2014-09-13 12:10:34 -05:00
|
|
|
node: ast::PatWild(ast::PatWildSingle),
|
2014-09-07 12:09:06 -05:00
|
|
|
span: DUMMY_SP
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Matrix<'a>(Vec<Vec<&'a Pat>>);
|
2014-06-25 12:07:37 -05:00
|
|
|
|
|
|
|
/// Pretty-printer for matrices of patterns, example:
|
|
|
|
/// ++++++++++++++++++++++++++
|
2015-01-07 10:58:31 -06:00
|
|
|
/// + _ + [] +
|
2014-06-25 12:07:37 -05:00
|
|
|
/// ++++++++++++++++++++++++++
|
|
|
|
/// + true + [First] +
|
|
|
|
/// ++++++++++++++++++++++++++
|
|
|
|
/// + true + [Second(true)] +
|
|
|
|
/// ++++++++++++++++++++++++++
|
|
|
|
/// + false + [_] +
|
|
|
|
/// ++++++++++++++++++++++++++
|
|
|
|
/// + _ + [_, _, ..tail] +
|
|
|
|
/// ++++++++++++++++++++++++++
|
2015-01-20 17:45:07 -06:00
|
|
|
impl<'a> fmt::Debug for Matrix<'a> {
|
2014-06-25 12:07:37 -05:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
try!(write!(f, "\n"));
|
|
|
|
|
|
|
|
let &Matrix(ref m) = self;
|
|
|
|
let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
|
2014-07-07 18:35:15 -05:00
|
|
|
row.iter()
|
|
|
|
.map(|&pat| pat_to_string(&*pat))
|
|
|
|
.collect::<Vec<String>>()
|
2014-06-25 12:07:37 -05:00
|
|
|
}).collect();
|
|
|
|
|
2015-01-25 04:58:43 -06:00
|
|
|
let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
|
2014-06-25 12:07:37 -05:00
|
|
|
assert!(m.iter().all(|row| row.len() == column_count));
|
2015-01-26 14:44:22 -06:00
|
|
|
let column_widths: Vec<uint> = (0..column_count).map(|col| {
|
2015-01-25 04:58:43 -06:00
|
|
|
pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)
|
2014-06-25 12:07:37 -05:00
|
|
|
}).collect();
|
|
|
|
|
2015-02-13 01:33:44 -06:00
|
|
|
let total_width = column_widths.iter().cloned().sum() + column_count * 3 + 1;
|
2014-12-28 12:29:56 -06:00
|
|
|
let br = repeat('+').take(total_width).collect::<String>();
|
2014-06-25 12:07:37 -05:00
|
|
|
try!(write!(f, "{}\n", br));
|
2015-01-31 19:03:04 -06:00
|
|
|
for row in pretty_printed_matrix {
|
2014-06-25 12:07:37 -05:00
|
|
|
try!(write!(f, "+"));
|
2014-09-14 22:27:36 -05:00
|
|
|
for (column, pat_str) in row.into_iter().enumerate() {
|
2014-06-25 12:07:37 -05:00
|
|
|
try!(write!(f, " "));
|
2014-11-17 13:29:38 -06:00
|
|
|
try!(write!(f, "{:1$}", pat_str, column_widths[column]));
|
2014-06-25 12:07:37 -05:00
|
|
|
try!(write!(f, " +"));
|
|
|
|
}
|
|
|
|
try!(write!(f, "\n"));
|
|
|
|
try!(write!(f, "{}\n", br));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> {
|
2015-02-18 12:06:21 -06:00
|
|
|
fn from_iter<T: IntoIterator<Item=Vec<&'a Pat>>>(iter: T) -> Matrix<'a> {
|
|
|
|
Matrix(iter.into_iter().collect())
|
2014-07-13 08:12:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
pub tcx: &'a ty::ctxt<'tcx>,
|
2015-01-02 03:09:35 -06:00
|
|
|
pub param_env: ParameterEnvironment<'a, 'tcx>,
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
|
|
|
|
2015-01-03 21:54:18 -06:00
|
|
|
#[derive(Clone, PartialEq)]
|
2014-06-21 07:56:23 -05:00
|
|
|
pub enum Constructor {
|
2014-06-25 12:07:37 -05:00
|
|
|
/// The constructor of all patterns that don't vary by constructor,
|
|
|
|
/// e.g. struct patterns and fixed-length arrays.
|
|
|
|
Single,
|
|
|
|
/// Enum variants.
|
2014-09-13 12:10:34 -05:00
|
|
|
Variant(ast::DefId),
|
2014-06-25 12:07:37 -05:00
|
|
|
/// Literal values.
|
|
|
|
ConstantValue(const_val),
|
|
|
|
/// Ranges of literal values (2..5).
|
|
|
|
ConstantRange(const_val, const_val),
|
|
|
|
/// Array patterns of length n.
|
2014-08-30 09:22:19 -05:00
|
|
|
Slice(uint),
|
|
|
|
/// Array patterns with a subslice.
|
|
|
|
SliceWithSubslice(uint, uint)
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2015-01-03 21:54:18 -06:00
|
|
|
#[derive(Clone, PartialEq)]
|
2014-06-07 07:17:01 -05:00
|
|
|
enum Usefulness {
|
2014-07-03 15:53:20 -05:00
|
|
|
Useful,
|
2014-09-07 12:09:06 -05:00
|
|
|
UsefulWithWitness(Vec<P<Pat>>),
|
2014-06-07 07:17:01 -05:00
|
|
|
NotUseful
|
|
|
|
}
|
|
|
|
|
2015-01-03 21:54:18 -06:00
|
|
|
#[derive(Copy)]
|
2014-06-07 07:17:01 -05:00
|
|
|
enum WitnessPreference {
|
|
|
|
ConstructWitness,
|
|
|
|
LeaveOutWitness
|
|
|
|
}
|
|
|
|
|
2014-09-09 17:54:36 -05:00
|
|
|
impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> {
|
2014-09-13 12:10:34 -05:00
|
|
|
fn visit_expr(&mut self, ex: &ast::Expr) {
|
2014-03-05 21:07:47 -06:00
|
|
|
check_expr(self, ex);
|
2013-08-12 20:29:15 -05:00
|
|
|
}
|
2014-09-13 12:10:34 -05:00
|
|
|
fn visit_local(&mut self, l: &ast::Local) {
|
2014-03-05 21:07:47 -06:00
|
|
|
check_local(self, l);
|
2013-08-12 20:29:15 -05:00
|
|
|
}
|
2014-09-13 12:10:34 -05:00
|
|
|
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v ast::FnDecl,
|
|
|
|
b: &'v ast::Block, s: Span, n: NodeId) {
|
2014-11-15 16:26:15 -06:00
|
|
|
check_fn(self, fk, fd, b, s, n);
|
2013-08-12 20:29:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
pub fn check_crate(tcx: &ty::ctxt) {
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
visit::walk_crate(&mut MatchCheckCtxt {
|
|
|
|
tcx: tcx,
|
2015-01-02 03:09:35 -06:00
|
|
|
param_env: ty::empty_parameter_environment(tcx),
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
}, tcx.map.krate());
|
2011-07-25 06:45:09 -05:00
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) {
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_expr(cx, ex);
|
2012-08-06 14:34:08 -05:00
|
|
|
match ex.node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::ExprMatch(ref scrut, ref arms, source) => {
|
2015-01-31 11:20:46 -06:00
|
|
|
for arm in arms {
|
2014-11-20 09:57:36 -06:00
|
|
|
// First, check legality of move bindings.
|
2014-06-07 07:17:01 -05:00
|
|
|
check_legality_of_move_bindings(cx,
|
|
|
|
arm.guard.is_some(),
|
2015-02-20 13:08:14 -06:00
|
|
|
&arm.pats);
|
2012-12-05 21:01:14 -06:00
|
|
|
|
2014-11-20 09:57:36 -06:00
|
|
|
// Second, if there is a guard on each arm, make sure it isn't
|
|
|
|
// assigning or borrowing anything mutably.
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
match arm.guard {
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(ref guard) => check_for_mutation_in_guard(cx, &**guard),
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-05 11:26:58 -06:00
|
|
|
let mut static_inliner = StaticInliner::new(cx.tcx, None);
|
2014-09-07 12:09:06 -05:00
|
|
|
let inlined_arms = arms.iter().map(|arm| {
|
|
|
|
(arm.pats.iter().map(|pat| {
|
|
|
|
static_inliner.fold_pat((*pat).clone())
|
|
|
|
}).collect(), arm.guard.as_ref().map(|e| &**e))
|
2014-09-13 12:10:34 -05:00
|
|
|
}).collect::<Vec<(Vec<P<Pat>>, Option<&ast::Expr>)>>();
|
2014-08-17 15:10:25 -05:00
|
|
|
|
2014-11-20 09:57:36 -06:00
|
|
|
// Bail out early if inlining failed.
|
2014-08-17 15:10:25 -05:00
|
|
|
if static_inliner.failed {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-20 09:57:36 -06:00
|
|
|
for pat in inlined_arms
|
|
|
|
.iter()
|
|
|
|
.flat_map(|&(ref pats, _)| pats.iter()) {
|
|
|
|
// Third, check legality of move bindings.
|
|
|
|
check_legality_of_bindings_in_at_patterns(cx, &**pat);
|
|
|
|
|
|
|
|
// Fourth, check if there are any references to NaN that we should warn about.
|
|
|
|
check_for_static_nan(cx, &**pat);
|
|
|
|
|
|
|
|
// Fifth, check if for any of the patterns that match an enumerated type
|
|
|
|
// are bindings with the same name as one of the variants of said type.
|
|
|
|
check_for_bindings_named_the_same_as_variants(cx, &**pat);
|
2014-09-07 12:09:06 -05:00
|
|
|
}
|
2014-08-17 15:10:25 -05:00
|
|
|
|
|
|
|
// Fourth, check for unreachable arms.
|
2015-02-18 13:48:57 -06:00
|
|
|
check_arms(cx, &inlined_arms[..], source);
|
2014-06-19 13:55:12 -05:00
|
|
|
|
|
|
|
// Finally, check if the whole match expression is exhaustive.
|
|
|
|
// Check for empty enum, because is_useful only works on inhabited types.
|
2014-06-07 07:17:01 -05:00
|
|
|
let pat_ty = node_id_to_type(cx.tcx, scrut.id);
|
2014-08-17 15:10:25 -05:00
|
|
|
if inlined_arms.is_empty() {
|
2014-07-11 11:54:01 -05:00
|
|
|
if !type_is_empty(cx.tcx, pat_ty) {
|
|
|
|
// We know the type is inhabited, so this must be wrong
|
|
|
|
span_err!(cx.tcx.sess, ex.span, E0002,
|
|
|
|
"non-exhaustive patterns: type {} is non-empty",
|
|
|
|
ty_to_string(cx.tcx, pat_ty)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// If the type *is* empty, it's vacuously exhaustive
|
|
|
|
return;
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
2014-07-13 08:12:47 -05:00
|
|
|
|
2014-08-17 15:10:25 -05:00
|
|
|
let matrix: Matrix = inlined_arms
|
2014-09-07 12:09:06 -05:00
|
|
|
.iter()
|
|
|
|
.filter(|&&(_, guard)| guard.is_none())
|
2014-12-09 11:21:18 -06:00
|
|
|
.flat_map(|arm| arm.0.iter())
|
2014-09-07 12:09:06 -05:00
|
|
|
.map(|pat| vec![&**pat])
|
2014-07-13 08:12:47 -05:00
|
|
|
.collect();
|
2015-01-22 16:46:40 -06:00
|
|
|
check_exhaustive(cx, ex.span, &matrix, source);
|
2014-06-07 07:17:01 -05:00
|
|
|
},
|
|
|
|
_ => ()
|
2012-01-14 18:05:07 -06:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
fn is_expr_const_nan(tcx: &ty::ctxt, expr: &ast::Expr) -> bool {
|
2014-07-13 08:12:47 -05:00
|
|
|
match eval_const_expr(tcx, expr) {
|
|
|
|
const_float(f) => f.is_nan(),
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-20 09:57:36 -06:00
|
|
|
fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) {
|
2015-02-05 11:26:58 -06:00
|
|
|
ast_util::walk_pat(pat, |p| {
|
2014-11-20 09:57:36 -06:00
|
|
|
match p.node {
|
|
|
|
ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => {
|
|
|
|
let pat_ty = ty::pat_ty(cx.tcx, p);
|
|
|
|
if let ty::ty_enum(def_id, _) = pat_ty.sty {
|
2015-02-16 22:44:23 -06:00
|
|
|
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
|
2014-11-20 09:57:36 -06:00
|
|
|
if let Some(DefLocal(_)) = def {
|
|
|
|
if ty::enum_variants(cx.tcx, def_id).iter().any(|variant|
|
|
|
|
token::get_name(variant.name) == token::get_name(ident.node.name)
|
|
|
|
&& variant.args.len() == 0
|
|
|
|
) {
|
|
|
|
span_warn!(cx.tcx.sess, p.span, E0170,
|
|
|
|
"pattern binding `{}` is named the same as one \
|
|
|
|
of the variants of the type `{}`",
|
2015-02-04 14:48:12 -06:00
|
|
|
&token::get_ident(ident.node), ty_to_string(cx.tcx, pat_ty));
|
2014-11-20 09:57:36 -06:00
|
|
|
span_help!(cx.tcx.sess, p.span,
|
|
|
|
"if you meant to match on a variant, \
|
|
|
|
consider making the path in the pattern qualified: `{}::{}`",
|
2015-02-04 14:48:12 -06:00
|
|
|
ty_to_string(cx.tcx, pat_ty), &token::get_ident(ident.node));
|
2014-11-20 09:57:36 -06:00
|
|
|
}
|
|
|
|
}
|
2013-07-24 11:00:33 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
}
|
2014-11-20 09:57:36 -06:00
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that we do not match against a static NaN (#6804)
|
|
|
|
fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
|
2015-02-05 11:26:58 -06:00
|
|
|
ast_util::walk_pat(pat, |p| {
|
2014-11-20 09:57:36 -06:00
|
|
|
match p.node {
|
|
|
|
ast::PatLit(ref expr) if is_expr_const_nan(cx.tcx, &**expr) => {
|
|
|
|
span_warn!(cx.tcx.sess, p.span, E0003,
|
|
|
|
"unmatchable NaN in pattern, \
|
|
|
|
use the is_nan method in a guard instead");
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
true
|
|
|
|
});
|
2014-08-17 15:10:25 -05:00
|
|
|
}
|
2013-07-24 11:00:33 -05:00
|
|
|
|
2014-08-17 15:10:25 -05:00
|
|
|
// Check for unreachable patterns
|
2014-09-13 12:10:34 -05:00
|
|
|
fn check_arms(cx: &MatchCheckCtxt,
|
|
|
|
arms: &[(Vec<P<Pat>>, Option<&ast::Expr>)],
|
|
|
|
source: ast::MatchSource) {
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut seen = Matrix(vec![]);
|
2014-08-25 16:55:00 -05:00
|
|
|
let mut printed_if_let_err = false;
|
2015-01-31 11:20:46 -06:00
|
|
|
for &(ref pats, guard) in arms {
|
|
|
|
for pat in pats {
|
2014-09-07 12:09:06 -05:00
|
|
|
let v = vec![&**pat];
|
2014-08-25 16:55:00 -05:00
|
|
|
|
2015-02-18 13:48:57 -06:00
|
|
|
match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
|
2014-08-25 16:55:00 -05:00
|
|
|
NotUseful => {
|
2014-10-02 23:41:24 -05:00
|
|
|
match source {
|
2014-12-19 16:58:02 -06:00
|
|
|
ast::MatchSource::IfLetDesugar { .. } => {
|
2014-10-02 23:41:24 -05:00
|
|
|
if printed_if_let_err {
|
|
|
|
// we already printed an irrefutable if-let pattern error.
|
|
|
|
// We don't want two, that's just confusing.
|
|
|
|
} else {
|
|
|
|
// find the first arm pattern so we can use its span
|
|
|
|
let &(ref first_arm_pats, _) = &arms[0];
|
2014-10-15 01:05:01 -05:00
|
|
|
let first_pat = &first_arm_pats[0];
|
2014-10-02 23:41:24 -05:00
|
|
|
let span = first_pat.span;
|
|
|
|
span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern");
|
|
|
|
printed_if_let_err = true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-12-19 16:58:02 -06:00
|
|
|
ast::MatchSource::WhileLetDesugar => {
|
2014-08-25 16:55:00 -05:00
|
|
|
// find the first arm pattern so we can use its span
|
2014-09-29 15:45:26 -05:00
|
|
|
let &(ref first_arm_pats, _) = &arms[0];
|
2014-10-15 01:05:01 -05:00
|
|
|
let first_pat = &first_arm_pats[0];
|
2014-08-25 16:55:00 -05:00
|
|
|
let span = first_pat.span;
|
2014-10-02 23:41:24 -05:00
|
|
|
span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern");
|
|
|
|
},
|
|
|
|
|
2015-01-22 16:46:40 -06:00
|
|
|
ast::MatchSource::ForLoopDesugar => {
|
|
|
|
// this is a bug, because on `match iter.next()` we cover
|
|
|
|
// `Some(<head>)` and `None`. It's impossible to have an unreachable
|
|
|
|
// pattern
|
|
|
|
// (see libsyntax/ext/expand.rs for the full expansion of a for loop)
|
|
|
|
cx.tcx.sess.span_bug(pat.span, "unreachable for-loop pattern")
|
|
|
|
},
|
|
|
|
|
2014-12-19 16:58:02 -06:00
|
|
|
ast::MatchSource::Normal => {
|
2014-10-11 11:03:15 -05:00
|
|
|
span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
|
|
|
|
},
|
2014-08-25 16:55:00 -05:00
|
|
|
}
|
|
|
|
}
|
2014-07-03 15:53:20 -05:00
|
|
|
Useful => (),
|
|
|
|
UsefulWithWitness(_) => unreachable!()
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
if guard.is_none() {
|
2014-06-25 12:07:37 -05:00
|
|
|
let Matrix(mut rows) = seen;
|
|
|
|
rows.push(v);
|
|
|
|
seen = Matrix(rows);
|
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
fn raw_pat<'a>(p: &'a Pat) -> &'a Pat {
|
|
|
|
match p.node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(_, _, Some(ref s)) => raw_pat(&**s),
|
2014-09-07 12:09:06 -05:00
|
|
|
_ => p
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-22 16:46:40 -06:00
|
|
|
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: ast::MatchSource) {
|
2014-10-10 10:49:12 -05:00
|
|
|
match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) {
|
2014-07-03 15:53:20 -05:00
|
|
|
UsefulWithWitness(pats) => {
|
2015-02-18 13:48:57 -06:00
|
|
|
let witness = match &pats[..] {
|
2014-09-07 12:09:06 -05:00
|
|
|
[ref witness] => &**witness,
|
2014-10-10 10:49:12 -05:00
|
|
|
[] => DUMMY_WILD_PAT,
|
2014-06-07 07:17:01 -05:00
|
|
|
_ => unreachable!()
|
|
|
|
};
|
2015-01-22 16:46:40 -06:00
|
|
|
match source {
|
|
|
|
ast::MatchSource::ForLoopDesugar => {
|
|
|
|
// `witness` has the form `Some(<head>)`, peel off the `Some`
|
|
|
|
let witness = match witness.node {
|
2015-02-18 13:48:57 -06:00
|
|
|
ast::PatEnum(_, Some(ref pats)) => match &pats[..] {
|
2015-01-22 16:46:40 -06:00
|
|
|
[ref pat] => &**pat,
|
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
span_err!(cx.tcx.sess, sp, E0297,
|
|
|
|
"refutable pattern in `for` loop binding: \
|
|
|
|
`{}` not covered",
|
|
|
|
pat_to_string(witness));
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
span_err!(cx.tcx.sess, sp, E0004,
|
|
|
|
"non-exhaustive patterns: `{}` not covered",
|
|
|
|
pat_to_string(witness)
|
|
|
|
);
|
|
|
|
},
|
|
|
|
}
|
2012-02-15 02:40:42 -06:00
|
|
|
}
|
2014-06-25 12:07:37 -05:00
|
|
|
NotUseful => {
|
|
|
|
// This is good, wildcard pattern isn't reachable
|
2014-07-03 15:53:20 -05:00
|
|
|
},
|
|
|
|
_ => unreachable!()
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
2014-01-10 16:02:36 -06:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
fn const_val_to_expr(value: &const_val) -> P<ast::Expr> {
|
2014-06-07 07:17:01 -05:00
|
|
|
let node = match value {
|
2014-09-13 12:10:34 -05:00
|
|
|
&const_bool(b) => ast::LitBool(b),
|
2014-06-07 07:17:01 -05:00
|
|
|
_ => unreachable!()
|
|
|
|
};
|
2014-09-13 12:10:34 -05:00
|
|
|
P(ast::Expr {
|
2014-06-07 07:17:01 -05:00
|
|
|
id: 0,
|
2014-09-13 12:10:34 -05:00
|
|
|
node: ast::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
|
2014-06-07 07:17:01 -05:00
|
|
|
span: DUMMY_SP
|
2014-09-07 12:09:06 -05:00
|
|
|
})
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
pub struct StaticInliner<'a, 'tcx: 'a> {
|
|
|
|
pub tcx: &'a ty::ctxt<'tcx>,
|
2015-02-05 11:26:58 -06:00
|
|
|
pub failed: bool,
|
|
|
|
pub renaming_map: Option<&'a mut FnvHashMap<(NodeId, Span), NodeId>>,
|
2014-08-17 15:10:25 -05:00
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
|
2015-02-05 11:26:58 -06:00
|
|
|
pub fn new<'b>(tcx: &'b ty::ctxt<'tcx>,
|
|
|
|
renaming_map: Option<&'b mut FnvHashMap<(NodeId, Span), NodeId>>)
|
|
|
|
-> StaticInliner<'b, 'tcx> {
|
2014-08-17 15:10:25 -05:00
|
|
|
StaticInliner {
|
|
|
|
tcx: tcx,
|
2015-02-05 11:26:58 -06:00
|
|
|
failed: false,
|
|
|
|
renaming_map: renaming_map
|
2014-08-17 15:10:25 -05:00
|
|
|
}
|
|
|
|
}
|
2014-07-13 08:12:47 -05:00
|
|
|
}
|
|
|
|
|
2015-02-05 11:26:58 -06:00
|
|
|
struct RenamingRecorder<'map> {
|
|
|
|
substituted_node_id: NodeId,
|
|
|
|
origin_span: Span,
|
|
|
|
renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> {
|
|
|
|
fn visit_id(&mut self, node_id: NodeId) {
|
|
|
|
let key = (node_id, self.origin_span);
|
|
|
|
self.renaming_map.insert(key, self.substituted_node_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
|
2014-09-07 12:09:06 -05:00
|
|
|
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
|
2015-02-05 11:26:58 -06:00
|
|
|
return match pat.node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(..) | ast::PatEnum(..) => {
|
2015-02-16 22:44:23 -06:00
|
|
|
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
|
2014-07-13 08:12:47 -05:00
|
|
|
match def {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(const_expr) => {
|
2015-02-05 11:26:58 -06:00
|
|
|
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
|
|
|
|
|
|
|
|
if let Some(ref mut renaming_map) = self.renaming_map {
|
|
|
|
// Record any renamings we do here
|
|
|
|
record_renamings(const_expr, &pat, renaming_map);
|
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
new_pat
|
|
|
|
})
|
|
|
|
}
|
2014-08-17 15:10:25 -05:00
|
|
|
None => {
|
|
|
|
self.failed = true;
|
|
|
|
span_err!(self.tcx.sess, pat.span, E0158,
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
"statics cannot be referenced in patterns");
|
2014-08-17 15:10:25 -05:00
|
|
|
pat
|
|
|
|
}
|
2014-07-13 08:12:47 -05:00
|
|
|
},
|
|
|
|
_ => noop_fold_pat(pat, self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => noop_fold_pat(pat, self)
|
2015-02-05 11:26:58 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
fn record_renamings(const_expr: &ast::Expr,
|
|
|
|
substituted_pat: &ast::Pat,
|
|
|
|
renaming_map: &mut FnvHashMap<(NodeId, Span), NodeId>) {
|
|
|
|
let mut renaming_recorder = RenamingRecorder {
|
|
|
|
substituted_node_id: substituted_pat.id,
|
|
|
|
origin_span: substituted_pat.span,
|
|
|
|
renaming_map: renaming_map,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut id_visitor = ast_util::IdVisitor {
|
|
|
|
operation: &mut renaming_recorder,
|
|
|
|
pass_through_items: true,
|
|
|
|
visited_outermost: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
id_visitor.visit_expr(const_expr);
|
2014-07-13 08:12:47 -05:00
|
|
|
}
|
|
|
|
}
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a partial witness for a pattern given a list of
|
|
|
|
/// patterns expanded by the specialization step.
|
|
|
|
///
|
|
|
|
/// When a pattern P is discovered to be useful, this function is used bottom-up
|
|
|
|
/// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
|
|
|
|
/// of values, V, where each value in that set is not covered by any previously
|
|
|
|
/// used patterns and is covered by the pattern P'. Examples:
|
|
|
|
///
|
|
|
|
/// left_ty: tuple of 3 elements
|
|
|
|
/// pats: [10, 20, _] => (10, 20, _)
|
|
|
|
///
|
|
|
|
/// left_ty: struct X { a: (bool, &'static str), b: uint}
|
|
|
|
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
|
|
|
|
fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
|
2014-09-13 13:09:25 -05:00
|
|
|
pats: Vec<&Pat>, left_ty: Ty) -> P<Pat> {
|
2014-09-07 12:09:06 -05:00
|
|
|
let pats_len = pats.len();
|
2014-09-14 22:27:36 -05:00
|
|
|
let mut pats = pats.into_iter().map(|p| P((*p).clone()));
|
2014-10-31 03:51:16 -05:00
|
|
|
let pat = match left_ty.sty {
|
2014-09-13 12:10:34 -05:00
|
|
|
ty::ty_tup(_) => ast::PatTup(pats.collect()),
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-06-19 13:55:12 -05:00
|
|
|
ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => {
|
|
|
|
let (vid, is_structure) = match ctor {
|
2014-07-13 08:12:47 -05:00
|
|
|
&Variant(vid) =>
|
|
|
|
(vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
|
|
|
|
_ =>
|
2014-11-20 09:57:36 -06:00
|
|
|
(cid, !ty::is_tuple_struct(cx.tcx, cid))
|
2014-06-07 07:17:01 -05:00
|
|
|
};
|
2014-06-19 13:55:12 -05:00
|
|
|
if is_structure {
|
|
|
|
let fields = ty::lookup_struct_fields(cx.tcx, vid);
|
2014-09-13 12:10:34 -05:00
|
|
|
let field_pats: Vec<_> = fields.into_iter()
|
2014-09-07 12:09:06 -05:00
|
|
|
.zip(pats)
|
2014-09-13 12:10:34 -05:00
|
|
|
.filter(|&(_, ref pat)| pat.node != ast::PatWild(ast::PatWildSingle))
|
2014-10-05 19:36:53 -05:00
|
|
|
.map(|(field, pat)| Spanned {
|
|
|
|
span: DUMMY_SP,
|
2014-09-13 12:10:34 -05:00
|
|
|
node: ast::FieldPat {
|
|
|
|
ident: ast::Ident::new(field.name),
|
2014-10-05 19:36:53 -05:00
|
|
|
pat: pat,
|
2014-10-27 02:11:26 -05:00
|
|
|
is_shorthand: false,
|
2014-10-05 19:36:53 -05:00
|
|
|
}
|
2014-06-19 13:55:12 -05:00
|
|
|
}).collect();
|
2014-09-07 12:09:06 -05:00
|
|
|
let has_more_fields = field_pats.len() < pats_len;
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatStruct(def_to_path(cx.tcx, vid), field_pats, has_more_fields)
|
2014-06-19 13:55:12 -05:00
|
|
|
} else {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatEnum(def_to_path(cx.tcx, vid), Some(pats.collect()))
|
2014-06-19 13:55:12 -05:00
|
|
|
}
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-12-05 17:56:25 -06:00
|
|
|
ty::ty_rptr(_, ty::mt { ty, mutbl }) => {
|
2014-10-31 03:51:16 -05:00
|
|
|
match ty.sty {
|
2014-06-25 12:07:37 -05:00
|
|
|
ty::ty_vec(_, Some(n)) => match ctor {
|
|
|
|
&Single => {
|
2014-09-07 12:09:06 -05:00
|
|
|
assert_eq!(pats_len, n);
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatVec(pats.collect(), None, vec!())
|
2014-06-25 12:07:37 -05:00
|
|
|
},
|
|
|
|
_ => unreachable!()
|
|
|
|
},
|
2014-06-07 07:17:01 -05:00
|
|
|
ty::ty_vec(_, None) => match ctor {
|
2014-06-25 12:07:37 -05:00
|
|
|
&Slice(n) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
assert_eq!(pats_len, n);
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatVec(pats.collect(), None, vec!())
|
2014-06-25 12:07:37 -05:00
|
|
|
},
|
2014-06-07 07:17:01 -05:00
|
|
|
_ => unreachable!()
|
|
|
|
},
|
2014-09-13 12:10:34 -05:00
|
|
|
ty::ty_str => ast::PatWild(ast::PatWildSingle),
|
2014-06-25 12:07:37 -05:00
|
|
|
|
2014-06-07 07:17:01 -05:00
|
|
|
_ => {
|
2014-09-07 12:09:06 -05:00
|
|
|
assert_eq!(pats_len, 1);
|
2014-12-05 17:56:25 -06:00
|
|
|
ast::PatRegion(pats.nth(0).unwrap(), mutbl)
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
}
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
ty::ty_vec(_, Some(len)) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
assert_eq!(pats_len, len);
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatVec(pats.collect(), None, vec![])
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
|
|
|
|
_ => {
|
2014-06-25 12:07:37 -05:00
|
|
|
match *ctor {
|
2014-09-13 12:10:34 -05:00
|
|
|
ConstantValue(ref v) => ast::PatLit(const_val_to_expr(v)),
|
|
|
|
_ => ast::PatWild(ast::PatWildSingle),
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
P(ast::Pat {
|
2014-06-07 07:17:01 -05:00
|
|
|
id: 0,
|
|
|
|
node: pat,
|
|
|
|
span: DUMMY_SP
|
2014-09-07 12:09:06 -05:00
|
|
|
})
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
|
2014-09-13 13:09:25 -05:00
|
|
|
left_ty: Ty, max_slice_length: uint) -> Option<Constructor> {
|
2014-06-25 12:07:37 -05:00
|
|
|
let used_constructors: Vec<Constructor> = rows.iter()
|
2014-10-15 01:05:01 -05:00
|
|
|
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length).into_iter())
|
2014-06-07 07:17:01 -05:00
|
|
|
.collect();
|
2014-06-25 12:07:37 -05:00
|
|
|
all_constructors(cx, left_ty, max_slice_length)
|
2014-09-14 22:27:36 -05:00
|
|
|
.into_iter()
|
2014-06-07 07:17:01 -05:00
|
|
|
.find(|c| !used_constructors.contains(c))
|
|
|
|
}
|
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
/// This determines the set of all possible constructors of a pattern matching
|
|
|
|
/// values of type `left_ty`. For vectors, this would normally be an infinite set
|
|
|
|
/// but is instead bounded by the maximum fixed length of slice patterns in
|
|
|
|
/// the column of patterns being analyzed.
|
2014-09-13 13:09:25 -05:00
|
|
|
fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty,
|
2014-06-25 12:07:37 -05:00
|
|
|
max_slice_length: uint) -> Vec<Constructor> {
|
2014-10-31 03:51:16 -05:00
|
|
|
match left_ty.sty {
|
2014-06-07 07:17:01 -05:00
|
|
|
ty::ty_bool =>
|
2014-06-25 12:07:37 -05:00
|
|
|
[true, false].iter().map(|b| ConstantValue(const_bool(*b))).collect(),
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-10-31 03:51:16 -05:00
|
|
|
ty::ty_rptr(_, ty::mt { ty, .. }) => match ty.sty {
|
2014-06-25 12:07:37 -05:00
|
|
|
ty::ty_vec(_, None) =>
|
|
|
|
range_inclusive(0, max_slice_length).map(|length| Slice(length)).collect(),
|
|
|
|
_ => vec!(Single)
|
2014-06-07 07:17:01 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
ty::ty_enum(eid, _) =>
|
2014-06-19 13:55:12 -05:00
|
|
|
ty::enum_variants(cx.tcx, eid)
|
|
|
|
.iter()
|
2014-06-25 12:07:37 -05:00
|
|
|
.map(|va| Variant(va.id))
|
2014-06-19 13:55:12 -05:00
|
|
|
.collect(),
|
2014-06-07 07:17:01 -05:00
|
|
|
|
|
|
|
_ =>
|
2014-06-25 12:07:37 -05:00
|
|
|
vec!(Single)
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-24 04:13:25 -05:00
|
|
|
// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
|
|
|
|
//
|
|
|
|
// Whether a vector `v` of patterns is 'useful' in relation to a set of such
|
|
|
|
// vectors `m` is defined as there being a set of inputs that will match `v`
|
|
|
|
// but not any of the sets in `m`.
|
|
|
|
//
|
|
|
|
// This is used both for reachability checking (if a pattern isn't useful in
|
|
|
|
// relation to preceding patterns, it is not reachable) and exhaustiveness
|
|
|
|
// checking (if a wildcard pattern is useful in relation to a matrix, the
|
|
|
|
// matrix isn't exhaustive).
|
|
|
|
|
2012-07-27 15:13:03 -05:00
|
|
|
// Note: is_useful doesn't work on empty types, as the paper notes.
|
|
|
|
// So it assumes that v is non-empty.
|
2014-07-28 13:33:06 -05:00
|
|
|
fn is_useful(cx: &MatchCheckCtxt,
|
|
|
|
matrix: &Matrix,
|
2014-09-07 12:09:06 -05:00
|
|
|
v: &[&Pat],
|
2014-07-28 13:33:06 -05:00
|
|
|
witness: WitnessPreference)
|
|
|
|
-> Usefulness {
|
|
|
|
let &Matrix(ref rows) = matrix;
|
2014-12-20 02:09:35 -06:00
|
|
|
debug!("{:?}", matrix);
|
2015-01-25 04:58:43 -06:00
|
|
|
if rows.len() == 0 {
|
2014-07-03 15:53:20 -05:00
|
|
|
return match witness {
|
|
|
|
ConstructWitness => UsefulWithWitness(vec!()),
|
|
|
|
LeaveOutWitness => Useful
|
|
|
|
};
|
2014-03-08 14:36:22 -06:00
|
|
|
}
|
2015-01-25 04:58:43 -06:00
|
|
|
if rows[0].len() == 0 {
|
2014-06-07 07:17:01 -05:00
|
|
|
return NotUseful;
|
2014-03-08 14:36:22 -06:00
|
|
|
}
|
2014-10-15 01:05:01 -05:00
|
|
|
let real_pat = match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) {
|
|
|
|
Some(r) => raw_pat(r[0]),
|
2014-06-07 07:17:01 -05:00
|
|
|
None if v.len() == 0 => return NotUseful,
|
2014-05-13 00:20:52 -05:00
|
|
|
None => v[0]
|
2012-04-24 04:13:25 -05:00
|
|
|
};
|
2014-09-07 12:09:06 -05:00
|
|
|
let left_ty = if real_pat.id == DUMMY_NODE_ID {
|
2014-11-04 06:57:21 -06:00
|
|
|
ty::mk_nil(cx.tcx)
|
2014-06-07 07:17:01 -05:00
|
|
|
} else {
|
|
|
|
ty::pat_ty(cx.tcx, &*real_pat)
|
|
|
|
};
|
|
|
|
|
2014-10-15 01:05:01 -05:00
|
|
|
let max_slice_length = rows.iter().filter_map(|row| match row[0].node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatVec(ref before, _, ref after) => Some(before.len() + after.len()),
|
2014-06-25 12:07:37 -05:00
|
|
|
_ => None
|
|
|
|
}).max().map_or(0, |v| v + 1);
|
|
|
|
|
|
|
|
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
|
|
|
|
if constructors.is_empty() {
|
2014-07-03 15:53:20 -05:00
|
|
|
match missing_constructor(cx, matrix, left_ty, max_slice_length) {
|
2014-06-07 07:17:01 -05:00
|
|
|
None => {
|
2014-09-14 22:27:36 -05:00
|
|
|
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
|
2014-07-03 15:53:20 -05:00
|
|
|
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
|
|
|
|
UsefulWithWitness(pats) => UsefulWithWitness({
|
|
|
|
let arity = constructor_arity(cx, &c, left_ty);
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut result = {
|
2015-02-18 13:48:57 -06:00
|
|
|
let pat_slice = &pats[..];
|
2015-01-26 14:44:22 -06:00
|
|
|
let subpats: Vec<_> = (0..arity).map(|i| {
|
2014-10-10 10:49:12 -05:00
|
|
|
pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p)
|
2014-12-30 12:51:18 -06:00
|
|
|
}).collect();
|
2014-09-07 12:09:06 -05:00
|
|
|
vec![construct_witness(cx, &c, subpats, left_ty)]
|
2014-07-03 15:53:20 -05:00
|
|
|
};
|
2014-09-14 22:27:36 -05:00
|
|
|
result.extend(pats.into_iter().skip(arity));
|
2014-07-03 15:53:20 -05:00
|
|
|
result
|
|
|
|
}),
|
|
|
|
result => result
|
|
|
|
}
|
|
|
|
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
2014-06-07 07:17:01 -05:00
|
|
|
},
|
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
Some(constructor) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
let matrix = rows.iter().filter_map(|r| {
|
|
|
|
if pat_is_binding_or_wild(&cx.tcx.def_map, raw_pat(r[0])) {
|
2014-10-15 01:05:01 -05:00
|
|
|
Some(r.tail().to_vec())
|
2014-09-07 12:09:06 -05:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}).collect();
|
2014-06-19 13:55:12 -05:00
|
|
|
match is_useful(cx, &matrix, v.tail(), witness) {
|
2014-07-03 15:53:20 -05:00
|
|
|
UsefulWithWitness(pats) => {
|
|
|
|
let arity = constructor_arity(cx, &constructor, left_ty);
|
2014-12-30 12:51:18 -06:00
|
|
|
let wild_pats: Vec<_> = repeat(DUMMY_WILD_PAT).take(arity).collect();
|
2014-07-03 15:53:20 -05:00
|
|
|
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut new_pats = vec![enum_pat];
|
2014-09-14 22:27:36 -05:00
|
|
|
new_pats.extend(pats.into_iter());
|
2014-09-07 12:09:06 -05:00
|
|
|
UsefulWithWitness(new_pats)
|
2014-07-03 15:53:20 -05:00
|
|
|
},
|
2014-06-07 07:17:01 -05:00
|
|
|
result => result
|
|
|
|
}
|
2012-05-03 10:35:12 -05:00
|
|
|
}
|
2014-06-25 12:07:37 -05:00
|
|
|
}
|
|
|
|
} else {
|
2014-09-14 22:27:36 -05:00
|
|
|
constructors.into_iter().map(|c|
|
2014-07-03 15:53:20 -05:00
|
|
|
is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness)
|
|
|
|
).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix,
|
2014-09-13 13:09:25 -05:00
|
|
|
v: &[&Pat], ctor: Constructor, lty: Ty,
|
2014-09-07 12:09:06 -05:00
|
|
|
witness: WitnessPreference) -> Usefulness {
|
2014-06-07 07:17:01 -05:00
|
|
|
let arity = constructor_arity(cx, &ctor, lty);
|
2014-06-25 12:07:37 -05:00
|
|
|
let matrix = Matrix(m.iter().filter_map(|r| {
|
2015-02-18 13:48:57 -06:00
|
|
|
specialize(cx, &r[..], &ctor, 0, arity)
|
2014-06-25 12:07:37 -05:00
|
|
|
}).collect());
|
2015-01-25 04:58:43 -06:00
|
|
|
match specialize(cx, v, &ctor, 0, arity) {
|
2015-02-18 13:48:57 -06:00
|
|
|
Some(v) => is_useful(cx, &matrix, &v[..], witness),
|
2014-06-07 07:17:01 -05:00
|
|
|
None => NotUseful
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
/// Determines the constructors that the given pattern can be specialized to.
|
|
|
|
///
|
|
|
|
/// In most cases, there's only one constructor that a specific pattern
|
|
|
|
/// represents, such as a specific enum variant or a specific literal value.
|
|
|
|
/// Slice patterns, however, can match slices of different lengths. For instance,
|
|
|
|
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
|
|
|
|
///
|
|
|
|
/// On the other hand, a wild pattern and an identifier pattern cannot be
|
|
|
|
/// specialized in any way.
|
2014-09-07 12:09:06 -05:00
|
|
|
fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
2014-09-13 13:09:25 -05:00
|
|
|
left_ty: Ty, max_slice_length: uint) -> Vec<Constructor> {
|
2012-04-24 04:13:25 -05:00
|
|
|
let pat = raw_pat(p);
|
2013-03-20 00:17:42 -05:00
|
|
|
match pat.node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(..) =>
|
2015-02-16 22:44:23 -06:00
|
|
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
|
|
|
Some(DefConst(..)) =>
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
|
|
|
been rewritten"),
|
2015-02-16 22:44:23 -06:00
|
|
|
Some(DefStruct(_)) => vec!(Single),
|
|
|
|
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
2014-06-25 12:07:37 -05:00
|
|
|
_ => vec!()
|
2014-06-19 13:55:12 -05:00
|
|
|
},
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatEnum(..) =>
|
2015-02-16 22:44:23 -06:00
|
|
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
|
|
|
Some(DefConst(..)) =>
|
2014-10-11 07:05:16 -05:00
|
|
|
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
been rewritten"),
|
2015-02-16 22:44:23 -06:00
|
|
|
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
2014-06-25 12:07:37 -05:00
|
|
|
_ => vec!(Single)
|
2014-06-19 13:55:12 -05:00
|
|
|
},
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatStruct(..) =>
|
2015-02-16 22:44:23 -06:00
|
|
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
|
|
|
Some(DefConst(..)) =>
|
2014-10-11 07:05:16 -05:00
|
|
|
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
been rewritten"),
|
2015-02-16 22:44:23 -06:00
|
|
|
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
2014-06-25 12:07:37 -05:00
|
|
|
_ => vec!(Single)
|
2014-06-07 07:17:01 -05:00
|
|
|
},
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatLit(ref expr) =>
|
2014-09-07 12:09:06 -05:00
|
|
|
vec!(ConstantValue(eval_const_expr(cx.tcx, &**expr))),
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatRange(ref lo, ref hi) =>
|
2014-09-07 12:09:06 -05:00
|
|
|
vec!(ConstantRange(eval_const_expr(cx.tcx, &**lo), eval_const_expr(cx.tcx, &**hi))),
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatVec(ref before, ref slice, ref after) =>
|
2014-10-31 03:51:16 -05:00
|
|
|
match left_ty.sty {
|
2014-06-25 12:07:37 -05:00
|
|
|
ty::ty_vec(_, Some(_)) => vec!(Single),
|
|
|
|
_ => if slice.is_some() {
|
|
|
|
range_inclusive(before.len() + after.len(), max_slice_length)
|
|
|
|
.map(|length| Slice(length))
|
|
|
|
.collect()
|
|
|
|
} else {
|
|
|
|
vec!(Slice(before.len() + after.len()))
|
|
|
|
}
|
|
|
|
},
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatBox(_) | ast::PatTup(_) | ast::PatRegion(..) =>
|
2014-06-25 12:07:37 -05:00
|
|
|
vec!(Single),
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatWild(_) =>
|
2014-06-25 12:07:37 -05:00
|
|
|
vec!(),
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatMac(_) =>
|
2014-06-07 07:17:01 -05:00
|
|
|
cx.tcx.sess.bug("unexpanded macro")
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
/// This computes the arity of a constructor. The arity of a constructor
|
|
|
|
/// is how many subpattern patterns of that constructor should be expanded to.
|
|
|
|
///
|
2015-01-25 04:58:43 -06:00
|
|
|
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
2014-06-25 12:07:37 -05:00
|
|
|
/// A struct pattern's arity is the number of fields it contains, etc.
|
2014-09-13 13:09:25 -05:00
|
|
|
pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> uint {
|
2014-10-31 03:51:16 -05:00
|
|
|
match ty.sty {
|
2014-04-09 02:15:31 -05:00
|
|
|
ty::ty_tup(ref fs) => fs.len(),
|
2015-01-25 04:58:43 -06:00
|
|
|
ty::ty_uniq(_) => 1,
|
2014-10-31 03:51:16 -05:00
|
|
|
ty::ty_rptr(_, ty::mt { ty, .. }) => match ty.sty {
|
2014-06-07 07:17:01 -05:00
|
|
|
ty::ty_vec(_, None) => match *ctor {
|
2014-06-25 12:07:37 -05:00
|
|
|
Slice(length) => length,
|
2015-01-25 04:58:43 -06:00
|
|
|
ConstantValue(_) => 0,
|
2014-06-25 12:07:37 -05:00
|
|
|
_ => unreachable!()
|
2014-06-07 07:17:01 -05:00
|
|
|
},
|
2015-01-25 04:58:43 -06:00
|
|
|
ty::ty_str => 0,
|
|
|
|
_ => 1
|
2014-04-09 02:15:31 -05:00
|
|
|
},
|
|
|
|
ty::ty_enum(eid, _) => {
|
2014-06-07 07:17:01 -05:00
|
|
|
match *ctor {
|
2014-06-25 12:07:37 -05:00
|
|
|
Variant(id) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
|
2014-06-07 07:17:01 -05:00
|
|
|
_ => unreachable!()
|
2014-04-09 02:15:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
|
2014-06-25 12:07:37 -05:00
|
|
|
ty::ty_vec(_, Some(n)) => n,
|
2015-01-25 04:58:43 -06:00
|
|
|
_ => 0
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
fn range_covered_by_constructor(ctor: &Constructor,
|
2014-07-13 08:12:47 -05:00
|
|
|
from: &const_val, to: &const_val) -> Option<bool> {
|
2014-06-25 12:07:37 -05:00
|
|
|
let (c_from, c_to) = match *ctor {
|
|
|
|
ConstantValue(ref value) => (value, value),
|
|
|
|
ConstantRange(ref from, ref to) => (from, to),
|
|
|
|
Single => return Some(true),
|
|
|
|
_ => unreachable!()
|
2014-06-02 13:49:44 -05:00
|
|
|
};
|
|
|
|
let cmp_from = compare_const_vals(c_from, from);
|
|
|
|
let cmp_to = compare_const_vals(c_to, to);
|
|
|
|
match (cmp_from, cmp_to) {
|
2015-01-29 05:40:14 -06:00
|
|
|
(Some(cmp_from), Some(cmp_to)) => {
|
|
|
|
Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
|
|
|
|
}
|
2014-06-02 13:49:44 -05:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 12:07:37 -05:00
|
|
|
/// This is the main specialization step. It expands the first pattern in the given row
|
|
|
|
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
|
|
|
|
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
|
|
|
|
///
|
|
|
|
/// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple
|
|
|
|
/// different patterns.
|
|
|
|
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
|
|
|
/// fields filled with wild patterns.
|
2014-10-10 10:49:12 -05:00
|
|
|
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
2014-09-07 12:09:06 -05:00
|
|
|
constructor: &Constructor, col: uint, arity: uint) -> Option<Vec<&'a Pat>> {
|
2014-06-07 07:17:01 -05:00
|
|
|
let &Pat {
|
2014-10-05 19:36:53 -05:00
|
|
|
id: pat_id, ref node, span: pat_span
|
2014-09-07 12:09:06 -05:00
|
|
|
} = raw_pat(r[col]);
|
2014-09-13 12:10:34 -05:00
|
|
|
let head: Option<Vec<&Pat>> = match *node {
|
|
|
|
ast::PatWild(_) =>
|
2014-12-30 12:51:18 -06:00
|
|
|
Some(repeat(DUMMY_WILD_PAT).take(arity).collect()),
|
2014-06-25 12:07:37 -05:00
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(_, _, _) => {
|
2015-02-16 22:44:23 -06:00
|
|
|
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
|
2014-06-07 07:17:01 -05:00
|
|
|
match opt_def {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
Some(DefConst(..)) =>
|
|
|
|
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
|
|
|
been rewritten"),
|
2014-06-25 12:07:37 -05:00
|
|
|
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
|
2014-06-21 16:16:31 -05:00
|
|
|
Some(vec!())
|
|
|
|
} else {
|
|
|
|
None
|
2014-06-19 13:55:12 -05:00
|
|
|
},
|
2014-12-30 12:51:18 -06:00
|
|
|
_ => Some(repeat(DUMMY_WILD_PAT).take(arity).collect())
|
2012-11-02 11:56:09 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
2014-06-25 12:07:37 -05:00
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatEnum(_, ref args) => {
|
2015-02-16 22:44:23 -06:00
|
|
|
let def = cx.tcx.def_map.borrow()[pat_id].full_def();
|
2014-06-07 07:17:01 -05:00
|
|
|
match def {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
DefConst(..) =>
|
|
|
|
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
|
|
|
been rewritten"),
|
2014-06-25 12:07:37 -05:00
|
|
|
DefVariant(_, id, _) if *constructor != Variant(id) => None,
|
2014-10-01 16:28:54 -05:00
|
|
|
DefVariant(..) | DefStruct(..) => {
|
2014-06-07 07:17:01 -05:00
|
|
|
Some(match args {
|
2014-09-07 12:09:06 -05:00
|
|
|
&Some(ref args) => args.iter().map(|p| &**p).collect(),
|
2014-12-30 12:51:18 -06:00
|
|
|
&None => repeat(DUMMY_WILD_PAT).take(arity).collect(),
|
2014-06-07 07:17:01 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => None
|
2012-08-06 19:01:14 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatStruct(_, ref pattern_fields, _) => {
|
2014-06-07 07:17:01 -05:00
|
|
|
// Is this a struct or an enum variant?
|
2015-02-16 22:44:23 -06:00
|
|
|
let def = cx.tcx.def_map.borrow()[pat_id].full_def();
|
2014-06-07 07:17:01 -05:00
|
|
|
let class_id = match def {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
DefConst(..) =>
|
|
|
|
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
|
|
|
been rewritten"),
|
2014-06-25 12:07:37 -05:00
|
|
|
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
|
2014-06-07 07:17:01 -05:00
|
|
|
Some(variant_id)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2014-07-04 18:45:47 -05:00
|
|
|
_ => {
|
|
|
|
// Assume this is a struct.
|
|
|
|
match ty::ty_to_def_id(node_id_to_type(cx.tcx, pat_id)) {
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_bug(pat_span,
|
|
|
|
"struct pattern wasn't of a \
|
|
|
|
type with a def ID?!")
|
|
|
|
}
|
|
|
|
Some(def_id) => Some(def_id),
|
|
|
|
}
|
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
};
|
|
|
|
class_id.map(|variant_id| {
|
|
|
|
let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
|
|
|
|
let args = struct_fields.iter().map(|sf| {
|
2014-10-05 19:36:53 -05:00
|
|
|
match pattern_fields.iter().find(|f| f.node.ident.name == sf.name) {
|
|
|
|
Some(ref f) => &*f.node.pat,
|
2014-10-10 10:49:12 -05:00
|
|
|
_ => DUMMY_WILD_PAT
|
2012-10-24 20:47:59 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
}).collect();
|
|
|
|
args
|
|
|
|
})
|
|
|
|
}
|
2014-06-02 10:18:23 -05:00
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatTup(ref args) =>
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(args.iter().map(|p| &**p).collect()),
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-12-05 17:56:25 -06:00
|
|
|
ast::PatBox(ref inner) | ast::PatRegion(ref inner, _) =>
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(vec![&**inner]),
|
2014-06-07 07:17:01 -05:00
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatLit(ref expr) => {
|
2014-06-07 07:17:01 -05:00
|
|
|
let expr_value = eval_const_expr(cx.tcx, &**expr);
|
2014-06-25 12:07:37 -05:00
|
|
|
match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(true) => Some(vec![]),
|
2014-06-07 07:17:01 -05:00
|
|
|
Some(false) => None,
|
|
|
|
None => {
|
2015-01-18 18:58:25 -06:00
|
|
|
span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
|
2014-03-08 14:36:22 -06:00
|
|
|
None
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
2012-08-06 19:01:14 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatRange(ref from, ref to) => {
|
2014-06-07 07:17:01 -05:00
|
|
|
let from_value = eval_const_expr(cx.tcx, &**from);
|
|
|
|
let to_value = eval_const_expr(cx.tcx, &**to);
|
2014-06-25 12:07:37 -05:00
|
|
|
match range_covered_by_constructor(constructor, &from_value, &to_value) {
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(true) => Some(vec![]),
|
2014-06-07 07:17:01 -05:00
|
|
|
Some(false) => None,
|
|
|
|
None => {
|
2015-01-18 18:58:25 -06:00
|
|
|
span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
|
2014-06-02 13:49:44 -05:00
|
|
|
None
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
2013-05-21 04:04:55 -05:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatVec(ref before, ref slice, ref after) => {
|
2014-06-25 12:07:37 -05:00
|
|
|
match *constructor {
|
|
|
|
// Fixed-length vectors.
|
|
|
|
Single => {
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
2014-12-30 12:51:18 -06:00
|
|
|
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len()));
|
2014-09-07 12:09:06 -05:00
|
|
|
pats.extend(after.iter().map(|p| &**p));
|
2014-06-25 12:07:37 -05:00
|
|
|
Some(pats)
|
|
|
|
},
|
|
|
|
Slice(length) if before.len() + after.len() <= length && slice.is_some() => {
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
2014-12-30 12:51:18 -06:00
|
|
|
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len()));
|
2014-09-07 12:09:06 -05:00
|
|
|
pats.extend(after.iter().map(|p| &**p));
|
2014-06-25 12:07:37 -05:00
|
|
|
Some(pats)
|
|
|
|
},
|
|
|
|
Slice(length) if before.len() + after.len() == length => {
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
|
|
|
pats.extend(after.iter().map(|p| &**p));
|
2014-06-25 12:07:37 -05:00
|
|
|
Some(pats)
|
|
|
|
},
|
2014-08-30 09:22:19 -05:00
|
|
|
SliceWithSubslice(prefix, suffix)
|
|
|
|
if before.len() == prefix
|
|
|
|
&& after.len() == suffix
|
|
|
|
&& slice.is_some() => {
|
2014-09-07 12:09:06 -05:00
|
|
|
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
|
|
|
pats.extend(after.iter().map(|p| &**p));
|
2014-08-30 09:22:19 -05:00
|
|
|
Some(pats)
|
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
_ => None
|
2012-12-08 14:22:43 -06:00
|
|
|
}
|
2014-06-07 07:17:01 -05:00
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatMac(_) => {
|
2015-01-18 18:58:25 -06:00
|
|
|
span_err!(cx.tcx.sess, pat_span, E0300, "unexpanded macro");
|
2014-06-07 07:17:01 -05:00
|
|
|
None
|
|
|
|
}
|
2014-06-02 10:18:23 -05:00
|
|
|
};
|
2014-10-15 01:05:01 -05:00
|
|
|
head.map(|mut head| {
|
2015-01-12 15:59:18 -06:00
|
|
|
head.push_all(&r[..col]);
|
2015-01-19 10:07:13 -06:00
|
|
|
head.push_all(&r[col + 1..]);
|
2014-10-15 01:05:01 -05:00
|
|
|
head
|
|
|
|
})
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
|
2014-09-13 12:10:34 -05:00
|
|
|
fn check_local(cx: &mut MatchCheckCtxt, loc: &ast::Local) {
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_local(cx, loc);
|
2014-05-26 07:01:09 -05:00
|
|
|
|
2014-05-26 07:42:48 -05:00
|
|
|
let name = match loc.source {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::LocalLet => "local",
|
|
|
|
ast::LocalFor => "`for` loop"
|
2014-05-26 07:42:48 -05:00
|
|
|
};
|
|
|
|
|
2015-02-05 11:26:58 -06:00
|
|
|
let mut static_inliner = StaticInliner::new(cx.tcx, None);
|
2014-09-07 12:09:06 -05:00
|
|
|
is_refutable(cx, &*static_inliner.fold_pat(loc.pat.clone()), |pat| {
|
|
|
|
span_err!(cx.tcx.sess, loc.pat.span, E0005,
|
|
|
|
"refutable pattern in {} binding: `{}` not covered",
|
|
|
|
name, pat_to_string(pat)
|
|
|
|
);
|
|
|
|
});
|
2012-12-05 21:01:14 -06:00
|
|
|
|
2014-07-28 13:33:06 -05:00
|
|
|
// Check legality of move bindings and `@` patterns.
|
2014-09-07 12:09:06 -05:00
|
|
|
check_legality_of_move_bindings(cx, false, slice::ref_slice(&loc.pat));
|
2014-07-28 13:33:06 -05:00
|
|
|
check_legality_of_bindings_in_at_patterns(cx, &*loc.pat);
|
2011-08-01 08:26:48 -05:00
|
|
|
}
|
|
|
|
|
2014-03-05 21:07:47 -06:00
|
|
|
fn check_fn(cx: &mut MatchCheckCtxt,
|
2014-09-09 17:54:36 -05:00
|
|
|
kind: FnKind,
|
2014-09-13 12:10:34 -05:00
|
|
|
decl: &ast::FnDecl,
|
|
|
|
body: &ast::Block,
|
2014-11-15 16:26:15 -06:00
|
|
|
sp: Span,
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
fn_id: NodeId) {
|
|
|
|
match kind {
|
|
|
|
visit::FkFnBlock => {}
|
|
|
|
_ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id),
|
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_fn(cx, kind, decl, body, sp);
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
|
2015-01-31 11:20:46 -06:00
|
|
|
for input in &decl.inputs {
|
2014-09-07 12:09:06 -05:00
|
|
|
is_refutable(cx, &*input.pat, |pat| {
|
|
|
|
span_err!(cx.tcx.sess, input.pat.span, E0006,
|
|
|
|
"refutable pattern in function argument: `{}` not covered",
|
|
|
|
pat_to_string(pat)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
check_legality_of_move_bindings(cx, false, slice::ref_slice(&input.pat));
|
2014-07-28 13:33:06 -05:00
|
|
|
check_legality_of_bindings_in_at_patterns(cx, &*input.pat);
|
2012-11-06 20:41:06 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-08 19:26:43 -06:00
|
|
|
fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A> where
|
|
|
|
F: FnOnce(&Pat) -> A,
|
|
|
|
{
|
2014-06-25 12:07:37 -05:00
|
|
|
let pats = Matrix(vec!(vec!(pat)));
|
2014-11-17 02:39:01 -06:00
|
|
|
match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) {
|
2014-07-03 15:53:20 -05:00
|
|
|
UsefulWithWitness(pats) => {
|
2014-05-31 08:13:46 -05:00
|
|
|
assert_eq!(pats.len(), 1);
|
2014-09-07 12:09:06 -05:00
|
|
|
Some(refutable(&*pats[0]))
|
2014-07-03 15:53:20 -05:00
|
|
|
},
|
|
|
|
NotUseful => None,
|
|
|
|
Useful => unreachable!()
|
|
|
|
}
|
2011-08-01 08:26:48 -05:00
|
|
|
}
|
|
|
|
|
2012-12-05 21:01:14 -06:00
|
|
|
// Legality of move bindings checking
|
2013-10-06 14:27:36 -05:00
|
|
|
fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
|
2014-04-21 18:21:53 -05:00
|
|
|
has_guard: bool,
|
2014-09-07 12:09:06 -05:00
|
|
|
pats: &[P<Pat>]) {
|
2012-12-05 21:01:14 -06:00
|
|
|
let tcx = cx.tcx;
|
2014-04-22 11:06:43 -05:00
|
|
|
let def_map = &tcx.def_map;
|
2012-12-05 21:01:14 -06:00
|
|
|
let mut by_ref_span = None;
|
2015-01-31 11:20:46 -06:00
|
|
|
for pat in pats {
|
2014-05-16 12:15:33 -05:00
|
|
|
pat_bindings(def_map, &**pat, |bm, _, span, _path| {
|
2012-12-05 21:01:14 -06:00
|
|
|
match bm {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::BindByRef(_) => {
|
2012-12-05 21:01:14 -06:00
|
|
|
by_ref_span = Some(span);
|
|
|
|
}
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::BindByValue(_) => {
|
2012-12-07 21:34:57 -06:00
|
|
|
}
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
2013-11-21 17:42:55 -06:00
|
|
|
})
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
|
2015-02-01 11:44:15 -06:00
|
|
|
let check_move = |p: &Pat, sub: Option<&Pat>| {
|
2012-12-14 19:50:48 -06:00
|
|
|
// check legality of moving out of the enum
|
2013-08-14 04:04:41 -05:00
|
|
|
|
2013-11-28 14:22:53 -06:00
|
|
|
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
|
2014-05-16 12:15:33 -05:00
|
|
|
if sub.map_or(false, |p| pat_contains_bindings(def_map, &*p)) {
|
2014-07-11 11:54:01 -05:00
|
|
|
span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings");
|
2012-12-14 19:50:48 -06:00
|
|
|
} else if has_guard {
|
2014-07-11 11:54:01 -05:00
|
|
|
span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
|
2012-12-14 19:50:48 -06:00
|
|
|
} else if by_ref_span.is_some() {
|
2014-07-11 11:54:01 -05:00
|
|
|
span_err!(cx.tcx.sess, p.span, E0009,
|
|
|
|
"cannot bind by-move and by-ref in the same pattern");
|
|
|
|
span_note!(cx.tcx.sess, by_ref_span.unwrap(), "by-ref binding occurs here");
|
2012-12-14 19:50:48 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-01-31 11:20:46 -06:00
|
|
|
for pat in pats {
|
2015-02-05 11:26:58 -06:00
|
|
|
ast_util::walk_pat(&**pat, |p| {
|
2014-05-16 12:15:33 -05:00
|
|
|
if pat_is_binding(def_map, &*p) {
|
2012-12-05 21:01:14 -06:00
|
|
|
match p.node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(ast::BindByValue(_), _, ref sub) => {
|
2014-04-21 18:21:53 -05:00
|
|
|
let pat_ty = ty::node_id_to_type(tcx, p.id);
|
2015-01-02 03:01:30 -06:00
|
|
|
if ty::type_moves_by_default(&cx.param_env, pat.span, pat_ty) {
|
2014-09-07 12:09:06 -05:00
|
|
|
check_move(p, sub.as_ref().map(|p| &**p));
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(ast::BindByRef(_), _, _) => {
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_bug(
|
|
|
|
p.span,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("binding pattern {} is not an \
|
2014-12-20 02:09:35 -06:00
|
|
|
identifier: {:?}",
|
2014-05-16 12:45:16 -05:00
|
|
|
p.id,
|
2015-02-20 13:08:14 -06:00
|
|
|
p.node));
|
2013-01-10 12:59:58 -06:00
|
|
|
}
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
2013-08-02 01:17:20 -05:00
|
|
|
true
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
|
|
|
|
/// Ensures that a pattern guard doesn't borrow by mutable reference or
|
|
|
|
/// assign.
|
2014-09-13 12:10:34 -05:00
|
|
|
fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
|
|
|
|
guard: &ast::Expr) {
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
let mut checker = MutationChecker {
|
|
|
|
cx: cx,
|
|
|
|
};
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
let mut visitor = ExprUseVisitor::new(&mut checker,
|
2015-01-02 03:09:35 -06:00
|
|
|
&checker.cx.param_env);
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
visitor.walk_expr(guard);
|
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
struct MutationChecker<'a, 'tcx: 'a> {
|
|
|
|
cx: &'a MatchCheckCtxt<'a, 'tcx>,
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
|
2014-09-16 08:24:56 -05:00
|
|
|
fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
fn consume(&mut self, _: NodeId, _: Span, _: cmt, _: ConsumeMode) {}
|
|
|
|
fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
|
|
|
|
fn borrow(&mut self,
|
|
|
|
_: NodeId,
|
|
|
|
span: Span,
|
|
|
|
_: cmt,
|
|
|
|
_: Region,
|
|
|
|
kind: BorrowKind,
|
|
|
|
_: LoanCause) {
|
|
|
|
match kind {
|
|
|
|
MutBorrow => {
|
2015-01-18 18:58:25 -06:00
|
|
|
span_err!(self.cx.tcx.sess, span, E0301,
|
|
|
|
"cannot mutably borrow in a pattern guard")
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
}
|
|
|
|
ImmBorrow | UniqueImmBorrow => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn decl_without_init(&mut self, _: NodeId, _: Span) {}
|
|
|
|
fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) {
|
|
|
|
match mode {
|
|
|
|
JustWrite | WriteAndRead => {
|
2015-01-18 18:58:25 -06:00
|
|
|
span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
}
|
|
|
|
Init => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-28 13:33:06 -05:00
|
|
|
/// Forbids bindings in `@` patterns. This is necessary for memory safety,
|
|
|
|
/// because of the way rvalues are handled in the borrow check. (See issue
|
|
|
|
/// #14587.)
|
|
|
|
fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) {
|
2014-09-12 05:10:30 -05:00
|
|
|
AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat);
|
2014-07-28 13:33:06 -05:00
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
|
|
|
|
cx: &'a MatchCheckCtxt<'b, 'tcx>,
|
2014-09-12 05:10:30 -05:00
|
|
|
bindings_allowed: bool
|
2014-07-28 13:33:06 -05:00
|
|
|
}
|
|
|
|
|
2014-09-09 17:54:36 -05:00
|
|
|
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_pat(&mut self, pat: &Pat) {
|
|
|
|
if !self.bindings_allowed && pat_is_binding(&self.cx.tcx.def_map, pat) {
|
2015-01-18 18:58:25 -06:00
|
|
|
span_err!(self.cx.tcx.sess, pat.span, E0303,
|
2014-07-28 13:33:06 -05:00
|
|
|
"pattern bindings are not allowed \
|
|
|
|
after an `@`");
|
|
|
|
}
|
|
|
|
|
|
|
|
match pat.node {
|
2014-09-13 12:10:34 -05:00
|
|
|
ast::PatIdent(_, _, Some(_)) => {
|
2014-09-12 05:10:30 -05:00
|
|
|
let bindings_were_allowed = self.bindings_allowed;
|
|
|
|
self.bindings_allowed = false;
|
|
|
|
visit::walk_pat(self, pat);
|
|
|
|
self.bindings_allowed = bindings_were_allowed;
|
|
|
|
}
|
|
|
|
_ => visit::walk_pat(self, pat),
|
2014-07-28 13:33:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|