未验证 提交 e97089da 编写于 作者: O Oliver Schneider 提交者: Oliver Schneider

Move librustc_const_eval to librustc_mir

上级 918b6d76
......@@ -64,7 +64,6 @@ for details on how to format and write long error codes.
[librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs),
[libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs),
[librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs),
[librustc_const_eval](https://github.com/rust-lang/rust/blob/master/src/librustc_const_eval/diagnostics.rs),
[librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs),
[librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs),
[librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs),
......
......@@ -63,7 +63,6 @@
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
use mir;
use ich::Fingerprint;
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
......
......@@ -13,7 +13,6 @@
use ty::{self, Ty, TyCtxt};
use ty::maps::queries;
use ty::subst::Substs;
use mir;
use std::hash::Hash;
use syntax_pos::symbol::InternedString;
......
[package]
authors = ["The Rust Project Developers"]
name = "rustc_const_eval"
version = "0.0.0"
[lib]
name = "rustc_const_eval"
path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
arena = { path = "../libarena" }
log = "0.4"
rustc = { path = "../librustc" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// 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.
#![allow(non_snake_case)]
// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {
E0001: r##"
#### Note: this error code is no longer emitted by the compiler.
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.
This means that perhaps some of the preceding patterns are too general, this
one is too specific or the ordering is incorrect.
For example, the following `match` block has too many arms:
```
match Some(0) {
Some(bar) => {/* ... */}
x => {/* ... */} // This handles the `None` case
_ => {/* ... */} // All possible cases have already been handled
}
```
`match` blocks have their patterns matched in order, so, for example, putting
a wildcard arm above a more specific arm will make the latter arm irrelevant.
Ensure the ordering of the match arm is correct and remove any superfluous
arms.
"##,
E0002: r##"
#### Note: this error code is no longer emitted by the compiler.
This error indicates that an empty match expression is invalid because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired. This error is typically fixed by adding
one or more cases to the match expression.
An example of an empty type is `enum Empty { }`. So, the following will work:
```
enum Empty {}
fn foo(x: Empty) {
match x {
// empty
}
}
```
However, this won't:
```compile_fail
fn foo(x: Option<String>) {
match x {
// empty
}
}
```
"##,
E0003: r##"
#### Note: this error code is no longer emitted by the compiler.
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. So, the following will not compile:
```compile_fail
const NAN: f32 = 0.0 / 0.0;
let number = 0.1f32;
match number {
NAN => { /* ... */ },
_ => {}
}
```
To match against NaN values, you should instead use the `is_nan()` method in a
guard, like so:
```
let number = 0.1f32;
match number {
x if x.is_nan() => { /* ... */ }
_ => {}
}
```
"##,
E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
```compile_fail,E0004
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
Terminator::TalkToMyHand => {}
}
```
If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else". Example:
```
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x {
Terminator::TalkToMyHand => {}
Terminator::HastaLaVistaBaby => {}
}
// or:
match x {
Terminator::TalkToMyHand => {}
_ => {}
}
```
"##,
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
```compile_fail,E0005
let x = Some(1);
let Some(y) = x;
// error: refutable pattern in local binding: `None` not covered
```
If you encounter this error you probably need to use a `match` or `if let` to
deal with the possibility of failure. Example:
```
let x = Some(1);
match x {
Some(y) => {
// do something
},
None => {}
}
// or:
if let Some(y) = x {
// do something
}
```
"##,
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code
like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
```compile_fail,E0007
let x = Some("s".to_string());
match x {
op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
None => {},
}
```
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail,E0008
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore becomes unavailable in the body of the arm.
The problem above can be solved by using the `ref` keyword.
```
match Some("hi".to_string()) {
Some(ref s) if s.len() == 0 => {},
_ => {},
}
```
Though this example seems innocuous and easy to solve, the problem becomes clear
when it encounters functions which consume the value:
```compile_fail,E0008
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a {
Some(y) if y.consume() > 0 => {}
_ => {}
}
}
```
In this situation, even the `ref` keyword cannot solve it, since borrowed
content cannot be moved. This problem cannot be solved generally. If the value
can be cloned, here is a not-so-specific solution:
```
#[derive(Clone)]
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a{
Some(ref y) if y.clone().consume() > 0 => {}
_ => {}
}
}
```
If the value will be consumed in the pattern guard, using its clone will not
move its ownership, so the code works.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
by-ref.
This limitation may be removed in a future version of Rust.
Erroneous code example:
```compile_fail,E0009
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
// same pattern
None => panic!()
}
```
You have two solutions:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((ref y, ref z)) => {},
// or Some((y, z)) => {}
None => panic!()
}
```
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
"##,
E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.
If you want to match against a `static`, consider using a guard instead:
```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => {}
_ => {}
}
```
"##,
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail,E0162
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
// This body will always be executed.
// ...
}
```
Try this instead:
```
struct Irrefutable(i32);
let irr = Irrefutable(0);
let Irrefutable(x) = irr;
println!("{}", x);
```
"##,
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail,E0165
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
// ...
}
```
Try this instead:
```no_run
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
// ...
}
```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
```
enum Method {
GET,
POST,
}
```
You would match it using:
```
enum Method {
GET,
POST,
}
let m = Method::GET;
match m {
Method::GET => {},
Method::POST => {},
}
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
```
use Method::*;
enum Method { GET, POST }
# fn main() {}
```
If you want others to be able to import variants from your module directly, use
`pub use`:
```
pub use Method::*;
pub enum Method { GET, POST }
# fn main() {}
```
"##,
E0297: r##"
#### Note: this error code is no longer emitted by the compiler.
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
```compile_fail,E0005
let xs : Vec<Option<i32>> = vec![Some(1), None];
// This fails because `None` is not covered.
for Some(x) in xs {
// ...
}
```
Match inside the loop instead:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
match item {
Some(x) => {},
None => {},
}
}
```
Or use `if let`:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
if let Some(x) = item {
// ...
}
}
```
"##,
E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail,E0301
match Some(()) {
None => { },
option if option.take().is_none() => {
/* impossible, option is `Some` */
},
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail,E0302
match Some(()) {
None => { },
option if { option = None; false } => { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
Before:
```compile_fail,E0303
match Some("hi".to_string()) {
ref op_string_ref @ Some(s) => {},
None => {},
}
```
After:
```
match Some("hi".to_string()) {
Some(ref s) => {
let op_string_ref = &Some(s);
// ...
},
None => {},
}
```
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
}
register_diagnostics! {
// E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)
}
......@@ -17,7 +17,6 @@ rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" }
rustc_back = { path = "../librustc_back" }
rustc_borrowck = { path = "../librustc_borrowck" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
rustc_incremental = { path = "../librustc_incremental" }
......
......@@ -37,7 +37,7 @@
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
use rustc_passes::{self, ast_validation, loops, consts, hir_stats};
use rustc_const_eval::{self, check_match};
use rustc_mir::const_eval::check_match;
use super::Compilation;
use serialize::json;
......@@ -942,7 +942,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
ty::provide(providers);
traits::provide(providers);
reachable::provide(providers);
rustc_const_eval::provide(providers);
rustc_passes::provide(providers);
middle::region::provide(providers);
cstore::provide(providers);
......
......@@ -35,7 +35,6 @@
extern crate rustc_allocator;
extern crate rustc_back;
extern crate rustc_borrowck;
extern crate rustc_const_eval;
extern crate rustc_data_structures;
extern crate rustc_errors as errors;
extern crate rustc_passes;
......@@ -1566,7 +1565,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
// FIXME: need to figure out a way to get these back in here
// all_errors.extend_from_slice(get_trans(sess).diagnostics());
all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
......
......@@ -12,6 +12,6 @@ test = false
[dependencies]
log = "0.4"
rustc = { path = "../librustc" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_mir = { path = "../librustc_mir"}
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
......@@ -39,7 +39,7 @@
extern crate rustc;
#[macro_use]
extern crate log;
extern crate rustc_const_eval;
extern crate rustc_mir;
extern crate syntax_pos;
use rustc::lint;
......
......@@ -15,7 +15,7 @@
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::layout::{self, LayoutOf};
use middle::const_val::ConstVal;
use rustc_const_eval::ConstContext;
use rustc_mir::const_eval::ConstContext;
use rustc::mir::interpret::{Value, PrimVal};
use util::nodemap::FxHashSet;
use lint::{LateContext, LintContext, LintArray};
......
......@@ -9,13 +9,13 @@ path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
arena = { path = "../libarena" }
bitflags = "1.0"
graphviz = { path = "../libgraphviz" }
log = "0.4"
log_settings = "0.1.1"
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
......
......@@ -21,7 +21,7 @@
use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap;
use rustc_back::PanicStrategy;
use rustc_const_eval::pattern::{BindingMode, PatternKind};
use const_eval::pattern::{BindingMode, PatternKind};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use shim;
use std::mem;
......
......@@ -13,15 +13,15 @@
use self::WitnessPreference::*;
use rustc::middle::const_val::ConstVal;
use eval::{compare_const_vals};
use const_eval::eval::{compare_const_vals};
use rustc_const_math::ConstInt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use pattern::{FieldPattern, Pattern, PatternKind};
use pattern::{PatternFoldable, PatternFolder};
use const_eval::pattern::{FieldPattern, Pattern, PatternKind};
use const_eval::pattern::{PatternFoldable, PatternFolder};
use rustc::hir::def_id::DefId;
use rustc::hir::RangeEnd;
......
......@@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
use _match::Usefulness::*;
use _match::WitnessPreference::*;
use const_eval::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
use const_eval::_match::Usefulness::*;
use const_eval::_match::WitnessPreference::*;
use pattern::{Pattern, PatternContext, PatternError, PatternKind};
use const_eval::pattern::{Pattern, PatternContext, PatternError, PatternKind};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
......
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// 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.
//! constant evaluation on the HIR and code to validate patterns/matches
mod eval;
mod _match;
pub mod check_match;
pub mod pattern;
pub use self::eval::*;
......@@ -8,7 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use eval;
use const_eval::eval;
use interpret::{const_val_field, const_discr};
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate};
use rustc::mir::{Field, BorrowKind, Mutability};
......@@ -693,7 +694,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
return match expr.node {
hir::ExprLit(ref lit) => {
let ty = self.tables.expr_ty(expr);
match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) {
match super::eval::lit_to_const(&lit.node, self.tcx, ty, false) {
Ok(value) => PatternKind::Constant {
value: self.tcx.mk_const(ty::Const {
ty,
......@@ -716,7 +717,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
hir::ExprLit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) {
match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) {
Ok(value) => PatternKind::Constant {
value: self.tcx.mk_const(ty::Const {
ty,
......@@ -782,9 +783,9 @@ fn const_to_pat(
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
match cv.val {
ConstVal::Value(val) => {
let discr = self.tcx.const_discr(self.param_env.and((
instance, val, cv.ty
))).unwrap();
let discr = const_discr(
self.tcx, self.param_env, instance, val, cv.ty
).unwrap();
let variant_index = adt_def
.discriminants(self.tcx)
.position(|var| var.to_u128_unchecked() == discr)
......@@ -801,8 +802,8 @@ fn const_to_pat(
.map(|(i, _)| {
let field = Field::new(i);
let val = match cv.val {
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
ConstVal::Value(miri) => const_val_field(
self.tcx, self.param_env, instance, field, miri, cv.ty,
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
......@@ -844,8 +845,8 @@ fn const_to_pat(
ConstVal::Aggregate(ConstAggregate::Struct(consts)) => {
consts.iter().find(|&&(name, _)| name == f.name).unwrap().1
},
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
ConstVal::Value(miri) => const_val_field(
self.tcx, self.param_env, instance, field, miri, cv.ty,
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
......@@ -862,8 +863,8 @@ fn const_to_pat(
let field = Field::new(i);
let val = match cv.val {
ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i],
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
ConstVal::Value(miri) => const_val_field(
self.tcx, self.param_env, instance, field, miri, cv.ty,
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
......@@ -882,8 +883,8 @@ fn const_to_pat(
let val = match cv.val {
ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i],
ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv,
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
ConstVal::Value(miri) => const_val_field(
self.tcx, self.param_env, instance, field, miri, cv.ty,
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
......
......@@ -12,6 +12,553 @@
register_long_diagnostics! {
E0001: r##"
#### Note: this error code is no longer emitted by the compiler.
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.
This means that perhaps some of the preceding patterns are too general, this
one is too specific or the ordering is incorrect.
For example, the following `match` block has too many arms:
```
match Some(0) {
Some(bar) => {/* ... */}
x => {/* ... */} // This handles the `None` case
_ => {/* ... */} // All possible cases have already been handled
}
```
`match` blocks have their patterns matched in order, so, for example, putting
a wildcard arm above a more specific arm will make the latter arm irrelevant.
Ensure the ordering of the match arm is correct and remove any superfluous
arms.
"##,
E0002: r##"
#### Note: this error code is no longer emitted by the compiler.
This error indicates that an empty match expression is invalid because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired. This error is typically fixed by adding
one or more cases to the match expression.
An example of an empty type is `enum Empty { }`. So, the following will work:
```
enum Empty {}
fn foo(x: Empty) {
match x {
// empty
}
}
```
However, this won't:
```compile_fail
fn foo(x: Option<String>) {
match x {
// empty
}
}
```
"##,
E0003: r##"
#### Note: this error code is no longer emitted by the compiler.
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. So, the following will not compile:
```compile_fail
const NAN: f32 = 0.0 / 0.0;
let number = 0.1f32;
match number {
NAN => { /* ... */ },
_ => {}
}
```
To match against NaN values, you should instead use the `is_nan()` method in a
guard, like so:
```
let number = 0.1f32;
match number {
x if x.is_nan() => { /* ... */ }
_ => {}
}
```
"##,
E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
```compile_fail,E0004
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
Terminator::TalkToMyHand => {}
}
```
If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else". Example:
```
enum Terminator {
HastaLaVistaBaby,
TalkToMyHand,
}
let x = Terminator::HastaLaVistaBaby;
match x {
Terminator::TalkToMyHand => {}
Terminator::HastaLaVistaBaby => {}
}
// or:
match x {
Terminator::TalkToMyHand => {}
_ => {}
}
```
"##,
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
```compile_fail,E0005
let x = Some(1);
let Some(y) = x;
// error: refutable pattern in local binding: `None` not covered
```
If you encounter this error you probably need to use a `match` or `if let` to
deal with the possibility of failure. Example:
```
let x = Some(1);
match x {
Some(y) => {
// do something
},
None => {}
}
// or:
if let Some(y) = x {
// do something
}
```
"##,
E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code
like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
```compile_fail,E0007
let x = Some("s".to_string());
match x {
op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
None => {},
}
```
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail,E0008
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore becomes unavailable in the body of the arm.
The problem above can be solved by using the `ref` keyword.
```
match Some("hi".to_string()) {
Some(ref s) if s.len() == 0 => {},
_ => {},
}
```
Though this example seems innocuous and easy to solve, the problem becomes clear
when it encounters functions which consume the value:
```compile_fail,E0008
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a {
Some(y) if y.consume() > 0 => {}
_ => {}
}
}
```
In this situation, even the `ref` keyword cannot solve it, since borrowed
content cannot be moved. This problem cannot be solved generally. If the value
can be cloned, here is a not-so-specific solution:
```
#[derive(Clone)]
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a{
Some(ref y) if y.clone().consume() > 0 => {}
_ => {}
}
}
```
If the value will be consumed in the pattern guard, using its clone will not
move its ownership, so the code works.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
by-ref.
This limitation may be removed in a future version of Rust.
Erroneous code example:
```compile_fail,E0009
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
// same pattern
None => panic!()
}
```
You have two solutions:
Solution #1: Bind the pattern's values the same way.
```
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((ref y, ref z)) => {},
// or Some((y, z)) => {}
None => panic!()
}
```
Solution #2: Implement the `Copy` trait for the `X` structure.
However, please keep in mind that the first solution should be preferred.
```
#[derive(Clone, Copy)]
struct X { x: (), }
let x = Some((X { x: () }, X { x: () }));
match x {
Some((y, ref z)) => {},
None => panic!()
}
```
"##,
E0158: r##"
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
The `static` keyword, on the other hand, guarantees a fixed location in memory.
This does not always mean that the value is constant. For example, a global
mutex can be declared `static` as well.
If you want to match against a `static`, consider using a guard instead:
```
static FORTY_TWO: i32 = 42;
match Some(42) {
Some(x) if x == FORTY_TWO => {}
_ => {}
}
```
"##,
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail,E0162
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
// This body will always be executed.
// ...
}
```
Try this instead:
```
struct Irrefutable(i32);
let irr = Irrefutable(0);
let Irrefutable(x) = irr;
println!("{}", x);
```
"##,
E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail,E0165
struct Irrefutable(i32);
let irr = Irrefutable(0);
// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
// ...
}
```
Try this instead:
```no_run
struct Irrefutable(i32);
let irr = Irrefutable(0);
loop {
let Irrefutable(x) = irr;
// ...
}
```
"##,
E0170: r##"
Enum variants are qualified by default. For example, given this type:
```
enum Method {
GET,
POST,
}
```
You would match it using:
```
enum Method {
GET,
POST,
}
let m = Method::GET;
match m {
Method::GET => {},
Method::POST => {},
}
```
If you don't qualify the names, the code will bind new variables named "GET" and
"POST" instead. This behavior is likely not what you want, so `rustc` warns when
that happens.
Qualified names are good practice, and most code works well with them. But if
you prefer them unqualified, you can import the variants into scope:
```
use Method::*;
enum Method { GET, POST }
# fn main() {}
```
If you want others to be able to import variants from your module directly, use
`pub use`:
```
pub use Method::*;
pub enum Method { GET, POST }
# fn main() {}
```
"##,
E0297: r##"
#### Note: this error code is no longer emitted by the compiler.
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:
```compile_fail,E0005
let xs : Vec<Option<i32>> = vec![Some(1), None];
// This fails because `None` is not covered.
for Some(x) in xs {
// ...
}
```
Match inside the loop instead:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
match item {
Some(x) => {},
None => {},
}
}
```
Or use `if let`:
```
let xs : Vec<Option<i32>> = vec![Some(1), None];
for item in xs {
if let Some(x) = item {
// ...
}
}
```
"##,
E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail,E0301
match Some(()) {
None => { },
option if option.take().is_none() => {
/* impossible, option is `Some` */
},
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail,E0302
match Some(()) {
None => { },
option if { option = None; false } => { },
Some(_) => { } // When the previous match failed, the option became `None`.
}
```
"##,
E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.
Before:
```compile_fail,E0303
match Some("hi".to_string()) {
ref op_string_ref @ Some(s) => {},
None => {},
}
```
After:
```
match Some("hi".to_string()) {
Some(ref s) => {
let op_string_ref = &Some(s);
// ...
},
None => {},
}
```
The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
E0010: r##"
The value of statics and constants must be known at compile time, and they live
for the entire lifetime of a program. Creating a boxed value allocates memory on
......@@ -1771,6 +2318,9 @@ struct Foo<'a> {
}
register_diagnostics! {
// E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)
// E0385, // {} in an aliasable location
E0493, // destructors cannot be evaluated at compile-time
E0524, // two closures require unique access to `..` at the same time
......
......@@ -27,7 +27,7 @@
pub mod cx;
pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
pub use const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
#[derive(Copy, Clone, Debug)]
pub enum LintLevel {
......
......@@ -5,7 +5,7 @@
use rustc::mir;
use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use rustc_const_eval::{lookup_const_by_id, ConstContext};
use const_eval::{lookup_const_by_id, ConstContext};
use rustc::mir::Field;
use rustc_data_structures::indexed_vec::Idx;
......@@ -306,16 +306,19 @@ fn global_item_with_linkage<'a>(
pub fn const_val_field<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
field: mir::Field,
val: Value,
ty: Ty<'tcx>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const_val_field: {:#?}", key);
match const_val_field_inner(tcx, key) {
match const_val_field_inner(tcx, param_env, instance, field, val, ty) {
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(field),
ty,
})),
Err(err) => Err(ConstEvalErr {
span: tcx.def_span(key.value.0.def_id()),
span: tcx.def_span(instance.def_id()),
kind: err.into(),
}),
}
......@@ -323,11 +326,14 @@ pub fn const_val_field<'a, 'tcx>(
fn const_val_field_inner<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
field: mir::Field,
value: Value,
ty: Ty<'tcx>,
) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> {
trace!("const_val_field: {:#?}", key);
let (instance, field, value, ty) = key.value;
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let (mut field, ty) = match value {
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"),
Value::ByRef(ptr, align) => {
......@@ -348,11 +354,13 @@ fn const_val_field_inner<'a, 'tcx>(
pub fn const_discr<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
value: Value,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, u128> {
trace!("const_discr: {:#?}", key);
let (instance, value, ty) = key.value;
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
let layout = ecx.layout_of(ty)?;
......
......@@ -16,6 +16,8 @@
#![deny(warnings)]
#![feature(slice_patterns)]
#![feature(from_ref)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(catch_expr)]
......@@ -38,6 +40,7 @@
#![feature(nonzero)]
#![feature(underscore_lifetimes)]
extern crate arena;
#[macro_use]
extern crate bitflags;
#[macro_use] extern crate log;
......@@ -52,7 +55,6 @@
extern crate syntax_pos;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate core; // for NonZero
extern crate log_settings;
extern crate rustc_apfloat;
......@@ -69,6 +71,7 @@
pub mod util;
pub mod interpret;
pub mod monomorphize;
pub mod const_eval;
use rustc::ty::maps::Providers;
......@@ -77,6 +80,7 @@ pub fn provide(providers: &mut Providers) {
shim::provide(providers);
transform::provide(providers);
providers.const_eval = interpret::const_eval_provider;
providers.check_match = const_eval::check_match::check_match;
}
__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
......@@ -11,7 +11,7 @@ crate-type = ["dylib"]
[dependencies]
log = "0.4"
rustc = { path = "../librustc" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_mir = { path = "../librustc_mir"}
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
syntax = { path = "../libsyntax" }
......
......@@ -25,7 +25,7 @@
// by borrowck::gather_loans
use rustc::ty::cast::CastKind;
use rustc_const_eval::ConstContext;
use rustc_mir::const_eval::ConstContext;
use rustc::middle::const_val::ConstEvalErr;
use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll};
use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
......
......@@ -23,7 +23,7 @@
#[macro_use]
extern crate rustc;
extern crate rustc_const_eval;
extern crate rustc_mir;
extern crate rustc_const_math;
extern crate rustc_data_structures;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册