| // 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 {} |
| } |