Rollup merge of #66967 - Nadrieril:remove-or-pat-hack, r=varkor

Remove hack for top-level or-patterns in match checking

Follow-up to #66612.

Or-patterns are now truly first-class in match checking. As a side-effect, redundant subpatterns are linted as such, making the `unreachable_patterns` lint a bit more general.

cc #54883

r? @varkor
This commit is contained in:
Mazdak Farrokhzad 2019-12-03 11:07:08 +01:00 committed by GitHub
commit bce77980a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 354 additions and 176 deletions

View file

@ -425,16 +425,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
}
/// This computes `S(constructor, self)`. See top of the file for explanations.
fn specialize_constructor<'a, 'q>(
fn specialize_constructor(
&self,
cx: &mut MatchCheckCtxt<'a, 'tcx>,
cx: &mut MatchCheckCtxt<'p, 'tcx>,
constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &[&'q Pat<'tcx>],
) -> Option<PatStack<'q, 'tcx>>
where
'a: 'q,
'p: 'q,
{
ctor_wild_subpatterns: &'p [Pat<'tcx>],
) -> Option<PatStack<'p, 'tcx>> {
let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
new_heads.map(|mut new_head| {
new_head.0.extend_from_slice(&self.0[1..]);
@ -459,6 +455,7 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
}
/// A 2D matrix.
#[derive(Clone)]
pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
impl<'p, 'tcx> Matrix<'p, 'tcx> {
@ -486,16 +483,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
}
/// This computes `S(constructor, self)`. See top of the file for explanations.
fn specialize_constructor<'a, 'q>(
fn specialize_constructor(
&self,
cx: &mut MatchCheckCtxt<'a, 'tcx>,
cx: &mut MatchCheckCtxt<'p, 'tcx>,
constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &[&'q Pat<'tcx>],
) -> Matrix<'q, 'tcx>
where
'a: 'q,
'p: 'q,
{
ctor_wild_subpatterns: &'p [Pat<'tcx>],
) -> Matrix<'p, 'tcx> {
self.0
.iter()
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
@ -1033,17 +1026,19 @@ impl<'tcx> Constructor<'tcx> {
}
#[derive(Clone, Debug)]
pub enum Usefulness<'tcx> {
Useful,
pub enum Usefulness<'tcx, 'p> {
/// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
Useful(Vec<&'p Pat<'tcx>>),
/// Carries a list of witnesses of non-exhaustiveness.
UsefulWithWitness(Vec<Witness<'tcx>>),
NotUseful,
}
impl<'tcx> Usefulness<'tcx> {
impl<'tcx, 'p> Usefulness<'tcx, 'p> {
fn new_useful(preference: WitnessPreference) -> Self {
match preference {
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
LeaveOutWitness => Useful,
LeaveOutWitness => Useful(vec![]),
}
}
@ -1604,13 +1599,13 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
/// 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).
pub fn is_useful<'p, 'a, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
pub fn is_useful<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v: &PatStack<'_, 'tcx>,
v: &PatStack<'p, 'tcx>,
witness_preference: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
) -> Usefulness<'tcx, 'p> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:#?}, {:#?})", matrix, v);
@ -1631,11 +1626,26 @@ pub fn is_useful<'p, 'a, 'tcx>(
// If the first pattern is an or-pattern, expand it.
if let Some(vs) = v.expand_or_pat() {
return vs
.into_iter()
.map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
.find(|result| result.is_useful())
.unwrap_or(NotUseful);
// We need to push the already-seen patterns into the matrix in order to detect redundant
// branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
let mut matrix = matrix.clone();
let mut unreachable_pats = Vec::new();
let mut any_is_useful = false;
for v in vs {
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
match res {
Useful(pats) => {
any_is_useful = true;
unreachable_pats.extend(pats);
}
NotUseful => unreachable_pats.push(v.head()),
UsefulWithWitness(_) => {
bug!("Encountered or-pat in `v` during exhaustiveness checking")
}
}
matrix.push(v);
}
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
}
let (ty, span) = matrix
@ -1768,21 +1778,21 @@ pub fn is_useful<'p, 'a, 'tcx>(
/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
fn is_useful_specialized<'p, 'a, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
fn is_useful_specialized<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v: &PatStack<'_, 'tcx>,
v: &PatStack<'p, 'tcx>,
ctor: Constructor<'tcx>,
lty: Ty<'tcx>,
witness_preference: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
) -> Usefulness<'tcx, 'p> {
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty);
let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
let ctor_wild_subpatterns =
cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
.map(|u| u.apply_constructor(cx, &ctor, lty))
.unwrap_or(NotUseful)
@ -2250,13 +2260,13 @@ fn constructor_covered_by_range<'tcx>(
if intersects { Some(()) } else { None }
}
fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
fn patterns_for_variant<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
subpatterns: &'p [FieldPat<'tcx>],
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
ctor_wild_subpatterns: &'p [Pat<'tcx>],
is_non_exhaustive: bool,
) -> PatStack<'p, 'tcx> {
let mut result = SmallVec::from_slice(ctor_wild_subpatterns);
let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect();
for subpat in subpatterns {
if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
@ -2280,11 +2290,11 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
pat: &'q Pat<'tcx>,
fn specialize_one_pattern<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
pat: &'p Pat<'tcx>,
constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
ctor_wild_subpatterns: &'p [Pat<'tcx>],
) -> Option<PatStack<'p, 'tcx>> {
if let NonExhaustive = constructor {
// Only a wildcard pattern can match the special extra constructor
@ -2294,9 +2304,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
let result = match *pat.kind {
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
PatKind::Binding { .. } | PatKind::Wild => {
Some(PatStack::from_slice(ctor_wild_subpatterns))
}
PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()),
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let ref variant = adt_def.variants[variant_index];
@ -2406,7 +2414,6 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
.chain(
ctor_wild_subpatterns
.iter()
.map(|p| *p)
.skip(prefix.len())
.take(slice_count)
.chain(suffix.iter()),

View file

@ -139,39 +139,22 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
let mut have_errors = false;
let inlined_arms: Vec<(Vec<_>, _)> = arms
let inlined_arms: Vec<_> = arms
.iter()
.map(|arm| {
(
// HACK(or_patterns; Centril | dlrobertson): Remove this and
// correctly handle exhaustiveness checking for nested or-patterns.
match &arm.pat.kind {
hir::PatKind::Or(pats) => pats,
_ => std::slice::from_ref(&arm.pat),
}
.iter()
.map(|pat| {
let mut patcx = PatCtxt::new(
self.tcx,
self.param_env.and(self.identity_substs),
self.tables,
);
patcx.include_lint_checks();
let pattern = cx
.pattern_arena
.alloc(expand_pattern(cx, patcx.lower_pattern(&pat)))
as &_;
if !patcx.errors.is_empty() {
patcx.report_inlining_errors(pat.span);
have_errors = true;
}
(pattern, &**pat)
})
.collect(),
arm.guard.as_ref().map(|g| match g {
hir::Guard::If(ref e) => &**e,
}),
)
let mut patcx = PatCtxt::new(
self.tcx,
self.param_env.and(self.identity_substs),
self.tables,
);
patcx.include_lint_checks();
let pattern: &_ =
cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&arm.pat)));
if !patcx.errors.is_empty() {
patcx.report_inlining_errors(arm.pat.span);
have_errors = true;
}
(pattern, &*arm.pat, arm.guard.is_some())
})
.collect();
@ -181,7 +164,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
}
// Fourth, check for unreachable arms.
check_arms(cx, &inlined_arms, source);
let matrix = check_arms(cx, &inlined_arms, source);
// Then, if the match has no arms, check whether the scrutinee
// is uninhabited.
@ -248,12 +231,6 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
return;
}
let matrix: Matrix<'_, '_> = inlined_arms
.iter()
.filter(|&&(_, guard)| guard.is_none())
.flat_map(|arm| &arm.0)
.map(|pat| PatStack::from_pattern(pat.0))
.collect();
let scrut_ty = self.tables.node_type(scrut.hir_id);
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
})
@ -267,8 +244,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
patcx.include_lint_checks();
let pattern = patcx.lower_pattern(pat);
let pattern_ty = pattern.ty;
let pattern = expand_pattern(cx, pattern);
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(&pattern)].into_iter().collect();
let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
Ok(_) => return,
@ -403,113 +380,120 @@ fn pat_is_catchall(pat: &Pat) -> bool {
}
// Check for unreachable patterns
fn check_arms<'tcx>(
cx: &mut MatchCheckCtxt<'_, 'tcx>,
arms: &[(Vec<(&super::Pat<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
fn check_arms<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
arms: &[(&'p super::Pat<'tcx>, &hir::Pat, bool)],
source: hir::MatchSource,
) {
) -> Matrix<'p, 'tcx> {
let mut seen = Matrix::empty();
let mut catchall = None;
for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
for &(pat, hir_pat) in pats {
let v = PatStack::from_pattern(pat);
for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
let v = PatStack::from_pattern(pat);
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
NotUseful => {
match source {
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => {
bug!()
}
hir::MatchSource::IfLetDesugar { .. } => {
cx.tcx.lint_hir(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.hir_id,
pat.span,
"irrefutable if-let pattern",
);
}
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
NotUseful => {
match source {
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
hir::MatchSource::WhileLetDesugar => {
// check which arm we're on.
match arm_index {
// The arm with the user-specified pattern.
0 => {
cx.tcx.lint_hir(
lint::builtin::UNREACHABLE_PATTERNS,
hir_pat.hir_id,
pat.span,
"unreachable pattern",
);
}
// The arm with the wildcard pattern.
1 => {
cx.tcx.lint_hir(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.hir_id,
pat.span,
"irrefutable while-let pattern",
);
}
_ => bug!(),
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
// check which arm we're on.
match arm_index {
// The arm with the user-specified pattern.
0 => {
cx.tcx.lint_hir(
lint::builtin::UNREACHABLE_PATTERNS,
hir_pat.hir_id,
pat.span,
"unreachable pattern",
);
}
}
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
let mut err = cx.tcx.struct_span_lint_hir(
lint::builtin::UNREACHABLE_PATTERNS,
hir_pat.hir_id,
pat.span,
"unreachable pattern",
);
// if we had a catchall pattern, hint at that
if let Some(catchall) = catchall {
err.span_label(pat.span, "unreachable pattern");
err.span_label(catchall, "matches any value");
// The arm with the wildcard pattern.
1 => {
let msg = match source {
hir::MatchSource::IfLetDesugar { .. } => {
"irrefutable if-let pattern"
}
hir::MatchSource::WhileLetDesugar => {
"irrefutable while-let pattern"
}
_ => bug!(),
};
cx.tcx.lint_hir(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.hir_id,
pat.span,
msg,
);
}
err.emit();
_ => bug!(),
}
// Unreachable patterns in try and await expressions occur when one of
// the arms are an uninhabited type. Which is OK.
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
}
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
let mut err = cx.tcx.struct_span_lint_hir(
lint::builtin::UNREACHABLE_PATTERNS,
hir_pat.hir_id,
pat.span,
"unreachable pattern",
);
// if we had a catchall pattern, hint at that
if let Some(catchall) = catchall {
err.span_label(pat.span, "unreachable pattern");
err.span_label(catchall, "matches any value");
}
err.emit();
}
// Unreachable patterns in try and await expressions occur when one of
// the arms are an uninhabited type. Which is OK.
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
}
Useful => (),
UsefulWithWitness(_) => bug!(),
}
if guard.is_none() {
seen.push(v);
if catchall.is_none() && pat_is_catchall(hir_pat) {
catchall = Some(pat.span);
Useful(unreachable_subpatterns) => {
for pat in unreachable_subpatterns {
cx.tcx.lint_hir(
lint::builtin::UNREACHABLE_PATTERNS,
hir_pat.hir_id,
pat.span,
"unreachable pattern",
);
}
}
UsefulWithWitness(_) => bug!(),
}
if !has_guard {
seen.push(v);
if catchall.is_none() && pat_is_catchall(hir_pat) {
catchall = Some(pat.span);
}
}
}
seen
}
fn check_not_useful(
cx: &mut MatchCheckCtxt<'_, 'tcx>,
fn check_not_useful<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
ty: Ty<'tcx>,
matrix: &Matrix<'_, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
hir_id: HirId,
) -> Result<(), Vec<super::Pat<'tcx>>> {
let wild_pattern = super::Pat::wildcard_from_ty(ty);
match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) {
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
UsefulWithWitness(pats) => Err(if pats.is_empty() {
vec![wild_pattern]
bug!("Exhaustiveness check returned no witnesses")
} else {
pats.into_iter().map(|w| w.single_pattern()).collect()
}),
Useful => bug!(),
Useful(_) => bug!(),
}
}
fn check_exhaustive<'tcx>(
cx: &mut MatchCheckCtxt<'_, 'tcx>,
fn check_exhaustive<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
scrut_ty: Ty<'tcx>,
sp: Span,
matrix: &Matrix<'_, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
hir_id: HirId,
) {
let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {

View file

@ -6,35 +6,40 @@
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
fn main() {
// Get the fatal error out of the way
match (0u8,) {
match (0,) {
(0 | _,) => {}
//~^ ERROR or-patterns are not fully implemented yet
}
match (0u8,) {
match (0,) {
(1 | 2,) => {}
_ => {}
}
match (0u8,) {
(1 | 1,) => {} // FIXME(or_patterns): redundancy not detected for now.
_ => {}
}
match (0u8, 0u8) {
match (0, 0) {
(1 | 2, 3 | 4) => {}
(1, 2) => {}
(2, 1) => {}
(3, 1) => {}
_ => {}
}
match (Some(0u8),) {
(None | Some(0 | 1),) => {}
(Some(2..=255),) => {}
}
match ((0u8,),) {
match ((0,),) {
((0 | 1,) | (2 | 3,),) => {},
((_,),) => {},
}
match (&[0u8][..],) {
([] | [0 | 1..=255] | [_, ..],) => {},
}
match ((0, 0),) {
((0, 0) | (0, 1),) => {}
_ => {}
}
match ((0, 0),) {
((0, 0) | (1, 0),) => {}
_ => {}
}
}

View file

@ -48,4 +48,32 @@ fn main() {
((1..=4,),) => {}, //~ ERROR unreachable pattern
_ => {},
}
match (0,) {
(1
| 1,) => {} //~ ERROR unreachable
_ => {}
}
match [0; 2] {
[0
| 0 //~ ERROR unreachable
, 0
| 0] => {} //~ ERROR unreachable
_ => {}
}
match &[][..] {
[0] => {}
[0, _] => {}
[0, _, _] => {}
[1, ..] => {}
[1 //~ ERROR unreachable
| 2, ..] => {}
_ => {}
}
match Some(0) {
Some(0) => {}
Some(0 //~ ERROR unreachable
| 1) => {}
_ => {}
}
}

View file

@ -70,11 +70,41 @@ error: unreachable pattern
LL | ((1..=4,),) => {},
| ^^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:54:12
|
LL | | 1,) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:61:15
|
LL | | 0] => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:59:15
|
LL | | 0
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:69:10
|
LL | [1
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:75:14
|
LL | Some(0
| ^
error: or-patterns are not fully implemented yet
--> $DIR/exhaustiveness-unreachable-pattern.rs:10:10
|
LL | (0 | _,) => {}
| ^^^^^
error: aborting due to 12 previous errors
error: aborting due to 17 previous errors

View file

@ -0,0 +1,56 @@
#![deny(unreachable_patterns)]
fn main() {
while let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
if let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
match 0u8 {
0
| 0 => {} //~ ERROR unreachable pattern
_ => {}
}
match Some(0u8) {
Some(0)
| Some(0) => {} //~ ERROR unreachable pattern
_ => {}
}
match (0u8, 0u8) {
(0, _) | (_, 0) => {}
(0, 0) => {} //~ ERROR unreachable pattern
(1, 1) => {}
_ => {}
}
match (0u8, 0u8) {
(0, 1) | (2, 3) => {}
(0, 3) => {}
(2, 1) => {}
_ => {}
}
match (0u8, 0u8) {
(_, 0) | (_, 1) => {}
_ => {}
}
match (0u8, 0u8) {
(0, _) | (1, _) => {}
_ => {}
}
match Some(0u8) {
None | Some(_) => {}
_ => {} //~ ERROR unreachable pattern
}
match Some(0u8) {
None | Some(_) => {}
Some(_) => {} //~ ERROR unreachable pattern
None => {} //~ ERROR unreachable pattern
}
match Some(0u8) {
Some(_) => {}
None => {}
None | Some(_) => {} //~ ERROR unreachable pattern
}
match 0u8 {
1 | 2 => {},
1..=2 => {}, //~ ERROR unreachable pattern
_ => {},
}
}

View file

@ -0,0 +1,68 @@
error: unreachable pattern
--> $DIR/top-level-alternation.rs:4:23
|
LL | while let 0..=2 | 1 = 0 {}
| ^
|
note: lint level defined here
--> $DIR/top-level-alternation.rs:1:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:5:20
|
LL | if let 0..=2 | 1 = 0 {}
| ^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:9:15
|
LL | | 0 => {}
| ^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:14:15
|
LL | | Some(0) => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:19:9
|
LL | (0, 0) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:39:9
|
LL | _ => {}
| ^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:43:9
|
LL | Some(_) => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:44:9
|
LL | None => {}
| ^^^^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:49:9
|
LL | None | Some(_) => {}
| ^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/top-level-alternation.rs:53:9
|
LL | 1..=2 => {},
| ^^^^^
error: aborting due to 10 previous errors