Skip to content

Commit fca1f9a

Browse files
committed
Auto merge of rust-lang#11106 - syvb:literal_unwrap_ice, r=dswij
[`unnecessary_literal_unwrap`]: Fix ICE on None.unwrap_or_default() Fixes rust-lang#11099 Fixes rust-lang#11064 I'm running into rust-lang#11099 (cc `@y21)` on my Rust codebase. Clippy ICEs on this code when evaluating the `unnecessary_literal_unwrap` lint: ```rust fn main() { let val1: u8 = None.unwrap_or_default(); } ``` This fixes that ICE and adds an message specifically for that case: ``` error: used `unwrap_or_default()` on `None` value --> $DIR/unnecessary_literal_unwrap.rs:26:5 | LL | None::<String>.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` ``` This PR also fixes the same ICE with `None.unwrap_or_else` (by giving the generic error message for the lint in that case). changelog: Fix ICE in `unnecessary_literal_unwrap` on `None.unwrap_or_default()`
2 parents fbe292e + 8d258c1 commit fca1f9a

6 files changed

+300
-125
lines changed

clippy_lints/src/methods/unnecessary_literal_unwrap.rs

+31
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath};
33
use rustc_errors::Applicability;
44
use rustc_hir as hir;
55
use rustc_lint::LateContext;
6+
use rustc_middle::ty;
7+
use rustc_middle::ty::print::with_forced_trimmed_paths;
68

79
use super::UNNECESSARY_LITERAL_UNWRAP;
810

@@ -22,6 +24,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
2224
}
2325
}
2426

27+
#[expect(clippy::too_many_lines)]
2528
pub(super) fn check(
2629
cx: &LateContext<'_>,
2730
expr: &hir::Expr<'_>,
@@ -84,6 +87,34 @@ pub(super) fn check(
8487
}
8588
Some(suggs)
8689
},
90+
("None", "unwrap_or_default", _) => {
91+
let ty = cx.typeck_results().expr_ty(expr);
92+
let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
93+
with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
94+
} else {
95+
"Default".to_string()
96+
};
97+
Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
98+
},
99+
("None", "unwrap_or", _) => Some(vec![
100+
(expr.span.with_hi(args[0].span.lo()), String::new()),
101+
(expr.span.with_lo(args[0].span.hi()), String::new()),
102+
]),
103+
("None", "unwrap_or_else", _) => match args[0].kind {
104+
hir::ExprKind::Closure(hir::Closure {
105+
fn_decl:
106+
hir::FnDecl {
107+
output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }),
108+
..
109+
},
110+
..
111+
}) => Some(vec![
112+
(expr.span.with_hi(span.hi()), String::new()),
113+
(expr.span.with_lo(args[0].span.hi()), String::new()),
114+
]),
115+
_ => None,
116+
},
117+
_ if call_args.is_empty() => None,
87118
(_, _, Some(_)) => None,
88119
("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
89120
(

tests/ui/unnecessary_literal_unwrap.fixed

+11
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
1616
1;
1717
}
1818

19+
#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
1920
fn unwrap_option_none() {
2021
let _val = panic!();
2122
let _val = panic!("this always happens");
23+
let _val: String = String::default();
24+
let _val: u16 = 234;
25+
let _val: u16 = 234;
26+
let _val: u16 = { 234 };
27+
let _val: u16 = { 234 };
2228

2329
panic!();
2430
panic!("this always happens");
31+
String::default();
32+
234;
33+
234;
34+
{ 234 };
35+
{ 234 };
2536
}
2637

2738
fn unwrap_result_ok() {

tests/ui/unnecessary_literal_unwrap.rs

+11
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
1616
Some(1).expect("this never happens");
1717
}
1818

19+
#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
1920
fn unwrap_option_none() {
2021
let _val = None::<()>.unwrap();
2122
let _val = None::<()>.expect("this always happens");
23+
let _val: String = None.unwrap_or_default();
24+
let _val: u16 = None.unwrap_or(234);
25+
let _val: u16 = None.unwrap_or_else(|| 234);
26+
let _val: u16 = None.unwrap_or_else(|| { 234 });
27+
let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
2228

2329
None::<()>.unwrap();
2430
None::<()>.expect("this always happens");
31+
None::<String>.unwrap_or_default();
32+
None::<u16>.unwrap_or(234);
33+
None::<u16>.unwrap_or_else(|| 234);
34+
None::<u16>.unwrap_or_else(|| { 234 });
35+
None::<u16>.unwrap_or_else(|| -> u16 { 234 });
2536
}
2637

2738
fn unwrap_result_ok() {

0 commit comments

Comments
 (0)