274 lines
8.0 KiB
Rust
274 lines
8.0 KiB
Rust
// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly.
|
|
|
|
#![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)]
|
|
#![deny(unreachable_patterns)]
|
|
|
|
// aux-build:enums.rs
|
|
extern crate enums;
|
|
// aux-build:unstable.rs
|
|
extern crate unstable;
|
|
// aux-build:structs.rs
|
|
extern crate structs;
|
|
|
|
use enums::{
|
|
EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant,
|
|
VariantNonExhaustive,
|
|
};
|
|
use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct};
|
|
use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct};
|
|
|
|
#[non_exhaustive]
|
|
#[derive(Default)]
|
|
pub struct Foo {
|
|
a: u8,
|
|
b: usize,
|
|
c: String,
|
|
}
|
|
|
|
#[non_exhaustive]
|
|
pub enum Bar {
|
|
A,
|
|
B,
|
|
C,
|
|
}
|
|
|
|
fn no_lint() {
|
|
let non_enum = NonExhaustiveEnum::Unit;
|
|
// Ok: without the attribute
|
|
match non_enum {
|
|
NonExhaustiveEnum::Unit => {}
|
|
NonExhaustiveEnum::Tuple(_) => {}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
#[deny(non_exhaustive_omitted_patterns)]
|
|
fn main() {
|
|
let enumeration = Bar::A;
|
|
|
|
// Ok: this is a crate local non_exhaustive enum
|
|
match enumeration {
|
|
Bar::A => {}
|
|
Bar::B => {}
|
|
_ => {}
|
|
}
|
|
|
|
let non_enum = NonExhaustiveEnum::Unit;
|
|
|
|
#[allow(non_exhaustive_omitted_patterns)]
|
|
match non_enum {
|
|
NonExhaustiveEnum::Unit => {}
|
|
NonExhaustiveEnum::Tuple(_) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match non_enum {
|
|
//~^ some variants are not matched explicitly
|
|
NonExhaustiveEnum::Unit => {}
|
|
NonExhaustiveEnum::Tuple(_) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match non_enum {
|
|
//~^ some variants are not matched explicitly
|
|
NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {}
|
|
_ => {}
|
|
}
|
|
|
|
let x = 5;
|
|
// We ignore the guard.
|
|
match non_enum {
|
|
NonExhaustiveEnum::Unit if x > 10 => {}
|
|
NonExhaustiveEnum::Tuple(_) => {}
|
|
NonExhaustiveEnum::Struct { .. } => {}
|
|
_ => {}
|
|
}
|
|
|
|
match (non_enum, true) {
|
|
(NonExhaustiveEnum::Unit, true) => {}
|
|
(NonExhaustiveEnum::Tuple(_), false) => {}
|
|
(NonExhaustiveEnum::Struct { .. }, false) => {}
|
|
_ => {}
|
|
}
|
|
match (non_enum, true) {
|
|
//~^ some variants are not matched explicitly
|
|
(NonExhaustiveEnum::Unit, true) => {}
|
|
(NonExhaustiveEnum::Tuple(_), false) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match (true, non_enum) {
|
|
(true, NonExhaustiveEnum::Unit) => {}
|
|
(false, NonExhaustiveEnum::Tuple(_)) => {}
|
|
(false, NonExhaustiveEnum::Struct { .. }) => {}
|
|
_ => {}
|
|
}
|
|
match (true, non_enum) {
|
|
//~^ some variants are not matched explicitly
|
|
(true, NonExhaustiveEnum::Unit) => {}
|
|
(false, NonExhaustiveEnum::Tuple(_)) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match Some(non_enum) {
|
|
//~^ some variants are not matched explicitly
|
|
Some(NonExhaustiveEnum::Unit) => {}
|
|
Some(NonExhaustiveEnum::Tuple(_)) => {}
|
|
_ => {}
|
|
}
|
|
|
|
// Ok: all covered and not `unreachable-patterns`
|
|
#[deny(unreachable_patterns)]
|
|
match non_enum {
|
|
NonExhaustiveEnum::Unit => {}
|
|
NonExhaustiveEnum::Tuple(_) => {}
|
|
NonExhaustiveEnum::Struct { .. } => {}
|
|
_ => {}
|
|
}
|
|
|
|
match NestedNonExhaustive::B {
|
|
//~^ some variants are not matched explicitly
|
|
NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {}
|
|
NestedNonExhaustive::A(_) => {}
|
|
NestedNonExhaustive::B => {}
|
|
_ => {}
|
|
}
|
|
|
|
match VariantNonExhaustive::Baz(1, 2) {
|
|
VariantNonExhaustive::Baz(_, _) => {}
|
|
VariantNonExhaustive::Bar { x, .. } => {}
|
|
}
|
|
//~^^ some fields are not explicitly listed
|
|
|
|
let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default();
|
|
//~^ some fields are not explicitly listed
|
|
|
|
// Ok: this is local
|
|
let Foo { a, b, .. } = Foo::default();
|
|
|
|
let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
|
|
//~^ some fields are not explicitly listed
|
|
//~^^ some fields are not explicitly listed
|
|
|
|
// Ok: this tests https://github.com/rust-lang/rust/issues/89382
|
|
let MixedVisFields { a, b, .. } = MixedVisFields::default();
|
|
|
|
// Ok: this only has 1 variant
|
|
match NonExhaustiveSingleVariant::A(true) {
|
|
NonExhaustiveSingleVariant::A(true) => {}
|
|
_ => {}
|
|
}
|
|
|
|
// We can't catch the case below, so for consistency we don't catch this one either.
|
|
match NonExhaustiveSingleVariant::A(true) {
|
|
_ => {}
|
|
}
|
|
// We can't catch this case, because this would require digging fully through all the values of
|
|
// any type we encounter. We need to be able to only consider present constructors.
|
|
match &NonExhaustiveSingleVariant::A(true) {
|
|
_ => {}
|
|
}
|
|
|
|
match Some(NonExhaustiveSingleVariant::A(true)) {
|
|
Some(_) => {}
|
|
None => {}
|
|
}
|
|
match Some(&NonExhaustiveSingleVariant::A(true)) {
|
|
Some(_) => {}
|
|
None => {}
|
|
}
|
|
|
|
// Ok: we don't lint on `if let` expressions
|
|
if let NonExhaustiveEnum::Tuple(_) = non_enum {}
|
|
|
|
match UnstableEnum::Stable {
|
|
//~^ some variants are not matched explicitly
|
|
UnstableEnum::Stable => {}
|
|
UnstableEnum::Stable2 => {}
|
|
_ => {}
|
|
}
|
|
|
|
// Ok: the feature is on and all variants are matched
|
|
match UnstableEnum::Stable {
|
|
UnstableEnum::Stable => {}
|
|
UnstableEnum::Stable2 => {}
|
|
UnstableEnum::Unstable => {}
|
|
_ => {}
|
|
}
|
|
|
|
// Ok: the feature is on and both variants are matched
|
|
match OnlyUnstableEnum::Unstable {
|
|
OnlyUnstableEnum::Unstable => {}
|
|
OnlyUnstableEnum::Unstable2 => {}
|
|
_ => {}
|
|
}
|
|
|
|
match OnlyUnstableEnum::Unstable {
|
|
//~^ some variants are not matched explicitly
|
|
OnlyUnstableEnum::Unstable => {}
|
|
_ => {}
|
|
}
|
|
|
|
let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
|
|
//~^ some fields are not explicitly listed
|
|
|
|
// OK: both unstable fields are matched with feature on
|
|
let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new();
|
|
|
|
let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
|
|
//~^ some fields are not explicitly listed
|
|
|
|
// OK: both unstable and stable fields are matched with feature on
|
|
let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default();
|
|
|
|
// Ok: local bindings are allowed
|
|
let local = NonExhaustiveEnum::Unit;
|
|
|
|
// Ok: missing patterns will be blocked by the pattern being refutable
|
|
let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
|
|
//~^ refutable pattern in local binding
|
|
|
|
// Check that matching on a reference results in a correct diagnostic
|
|
match &non_enum {
|
|
//~^ some variants are not matched explicitly
|
|
//~| pattern `&NonExhaustiveEnum::Struct { .. }` not covered
|
|
NonExhaustiveEnum::Unit => {}
|
|
NonExhaustiveEnum::Tuple(_) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match (true, &non_enum) {
|
|
//~^ some variants are not matched explicitly
|
|
//~| patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered
|
|
(true, NonExhaustiveEnum::Unit) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match (&non_enum, true) {
|
|
//~^ some variants are not matched explicitly
|
|
//~| patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered
|
|
(NonExhaustiveEnum::Unit, true) => {}
|
|
_ => {}
|
|
}
|
|
|
|
match Some(&non_enum) {
|
|
//~^ some variants are not matched explicitly
|
|
//~| pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered
|
|
Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
#[deny(non_exhaustive_omitted_patterns)]
|
|
// Ok: Pattern in a param is always wildcard
|
|
pub fn takes_non_exhaustive(_: NonExhaustiveEnum) {
|
|
let _closure = |_: NonExhaustiveEnum| {};
|
|
}
|
|
|
|
// ICE #117033
|
|
enum Void {}
|
|
#[deny(non_exhaustive_omitted_patterns)]
|
|
pub fn void(v: Void) -> ! {
|
|
match v {}
|
|
}
|