blob: 2264b560791aa87d33f830465e7cb0e1e61c39fc [file] [log] [blame]
#![warn(clippy::collapsible_match)]
#![allow(
clippy::equatable_if_let,
clippy::needless_return,
clippy::no_effect,
clippy::single_match,
clippy::uninlined_format_args,
clippy::let_unit_value
)]
fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>) {
// match without block
match res_opt {
Ok(val) => match val {
//~^ ERROR: this `match` can be collapsed into the outer `match`
Some(n) => foo(n),
_ => return,
},
_ => return,
}
// match with block
match res_opt {
Ok(val) => match val {
//~^ ERROR: this `match` can be collapsed into the outer `match`
Some(n) => foo(n),
_ => return,
},
_ => return,
}
// if let, if let
if let Ok(val) = res_opt {
if let Some(n) = val {
//~^ ERROR: this `if let` can be collapsed into the outer `if let`
take(n);
}
}
// if let else, if let else
if let Ok(val) = res_opt {
if let Some(n) = val {
//~^ ERROR: this `if let` can be collapsed into the outer `if let`
take(n);
} else {
return;
}
} else {
return;
}
// if let, match
if let Ok(val) = res_opt {
match val {
//~^ ERROR: this `match` can be collapsed into the outer `if let`
Some(n) => foo(n),
_ => (),
}
}
// match, if let
match res_opt {
Ok(val) => {
if let Some(n) = val {
//~^ ERROR: this `if let` can be collapsed into the outer `match`
take(n);
}
},
_ => {},
}
// if let else, match
if let Ok(val) = res_opt {
match val {
//~^ ERROR: this `match` can be collapsed into the outer `if let`
Some(n) => foo(n),
_ => return,
}
} else {
return;
}
// match, if let else
match res_opt {
Ok(val) => {
if let Some(n) = val {
//~^ ERROR: this `if let` can be collapsed into the outer `match`
take(n);
} else {
return;
}
},
_ => return,
}
// None in inner match same as outer wild branch
match res_opt {
Ok(val) => match val {
//~^ ERROR: this `match` can be collapsed into the outer `match`
Some(n) => foo(n),
None => return,
},
_ => return,
}
// None in outer match same as inner wild branch
match opt_opt {
Some(val) => match val {
//~^ ERROR: this `match` can be collapsed into the outer `match`
Some(n) => foo(n),
_ => return,
},
None => return,
}
}
fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u32, String>, String>) {
while let Some(x) = make() {
if let Some(1) = x {
todo!();
}
}
// no wild pattern in outer match
match res_opt {
Ok(val) => match val {
Some(n) => foo(n),
_ => return,
},
Err(_) => return,
}
// inner branch is not wild or None
match res_res {
Ok(val) => match val {
Ok(n) => foo(n),
Err(_) => return,
},
_ => return,
}
// statement before inner match
match res_opt {
Ok(val) => {
"hi buddy";
match val {
Some(n) => foo(n),
_ => return,
}
},
_ => return,
}
// statement after inner match
match res_opt {
Ok(val) => {
match val {
Some(n) => foo(n),
_ => return,
}
"hi buddy";
},
_ => return,
}
// wild branches do not match
match res_opt {
Ok(val) => match val {
Some(n) => foo(n),
_ => {
"sup";
return;
},
},
_ => return,
}
// binding used in if guard
match res_opt {
Ok(val) if val.is_some() => match val {
Some(n) => foo(n),
_ => return,
},
_ => return,
}
// binding used in inner match body
match res_opt {
Ok(val) => match val {
Some(_) => take(val),
_ => return,
},
_ => return,
}
// if guard on inner match
{
match res_opt {
Ok(val) => match val {
Some(n) if make() => foo(n),
_ => return,
},
_ => return,
}
match res_opt {
Ok(val) => match val {
_ => make(),
_ if make() => return,
},
_ => return,
}
}
// differing macro contexts
{
macro_rules! mac {
($val:ident) => {
match $val {
Some(n) => foo(n),
_ => return,
}
};
}
match res_opt {
Ok(val) => mac!(val),
_ => return,
}
}
// OR pattern
enum E<T> {
A(T),
B(T),
C(T),
};
match make::<E<Option<u32>>>() {
E::A(val) | E::B(val) => match val {
Some(n) => foo(n),
_ => return,
},
_ => return,
}
#[clippy::msrv = "1.52.0"]
let _ = match make::<Option<E<u32>>>() {
Some(val) => match val {
E::A(val) | E::B(val) => foo(val),
_ => return,
},
_ => return,
};
#[clippy::msrv = "1.53.0"]
let _ = match make::<Option<E<u32>>>() {
Some(val) => match val {
E::A(val) | E::B(val) => foo(val),
_ => return,
},
_ => return,
};
if let Ok(val) = res_opt {
if let Some(n) = val {
let _ = || {
// usage in closure
println!("{:?}", val);
};
}
}
let _: &dyn std::any::Any = match &Some(Some(1)) {
Some(e) => match e {
Some(e) => e,
e => e,
},
// else branch looks the same but the binding is different
e => e,
};
}
pub enum Issue9647 {
A { a: Option<Option<u8>>, b: () },
B,
}
pub fn test_1(x: Issue9647) {
if let Issue9647::A { a, .. } = x {
if let Some(u) = a {
//~^ ERROR: this `if let` can be collapsed into the outer `if let`
println!("{u:?}")
}
}
}
pub fn test_2(x: Issue9647) {
if let Issue9647::A { a: Some(a), .. } = x {
if let Some(u) = a {
//~^ ERROR: this `if let` can be collapsed into the outer `if let`
println!("{u}")
}
}
}
fn make<T>() -> T {
unimplemented!()
}
fn foo<T, U>(t: T) -> U {
unimplemented!()
}
fn take<T>(t: T) {}
fn main() {}