Make is_useful handle empty types properly
This commit is contained in:
parent
9ad20442e8
commit
bcdbe942e1
24 changed files with 246 additions and 85 deletions
|
@ -70,6 +70,12 @@ declare_lint! {
|
||||||
"detects unreachable code paths"
|
"detects unreachable code paths"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
pub UNREACHABLE_PATTERNS,
|
||||||
|
Warn,
|
||||||
|
"detects unreachable patterns"
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub WARNINGS,
|
pub WARNINGS,
|
||||||
Warn,
|
Warn,
|
||||||
|
@ -239,6 +245,7 @@ impl LintPass for HardwiredLints {
|
||||||
UNUSED_ASSIGNMENTS,
|
UNUSED_ASSIGNMENTS,
|
||||||
DEAD_CODE,
|
DEAD_CODE,
|
||||||
UNREACHABLE_CODE,
|
UNREACHABLE_CODE,
|
||||||
|
UNREACHABLE_PATTERNS,
|
||||||
WARNINGS,
|
WARNINGS,
|
||||||
UNUSED_FEATURES,
|
UNUSED_FEATURES,
|
||||||
STABLE_FEATURES,
|
STABLE_FEATURES,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use eval::{compare_const_vals};
|
||||||
|
|
||||||
use rustc_const_math::ConstInt;
|
use rustc_const_math::ConstInt;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
use pattern::{FieldPattern, Pattern, PatternKind};
|
use pattern::{FieldPattern, Pattern, PatternKind};
|
||||||
|
@ -29,6 +29,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc::mir::Field;
|
use rustc::mir::Field;
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
|
|
||||||
|
use syntax::ast::NodeId;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
|
@ -144,6 +145,14 @@ impl<'a, 'tcx> FromIterator<Vec<&'a Pattern<'tcx>>> for Matrix<'a, 'tcx> {
|
||||||
//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
|
//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
|
||||||
pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
/// (roughly) where in the code the match occurs. This is necessary for
|
||||||
|
/// checking inhabited-ness of types because whether a type is (visibly)
|
||||||
|
/// inhabited can depend on whether it was defined in the current module or
|
||||||
|
/// not. eg.
|
||||||
|
/// struct Foo { _private: ! }
|
||||||
|
/// can not be seen to be empty outside it's module and should not
|
||||||
|
/// be matchable with an empty match statement.
|
||||||
|
pub node: NodeId,
|
||||||
/// A wild pattern with an error type - it exists to avoid having to normalize
|
/// A wild pattern with an error type - it exists to avoid having to normalize
|
||||||
/// associated types to get field types.
|
/// associated types to get field types.
|
||||||
pub wild_pattern: &'a Pattern<'tcx>,
|
pub wild_pattern: &'a Pattern<'tcx>,
|
||||||
|
@ -154,6 +163,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
||||||
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||||
pub fn create_and_enter<F, R>(
|
pub fn create_and_enter<F, R>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
node: NodeId,
|
||||||
f: F) -> R
|
f: F) -> R
|
||||||
where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
|
where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
|
||||||
{
|
{
|
||||||
|
@ -167,6 +177,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
f(MatchCheckCtxt {
|
f(MatchCheckCtxt {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
|
node: node,
|
||||||
wild_pattern: &wild_pattern,
|
wild_pattern: &wild_pattern,
|
||||||
pattern_arena: &pattern_arena,
|
pattern_arena: &pattern_arena,
|
||||||
byte_array_map: FxHashMap(),
|
byte_array_map: FxHashMap(),
|
||||||
|
@ -362,9 +373,9 @@ impl<'tcx> Witness<'tcx> {
|
||||||
/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
|
/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
|
||||||
/// still be unmatched if the first constructor is replaced by any of the constructors
|
/// still be unmatched if the first constructor is replaced by any of the constructors
|
||||||
/// in the return value.
|
/// in the return value.
|
||||||
fn missing_constructors(cx: &mut MatchCheckCtxt,
|
fn missing_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||||
matrix: &Matrix,
|
matrix: &Matrix,
|
||||||
pcx: PatternContext) -> Vec<Constructor> {
|
pcx: PatternContext<'tcx>) -> Vec<Constructor> {
|
||||||
let used_constructors: Vec<Constructor> =
|
let used_constructors: Vec<Constructor> =
|
||||||
matrix.0.iter()
|
matrix.0.iter()
|
||||||
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
|
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
|
||||||
|
@ -384,16 +395,46 @@ fn missing_constructors(cx: &mut MatchCheckCtxt,
|
||||||
///
|
///
|
||||||
/// but is instead bounded by the maximum fixed length of slice patterns in
|
/// but is instead bounded by the maximum fixed length of slice patterns in
|
||||||
/// the column of patterns being analyzed.
|
/// the column of patterns being analyzed.
|
||||||
fn all_constructors(_cx: &mut MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructor> {
|
///
|
||||||
|
/// We make sure to omit constructors that are statically impossible. eg for
|
||||||
|
/// Option<!> we do not include Some(_) in the returned list of constructors.
|
||||||
|
fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||||
|
pcx: PatternContext<'tcx>) -> Vec<Constructor>
|
||||||
|
{
|
||||||
match pcx.ty.sty {
|
match pcx.ty.sty {
|
||||||
ty::TyBool =>
|
ty::TyBool =>
|
||||||
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
||||||
ty::TySlice(_) =>
|
ty::TySlice(ref sub_ty) => {
|
||||||
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect(),
|
if sub_ty.is_uninhabited(Some(cx.node), cx.tcx) {
|
||||||
ty::TyArray(_, length) => vec![Slice(length)],
|
vec![Slice(0)]
|
||||||
ty::TyAdt(def, _) if def.is_enum() && def.variants.len() > 1 =>
|
} else {
|
||||||
def.variants.iter().map(|v| Variant(v.did)).collect(),
|
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
|
||||||
_ => vec![Single]
|
}
|
||||||
|
}
|
||||||
|
ty::TyArray(ref sub_ty, length) => {
|
||||||
|
if length == 0 || !sub_ty.is_uninhabited(Some(cx.node), cx.tcx) {
|
||||||
|
vec![Slice(length)]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
|
||||||
|
def.variants.iter().filter_map(|v| {
|
||||||
|
let mut visited = FxHashSet::default();
|
||||||
|
if v.is_uninhabited_recurse(&mut visited, Some(cx.node), cx.tcx, substs, false) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Variant(v.did))
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if pcx.ty.is_uninhabited(Some(cx.node), cx.tcx) {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
vec![Single]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use rustc::middle::mem_categorization::{cmt};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
|
use rustc::lint;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
|
|
||||||
use rustc::hir::def::*;
|
use rustc::hir::def::*;
|
||||||
|
@ -150,7 +151,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchCheckCtxt::create_and_enter(self.tcx, |ref mut cx| {
|
MatchCheckCtxt::create_and_enter(self.tcx, scrut.id, |ref mut cx| {
|
||||||
let mut have_errors = false;
|
let mut have_errors = false;
|
||||||
|
|
||||||
let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
|
let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
|
||||||
|
@ -210,7 +211,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||||
"local binding"
|
"local binding"
|
||||||
};
|
};
|
||||||
|
|
||||||
MatchCheckCtxt::create_and_enter(self.tcx, |ref mut cx| {
|
MatchCheckCtxt::create_and_enter(self.tcx, pat.id, |ref mut cx| {
|
||||||
let mut patcx = PatternContext::new(self.tcx);
|
let mut patcx = PatternContext::new(self.tcx);
|
||||||
let pats : Matrix = vec![vec![
|
let pats : Matrix = vec![vec![
|
||||||
expand_pattern(cx, patcx.lower_pattern(pat))
|
expand_pattern(cx, patcx.lower_pattern(pat))
|
||||||
|
@ -324,14 +325,19 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
hir::MatchSource::Normal => {
|
hir::MatchSource::Normal => {
|
||||||
let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001,
|
// if we had a catchall pattern, raise an error.
|
||||||
"unreachable pattern");
|
// Otherwise an unreachable pattern raises a warning.
|
||||||
err.span_label(pat.span, &"this is an unreachable pattern");
|
|
||||||
// if we had a catchall pattern, hint at that
|
|
||||||
if let Some(catchall) = catchall {
|
if let Some(catchall) = catchall {
|
||||||
|
let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001,
|
||||||
|
"unreachable pattern");
|
||||||
|
err.span_label(pat.span, &"this is an unreachable pattern");
|
||||||
err.span_note(catchall, "this pattern matches any value");
|
err.span_note(catchall, "this pattern matches any value");
|
||||||
|
err.emit();
|
||||||
|
} else {
|
||||||
|
cx.tcx.sess.add_lint(lint::builtin::UNREACHABLE_PATTERNS,
|
||||||
|
hir_pat.id, pat.span,
|
||||||
|
String::from("unreachable pattern"));
|
||||||
}
|
}
|
||||||
err.emit();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hir::MatchSource::TryDesugar => {
|
hir::MatchSource::TryDesugar => {
|
||||||
|
|
|
@ -28,7 +28,7 @@ For example, the following `match` block has too many arms:
|
||||||
```compile_fail,E0001
|
```compile_fail,E0001
|
||||||
match Some(0) {
|
match Some(0) {
|
||||||
Some(bar) => {/* ... */}
|
Some(bar) => {/* ... */}
|
||||||
None => {/* ... */}
|
x => {/* ... */} // This handles the `None` case
|
||||||
_ => {/* ... */} // All possible cases have already been handled
|
_ => {/* ... */} // All possible cases have already been handled
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -165,6 +165,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||||
DEAD_CODE,
|
DEAD_CODE,
|
||||||
UNUSED_MUT,
|
UNUSED_MUT,
|
||||||
UNREACHABLE_CODE,
|
UNREACHABLE_CODE,
|
||||||
|
UNREACHABLE_PATTERNS,
|
||||||
UNUSED_MUST_USE,
|
UNUSED_MUST_USE,
|
||||||
UNUSED_UNSAFE,
|
UNUSED_UNSAFE,
|
||||||
PATH_STATEMENTS,
|
PATH_STATEMENTS,
|
||||||
|
|
|
@ -399,7 +399,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.check_pat(&p, discrim_ty);
|
self.check_pat(&p, discrim_ty);
|
||||||
all_pats_diverge &= self.diverges.get();
|
all_pats_diverge &= self.diverges.get();
|
||||||
}
|
}
|
||||||
all_pats_diverge
|
// As discussed with @eddyb, this is for disabling unreachable_code
|
||||||
|
// warnings on patterns (they're now subsumed by unreachable_patterns
|
||||||
|
// warnings).
|
||||||
|
match all_pats_diverge {
|
||||||
|
Diverges::Maybe => Diverges::Maybe,
|
||||||
|
Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways,
|
||||||
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
// Now typecheck the blocks.
|
// Now typecheck the blocks.
|
||||||
|
|
|
@ -8,11 +8,13 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foo = Some(1);
|
let foo = Some(1);
|
||||||
match foo {
|
match foo {
|
||||||
Some(bar) => {/* ... */}
|
Some(_) => {/* ... */}
|
||||||
None => {/* ... */}
|
None => {/* ... */}
|
||||||
_ => {/* ... */} //~ ERROR E0001
|
_ => {/* ... */} //~ ERROR unreachable pattern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ fn tail(source_list: &IntList) -> IntList {
|
||||||
match source_list {
|
match source_list {
|
||||||
&IntList::Cons(val, box ref next_list) => tail(next_list),
|
&IntList::Cons(val, box ref next_list) => tail(next_list),
|
||||||
&IntList::Cons(val, box Nil) => IntList::Cons(val, box Nil),
|
&IntList::Cons(val, box Nil) => IntList::Cons(val, box Nil),
|
||||||
//~^ ERROR unreachable pattern
|
//~^ ERROR cannot move out of borrowed content
|
||||||
//~^^ WARN pattern binding `Nil` is named the same as one of the variants of the type `IntList`
|
//~^^ WARN pattern binding `Nil` is named the same as one of the variants of the type `IntList`
|
||||||
_ => panic!()
|
_ => panic!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let sl = vec![1,2,3];
|
let sl = vec![1,2,3];
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![allow(overflowing_literals)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn test(val: u8) {
|
fn test(val: u8) {
|
||||||
match val {
|
match val {
|
||||||
256 => print!("0b1110\n"),
|
256 => print!("0b1110\n"),
|
||||||
|
|
26
src/test/compile-fail/issue-30240-b.rs
Normal file
26
src/test/compile-fail/issue-30240-b.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match "world" {
|
||||||
|
"hello" => {}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
match "world" {
|
||||||
|
ref _x if false => {}
|
||||||
|
"hello" => {}
|
||||||
|
"hello" => {} //~ ERROR unreachable pattern
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,5 @@ fn main() {
|
||||||
match "world" { //~ ERROR non-exhaustive patterns: `&_`
|
match "world" { //~ ERROR non-exhaustive patterns: `&_`
|
||||||
ref _x if false => {}
|
ref _x if false => {}
|
||||||
"hello" => {}
|
"hello" => {}
|
||||||
"hello" => {} //~ ERROR unreachable pattern
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
enum Enum {
|
enum Enum {
|
||||||
Var1,
|
Var1,
|
||||||
Var2,
|
Var2,
|
||||||
|
@ -41,13 +43,4 @@ fn main() {
|
||||||
//~^ ERROR unreachable pattern
|
//~^ ERROR unreachable pattern
|
||||||
//~^^ NOTE this is an unreachable pattern
|
//~^^ NOTE this is an unreachable pattern
|
||||||
};
|
};
|
||||||
// `_` need not emit a note, it is pretty obvious already.
|
|
||||||
let t = (Var1, Var1);
|
|
||||||
match t {
|
|
||||||
(Var1, b) => (),
|
|
||||||
_ => (),
|
|
||||||
anything => ()
|
|
||||||
//~^ ERROR unreachable pattern
|
|
||||||
//~^^ NOTE this is an unreachable pattern
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,5 @@ fn main() {
|
||||||
box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
|
box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
|
||||||
box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
|
box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
|
||||||
},
|
},
|
||||||
_ => panic!("WAT") //~ ERROR unreachable pattern
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
71
src/test/compile-fail/match-argm-statics-2.rs
Normal file
71
src/test/compile-fail/match-argm-statics-2.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use self::Direction::{North, East, South, West};
|
||||||
|
|
||||||
|
struct NewBool(bool);
|
||||||
|
|
||||||
|
enum Direction {
|
||||||
|
North,
|
||||||
|
East,
|
||||||
|
South,
|
||||||
|
West
|
||||||
|
}
|
||||||
|
|
||||||
|
const TRUE_TRUE: (bool, bool) = (true, true);
|
||||||
|
|
||||||
|
fn nonexhaustive_1() {
|
||||||
|
match (true, false) {
|
||||||
|
//~^ ERROR non-exhaustive patterns: `(true, false)` not covered
|
||||||
|
TRUE_TRUE => (),
|
||||||
|
(false, false) => (),
|
||||||
|
(false, true) => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NONE: Option<Direction> = None;
|
||||||
|
const EAST: Direction = East;
|
||||||
|
|
||||||
|
fn nonexhaustive_2() {
|
||||||
|
match Some(Some(North)) {
|
||||||
|
//~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
|
||||||
|
Some(NONE) => (),
|
||||||
|
Some(Some(North)) => (),
|
||||||
|
Some(Some(EAST)) => (),
|
||||||
|
Some(Some(South)) => (),
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NEW_FALSE: NewBool = NewBool(false);
|
||||||
|
struct Foo {
|
||||||
|
bar: Option<Direction>,
|
||||||
|
baz: NewBool
|
||||||
|
}
|
||||||
|
|
||||||
|
const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
|
||||||
|
|
||||||
|
fn nonexhaustive_3() {
|
||||||
|
match (Foo { bar: Some(North), baz: NewBool(true) }) {
|
||||||
|
//~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
|
||||||
|
Foo { bar: None, baz: NewBool(true) } => (),
|
||||||
|
Foo { bar: _, baz: NEW_FALSE } => (),
|
||||||
|
Foo { bar: Some(West), baz: NewBool(true) } => (),
|
||||||
|
Foo { bar: Some(South), .. } => (),
|
||||||
|
Foo { bar: Some(EAST), .. } => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
nonexhaustive_1();
|
||||||
|
nonexhaustive_2();
|
||||||
|
nonexhaustive_3();
|
||||||
|
}
|
||||||
|
|
|
@ -7,10 +7,16 @@
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
use self::Direction::{North, East, South, West};
|
use self::Direction::{North, East, South, West};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
struct NewBool(bool);
|
struct NewBool(bool);
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
enum Direction {
|
enum Direction {
|
||||||
North,
|
North,
|
||||||
East,
|
East,
|
||||||
|
@ -20,15 +26,6 @@ enum Direction {
|
||||||
|
|
||||||
const TRUE_TRUE: (bool, bool) = (true, true);
|
const TRUE_TRUE: (bool, bool) = (true, true);
|
||||||
|
|
||||||
fn nonexhaustive_1() {
|
|
||||||
match (true, false) {
|
|
||||||
//~^ ERROR non-exhaustive patterns: `(true, false)` not covered
|
|
||||||
TRUE_TRUE => (),
|
|
||||||
(false, false) => (),
|
|
||||||
(false, true) => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unreachable_1() {
|
fn unreachable_1() {
|
||||||
match (true, false) {
|
match (true, false) {
|
||||||
TRUE_TRUE => (),
|
TRUE_TRUE => (),
|
||||||
|
@ -43,17 +40,6 @@ fn unreachable_1() {
|
||||||
const NONE: Option<Direction> = None;
|
const NONE: Option<Direction> = None;
|
||||||
const EAST: Direction = East;
|
const EAST: Direction = East;
|
||||||
|
|
||||||
fn nonexhaustive_2() {
|
|
||||||
match Some(Some(North)) {
|
|
||||||
//~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
|
|
||||||
Some(NONE) => (),
|
|
||||||
Some(Some(North)) => (),
|
|
||||||
Some(Some(EAST)) => (),
|
|
||||||
Some(Some(South)) => (),
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unreachable_2() {
|
fn unreachable_2() {
|
||||||
match Some(Some(North)) {
|
match Some(Some(North)) {
|
||||||
Some(NONE) => (),
|
Some(NONE) => (),
|
||||||
|
@ -73,19 +59,6 @@ struct Foo {
|
||||||
baz: NewBool
|
baz: NewBool
|
||||||
}
|
}
|
||||||
|
|
||||||
const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
|
|
||||||
|
|
||||||
fn nonexhaustive_3() {
|
|
||||||
match (Foo { bar: Some(North), baz: NewBool(true) }) {
|
|
||||||
//~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
|
|
||||||
Foo { bar: None, baz: NewBool(true) } => (),
|
|
||||||
Foo { bar: _, baz: NEW_FALSE } => (),
|
|
||||||
Foo { bar: Some(West), baz: NewBool(true) } => (),
|
|
||||||
Foo { bar: Some(South), .. } => (),
|
|
||||||
Foo { bar: Some(EAST), .. } => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unreachable_3() {
|
fn unreachable_3() {
|
||||||
match (Foo { bar: Some(EAST), baz: NewBool(true) }) {
|
match (Foo { bar: Some(EAST), baz: NewBool(true) }) {
|
||||||
Foo { bar: None, baz: NewBool(true) } => (),
|
Foo { bar: None, baz: NewBool(true) } => (),
|
||||||
|
@ -100,9 +73,6 @@ fn unreachable_3() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
nonexhaustive_1();
|
|
||||||
nonexhaustive_2();
|
|
||||||
nonexhaustive_3();
|
|
||||||
unreachable_1();
|
unreachable_1();
|
||||||
unreachable_2();
|
unreachable_2();
|
||||||
unreachable_3();
|
unreachable_3();
|
||||||
|
|
26
src/test/compile-fail/match-byte-array-patterns-2.rs
Normal file
26
src/test/compile-fail/match-byte-array-patterns-2.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(advanced_slice_patterns, slice_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let buf = &[0, 1, 2, 3];
|
||||||
|
|
||||||
|
match buf { //~ ERROR non-exhaustive
|
||||||
|
b"AAAA" => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf: &[u8] = buf;
|
||||||
|
|
||||||
|
match buf { //~ ERROR non-exhaustive
|
||||||
|
b"AAAA" => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(advanced_slice_patterns, slice_patterns)]
|
#![feature(advanced_slice_patterns, slice_patterns)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let buf = &[0, 1, 2, 3];
|
let buf = &[0, 1, 2, 3];
|
||||||
|
@ -37,10 +38,6 @@ fn main() {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match buf { //~ ERROR non-exhaustive
|
|
||||||
b"AAAA" => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let buf: &[u8] = buf;
|
let buf: &[u8] = buf;
|
||||||
|
|
||||||
match buf {
|
match buf {
|
||||||
|
@ -66,8 +63,4 @@ fn main() {
|
||||||
b"AAAA" => {}, //~ ERROR unreachable pattern
|
b"AAAA" => {}, //~ ERROR unreachable pattern
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match buf { //~ ERROR non-exhaustive
|
|
||||||
b"AAAA" => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
//error-pattern: unreachable
|
//error-pattern: unreachable
|
||||||
//error-pattern: unreachable
|
//error-pattern: unreachable
|
||||||
|
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match 5 {
|
match 5 {
|
||||||
1 ... 10 => { }
|
1 ... 10 => { }
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
// The arity of `ref x` is always 1. If the pattern is compared to some non-structural type whose
|
// The arity of `ref x` is always 1. If the pattern is compared to some non-structural type whose
|
||||||
// arity is always 0, an ICE occurs.
|
// arity is always 0, an ICE occurs.
|
||||||
|
@ -19,7 +20,7 @@ fn main() {
|
||||||
let homura = [1, 2, 3];
|
let homura = [1, 2, 3];
|
||||||
|
|
||||||
match homura {
|
match homura {
|
||||||
[1, ref madoka, 3] => (),
|
[1, ref _madoka, 3] => (),
|
||||||
[1, 2, 3] => (), //~ ERROR unreachable pattern
|
[1, 2, 3] => (), //~ ERROR unreachable pattern
|
||||||
[_, _, _] => (),
|
[_, _, _] => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn a() {
|
fn a() {
|
||||||
let v = [1, 2, 3];
|
let v = [1, 2, 3];
|
||||||
|
|
|
@ -9,13 +9,14 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x: Vec<(isize, isize)> = Vec::new();
|
let x: Vec<(isize, isize)> = Vec::new();
|
||||||
let x: &[(isize, isize)] = &x;
|
let x: &[(isize, isize)] = &x;
|
||||||
match *x {
|
match *x {
|
||||||
[a, (2, 3), _] => (),
|
[_, (2, 3), _] => (),
|
||||||
[(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern
|
[(1, 2), (2, 3), _] => (), //~ ERROR unreachable pattern
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ fn main() {
|
||||||
"baz".to_string()];
|
"baz".to_string()];
|
||||||
let x: &[String] = &x;
|
let x: &[String] = &x;
|
||||||
match *x {
|
match *x {
|
||||||
[a, _, _, ..] => { println!("{}", a); }
|
[ref a, _, _, ..] => { println!("{}", a); }
|
||||||
[_, _, _, _, _] => { } //~ ERROR unreachable pattern
|
[_, _, _, _, _] => { } //~ ERROR unreachable pattern
|
||||||
_ => { }
|
_ => { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
x: isize,
|
x: isize,
|
||||||
y: isize,
|
y: isize,
|
||||||
|
@ -16,7 +18,7 @@ struct Foo {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let a = Foo { x: 1, y: 2 };
|
let a = Foo { x: 1, y: 2 };
|
||||||
match a {
|
match a {
|
||||||
Foo { x: x, y: y } => (),
|
Foo { x: _x, y: _y } => (),
|
||||||
Foo { .. } => () //~ ERROR unreachable pattern
|
Foo { .. } => () //~ ERROR unreachable pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,16 @@
|
||||||
|
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
enum foo { a(Box<foo>, isize), b(usize), }
|
enum Foo { A(Box<Foo>, isize), B(usize), }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match Foo::B(1) {
|
||||||
|
Foo::B(_) | Foo::A(box _, 1) => { }
|
||||||
|
Foo::A(_, 1) => { }
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() { match foo::b(1) { foo::b(_) | foo::a(box _, 1) => { } foo::a(_, 1) => { } } }
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue