Multiple fixes to FNs of question_mark (#16769)

Closes rust-lang/rust-clippy#16751

changelog: [`question_mark`] fix FN for manual unwrap with `if let` or
`match`
changelog: [`question_mark`] fix FN when the match scrutinee is behind
reference
changelog: [`question_mark`] fix FN when match binding is behind `ref`
or `mut`
This commit is contained in:
dswij
2026-04-04 15:56:33 +00:00
committed by GitHub
12 changed files with 394 additions and 150 deletions
+17 -21
View File
@@ -87,28 +87,24 @@ pub(super) fn check_with<'tcx, F>(
None => "",
};
match can_move_expr_to_closure(cx, some_expr.expr) {
Some(captures) => {
// Check if captures the closure will need conflict with borrows made in the scrutinee.
// TODO: check all the references made in the scrutinee expression. This will require interacting
// with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
if let Some(binding_ref_mutability) = binding_ref {
let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
_ => None,
});
if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
match captures.get(l) {
Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None,
Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
return None;
},
Some(CaptureKind::Ref(Mutability::Not)) | None => (),
}
}
let captures = can_move_expr_to_closure(cx, some_expr.expr)?;
// Check if captures the closure will need conflict with borrows made in the scrutinee.
// TODO: check all the references made in the scrutinee expression. This will require interacting
// with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
if let Some(binding_ref_mutability) = binding_ref {
let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
_ => None,
});
if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
match captures.get(l) {
Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None,
Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
return None;
},
Some(CaptureKind::Ref(Mutability::Not)) | None => (),
}
},
None => return None,
}
}
let mut app = Applicability::MachineApplicable;
@@ -35,13 +35,12 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() {
// For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..)
len.try_to_target_usize(cx.tcx).map(u128::from)
} else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) {
} else {
let args = VecArgs::hir(cx, expr_or_init(cx, recv))?;
match args {
VecArgs::Vec(vec) => vec.len().try_into().ok(),
VecArgs::Repeat(_, len) => expr_as_u128(cx, len),
}
} else {
None
}
},
Some(sym::IterEmpty) => Some(0),
+116 -47
View File
@@ -2,10 +2,10 @@
use crate::question_mark_used::QUESTION_MARK_USED;
use clippy_config::Conf;
use clippy_config::types::MatchLintBehaviour;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::usage::local_used_after_expr;
@@ -24,6 +24,7 @@
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@@ -222,13 +223,11 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
// We only need to check `if let Some(x) = option` not `if let None = option`,
// because the later one will be suggested as `if option.is_none()` thus causing conflict.
res.ctor_parent(cx).is_lang_item(cx, OptionSome)
&& if_else.is_some()
&& expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, None)
&& matches!(if_else, Some(inner) if expr_return_none_or_err(smbl, cx, inner, let_expr, None))
},
sym::Result => {
(res.ctor_parent(cx).is_lang_item(cx, ResultOk)
&& if_else.is_some()
&& expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym)))
&& matches!(if_else, Some(inner) if expr_return_none_or_err(smbl, cx, inner, let_expr, Some(let_pat_sym))))
|| res.ctor_parent(cx).is_lang_item(cx, ResultErr)
&& expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym))
&& if_else.is_none()
@@ -328,7 +327,7 @@ enum TryMode {
}
fn find_try_mode<'tcx>(cx: &LateContext<'tcx>, scrutinee: &Expr<'tcx>) -> Option<TryMode> {
let scrutinee_ty = cx.typeck_results().expr_ty_adjusted(scrutinee);
let scrutinee_ty = cx.typeck_results().expr_ty_adjusted(scrutinee).peel_refs();
let ty::Adt(scrutinee_adt_def, _) = scrutinee_ty.kind() else {
return None;
};
@@ -360,14 +359,18 @@ fn extract_ctor_call<'a, 'tcx>(
// Extracts the local ID of a plain `val` pattern.
fn extract_binding_pat(pat: &Pat<'_>) -> Option<HirId> {
if let PatKind::Binding(BindingMode::NONE, binding, _, None) = pat.kind {
if let PatKind::Binding(_, binding, _, None) = pat.kind {
Some(binding)
} else {
None
}
}
fn check_arm_is_some_or_ok<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool {
fn check_arm_is_some_or_ok<'tcx>(
cx: &LateContext<'tcx>,
mode: TryMode,
arm: &Arm<'tcx>,
) -> Option<IfLetOrMatchThen<'tcx>> {
let happy_ctor = match mode {
TryMode::Result => ResultOk,
TryMode::Option => OptionSome,
@@ -378,13 +381,16 @@ fn check_arm_is_some_or_ok<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Ar
&& let Some(val_binding) = extract_ctor_call(cx, happy_ctor, arm.pat)
// Extract out `val`
&& let Some(binding) = extract_binding_pat(val_binding)
// Check body is just `=> val`
&& peel_blocks(arm.body).res_local_id() == Some(binding)
{
true
} else {
false
// Check body is just `=> val`
return Some(if peel_blocks(arm.body).res_local_id() == Some(binding) {
IfLetOrMatchThen::DirectReturn
} else {
IfLetOrMatchThen::ManualUnwrap(val_binding.span, arm.body)
});
}
None
}
fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool {
@@ -439,9 +445,23 @@ fn is_local_or_local_into(cx: &LateContext<'_>, expr: &Expr<'_>, val: HirId) ->
}
}
fn check_arms_are_try<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm1: &Arm<'tcx>, arm2: &Arm<'tcx>) -> bool {
(check_arm_is_some_or_ok(cx, mode, arm1) && check_arm_is_none_or_err(cx, mode, arm2))
|| (check_arm_is_some_or_ok(cx, mode, arm2) && check_arm_is_none_or_err(cx, mode, arm1))
fn check_arms_are_try<'tcx>(
cx: &LateContext<'tcx>,
mode: TryMode,
arm1: &Arm<'tcx>,
arm2: &Arm<'tcx>,
) -> Option<IfLetOrMatchThen<'tcx>> {
(check_arm_is_none_or_err(cx, mode, arm2).then(|| check_arm_is_some_or_ok(cx, mode, arm1)))
.or_else(|| check_arm_is_none_or_err(cx, mode, arm1).then(|| check_arm_is_some_or_ok(cx, mode, arm2)))
.flatten()
}
#[derive(Debug)]
enum IfLetOrMatchThen<'tcx> {
/// Return the binding from an if let or match arm as is.
DirectReturn,
/// Working on the binding from an if let or match arm as if it comes from a `?`.
ManualUnwrap(Span, &'tcx Expr<'tcx>),
}
fn check_if_try_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
@@ -449,19 +469,47 @@ fn check_if_try_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
&& !expr.span.from_expansion()
&& let Some(mode) = find_try_mode(cx, scrutinee)
&& !span_contains_cfg(cx, expr.span)
&& check_arms_are_try(cx, mode, arm1, arm2)
&& let Some(if_let_or_match_then) = check_arms_are_try(cx, mode, arm1, arm2)
{
let mut applicability = Applicability::MachineApplicable;
let snippet = snippet_with_applicability(cx, scrutinee.span.source_callsite(), "..", &mut applicability);
span_lint_and_sugg(
span_lint_and_then(
cx,
QUESTION_MARK,
expr.span,
"this `match` expression can be replaced with `?`",
"try instead",
snippet.into_owned() + "?",
applicability,
|diag| {
let mut applicability = Applicability::MachineApplicable;
let scrutinee_snippet =
snippet_with_applicability(cx, scrutinee.span.source_callsite(), "..", &mut applicability);
match if_let_or_match_then {
IfLetOrMatchThen::DirectReturn => {
diag.span_suggestion(
expr.span,
"try instead",
scrutinee_snippet.into_owned() + "?",
applicability,
);
},
IfLetOrMatchThen::ManualUnwrap(binding_span, arm_body) => {
let indent = indent_of(cx, expr.span).unwrap_or_default();
let arm_body_snippet = snippet_with_applicability(cx, arm_body.span, "..", &mut applicability);
let mut sugg = reindent_multiline(&arm_body_snippet, true, Some(indent));
let binding_snippet = snippet_with_applicability(cx, binding_span, "..", &mut applicability);
let inner_indent = " ".repeat(indent + 4);
if matches!(arm_body.kind, ExprKind::Block(..)) {
sugg.insert_str(
1,
&format!("\n{inner_indent}let {binding_snippet} = {scrutinee_snippet}?;"),
);
} else {
let outer_indent = " ".repeat(indent);
sugg = format!(
"{{\n{inner_indent}let {binding_snippet} = {scrutinee_snippet}?;\n{inner_indent}{sugg}\n{outer_indent}}}"
);
}
diag.span_suggestion(expr.span, "try instead", sugg, applicability);
},
}
},
);
}
}
@@ -486,8 +534,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
if_then,
if_else,
)
&& ((is_early_return(sym::Option, cx, &if_block) && peel_blocks(if_then).res_local_id() == Some(bind_id))
|| is_early_return(sym::Result, cx, &if_block))
&& let is_option_early_return = is_early_return(sym::Option, cx, &if_block)
&& (is_option_early_return || is_early_return(sym::Result, cx, &if_block))
&& if_else
.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e)))
.is_none_or(|e| !e)
@@ -499,32 +547,53 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
return;
}
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
let parent = cx.tcx.parent_hir_node(expr.hir_id);
let requires_semi = matches!(parent, Node::Stmt(_)) || cx.typeck_results().expr_ty(expr).is_unit();
let method_call_str = match by_ref {
ByRef::Yes(_, Mutability::Mut) => ".as_mut()",
ByRef::Yes(_, Mutability::Not) => ".as_ref()",
ByRef::No => "",
};
let mut sugg = format!(
"{receiver_str}{method_call_str}?{}",
if requires_semi { ";" } else { "" }
);
if is_else_clause(cx.tcx, expr) || (requires_semi && !matches!(parent, Node::Stmt(_) | Node::Block(_))) {
sugg = format!("{{ {sugg} }}");
// Leave `if let Some(x) = opt { .. } else { None }` to `needless_match` or `manual_map_option`.
if is_option_early_return
&& if_else.is_some_and(|else_| !matches!(peel_blocks_with_stmt(else_).kind, ExprKind::Ret(_)))
{
return;
}
span_lint_and_sugg(
span_lint_and_then(
cx,
QUESTION_MARK,
expr.span,
"this block may be rewritten with the `?` operator",
"replace it with",
sugg,
applicability,
|diag| {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
if !is_option_early_return || peel_blocks(if_then).res_local_id() == Some(bind_id) {
let parent = cx.tcx.parent_hir_node(expr.hir_id);
let requires_semi = matches!(parent, Node::Stmt(_)) || cx.typeck_results().expr_ty(expr).is_unit();
let method_call_str = match by_ref {
ByRef::Yes(_, Mutability::Mut) => ".as_mut()",
ByRef::Yes(_, Mutability::Not) => ".as_ref()",
ByRef::No => "",
};
let mut sugg = format!(
"{receiver_str}{method_call_str}?{}",
if requires_semi { ";" } else { "" }
);
if is_else_clause(cx.tcx, expr)
|| (requires_semi && !matches!(parent, Node::Stmt(_) | Node::Block(_)))
{
sugg = format!("{{ {sugg} }}");
}
diag.span_suggestion(expr.span, "replace it with", sugg, applicability);
return;
}
let mut sugg = snippet_with_applicability(cx, if_then.span, "..", &mut applicability).into_owned();
let binding_snippet = snippet_with_applicability(cx, field.span, "..", &mut applicability);
let indent = indent_of(cx, expr.span).unwrap_or_default();
sugg.insert_str(
1,
&format!("\n{}let {binding_snippet} = {receiver_str}?;", " ".repeat(indent + 4)),
);
diag.span_suggestion(expr.span, "replace it with", sugg, applicability);
},
);
}
}
+8 -11
View File
@@ -308,18 +308,15 @@ fn extract_local(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> Option<Local> {
field_indices.push(field_idx);
expr = recv;
}
if let Some(local_id) = expr.res_local_id() {
if field_indices.is_empty() {
Some(Local::Pure { local_id })
} else {
Some(Local::WithFieldAccess {
local_id,
field_indices,
span,
})
}
let local_id = expr.res_local_id()?;
if field_indices.is_empty() {
Some(Local::Pure { local_id })
} else {
None
Some(Local::WithFieldAccess {
local_id,
field_indices,
span,
})
}
}
+8 -11
View File
@@ -1240,17 +1240,14 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
/// This does not look for impls in the type's `Deref::Target` type.
/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
cx.tcx.inherent_impls(ty_did).iter().find_map(|&did| {
cx.tcx
.associated_items(did)
.filter_by_name_unhygienic(method_name)
.next()
.filter(|item| item.tag() == AssocTag::Fn)
})
} else {
None
}
let ty_did = ty.ty_adt_def().map(AdtDef::did)?;
cx.tcx.inherent_impls(ty_did).iter().find_map(|&did| {
cx.tcx
.associated_items(did)
.filter_by_name_unhygienic(method_name)
.next()
.filter(|item| item.tag() == AssocTag::Fn)
})
}
/// Gets the type of a field by name.
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(clippy::manual_filter)]
#![allow(unused_variables, dead_code, clippy::useless_vec)]
#![allow(unused_variables, clippy::question_mark, clippy::useless_vec)]
fn main() {
Some(0).filter(|&x| x <= 0);
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(clippy::manual_filter)]
#![allow(unused_variables, dead_code, clippy::useless_vec)]
#![allow(unused_variables, clippy::question_mark, clippy::useless_vec)]
fn main() {
match Some(0) {
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(clippy::needless_match)]
#![allow(clippy::manual_map)]
#![allow(clippy::manual_map, clippy::question_mark)]
#![allow(dead_code)]
#![allow(unused)]
#[derive(Clone, Copy)]
+1 -1
View File
@@ -1,5 +1,5 @@
#![warn(clippy::needless_match)]
#![allow(clippy::manual_map)]
#![allow(clippy::manual_map, clippy::question_mark)]
#![allow(dead_code)]
#![allow(unused)]
#[derive(Clone, Copy)]
+38 -11
View File
@@ -1,5 +1,10 @@
#![feature(try_blocks)]
#![allow(clippy::unnecessary_wraps, clippy::no_effect)]
#![allow(
clippy::unnecessary_wraps,
clippy::no_effect,
clippy::needless_return,
clippy::toplevel_ref_arg
)]
use std::sync::MutexGuard;
@@ -110,10 +115,7 @@ fn func() -> Option<i32> {
let _val = f()?;
let s: &str = match &Some(String::new()) {
Some(v) => v,
None => return None,
};
let s: &str = &Some(String::new())?;
f()?;
@@ -124,12 +126,10 @@ fn func() -> Option<i32> {
None => return opt_none!(),
};
match f() {
Some(val) => {
println!("{val}");
val
},
None => return None,
{
let val = f()?;
println!("{val}");
val
};
Some(0)
@@ -537,3 +537,30 @@ fn issue16654() -> Result<(), i32> {
Ok(())
}
#[rustfmt::skip]
fn issue16751(mut v: Option<usize>) -> Option<usize> {
let _ = {
let n = &v?;
println!("{n}");
Some(42)
};
let _ = {
let ref mut n = v?;
println!("{n}");
Some(42)
};
let _ = {
let ref mut n = v?;
//~^ question_mark
println!("{n}");
42
};
{
let n = v?;
if n > 10 { Some(42) } else { None }
}
}
+43 -1
View File
@@ -1,5 +1,10 @@
#![feature(try_blocks)]
#![allow(clippy::unnecessary_wraps, clippy::no_effect)]
#![allow(
clippy::unnecessary_wraps,
clippy::no_effect,
clippy::needless_return,
clippy::toplevel_ref_arg
)]
use std::sync::MutexGuard;
@@ -156,6 +161,7 @@ fn f() -> Option<String> {
};
let s: &str = match &Some(String::new()) {
//~^ question_mark
Some(v) => v,
None => return None,
};
@@ -178,6 +184,7 @@ fn f() -> Option<String> {
};
match f() {
//~^ question_mark
Some(val) => {
println!("{val}");
val
@@ -668,3 +675,38 @@ fn issue16654() -> Result<(), i32> {
Ok(())
}
#[rustfmt::skip]
fn issue16751(mut v: Option<usize>) -> Option<usize> {
let _ = match &v {
//~^ question_mark
Some(n) => {
println!("{n}");
Some(42)
}
None => return None,
};
let _ = match v {
//~^ question_mark
Some(ref mut n) => {
println!("{n}");
Some(42)
}
None => return None,
};
let _ = if let Some(ref mut n) = v {
//~^ question_mark
println!("{n}");
42
} else {
return None;
};
match v {
//~^ question_mark
Some(n) => if n > 10 { Some(42) } else { None },
None => return None,
}
}
+158 -41
View File
@@ -1,5 +1,5 @@
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:7:5
--> tests/ui/question_mark.rs:12:5
|
LL | / if a.is_none() {
LL | |
@@ -11,7 +11,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::question_mark)]`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:53:9
--> tests/ui/question_mark.rs:58:9
|
LL | / if (self.opt).is_none() {
LL | |
@@ -20,7 +20,7 @@ LL | | }
| |_________^ help: replace it with: `(self.opt)?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:58:9
--> tests/ui/question_mark.rs:63:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -29,7 +29,7 @@ LL | | }
| |_________^ help: replace it with: `self.opt?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:63:17
--> tests/ui/question_mark.rs:68:17
|
LL | let _ = if self.opt.is_none() {
| _________________^
@@ -41,7 +41,7 @@ LL | | };
| |_________^ help: replace it with: `Some(self.opt?)`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:70:17
--> tests/ui/question_mark.rs:75:17
|
LL | let _ = if let Some(x) = self.opt {
| _________________^
@@ -53,7 +53,7 @@ LL | | };
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:88:9
--> tests/ui/question_mark.rs:93:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -62,7 +62,7 @@ LL | | }
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:97:9
--> tests/ui/question_mark.rs:102:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -71,7 +71,7 @@ LL | | }
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:106:9
--> tests/ui/question_mark.rs:111:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -80,7 +80,7 @@ LL | | }
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:114:26
--> tests/ui/question_mark.rs:119:26
|
LL | let v: &Vec<_> = if let Some(ref v) = self.opt {
| __________________________^
@@ -92,7 +92,7 @@ LL | | };
| |_________^ help: replace it with: `self.opt.as_ref()?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:125:17
--> tests/ui/question_mark.rs:130:17
|
LL | let v = if let Some(v) = self.opt {
| _________________^
@@ -104,7 +104,7 @@ LL | | };
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:147:5
--> tests/ui/question_mark.rs:152:5
|
LL | / if f().is_none() {
LL | |
@@ -113,7 +113,7 @@ LL | | }
| |_____^ help: replace it with: `f()?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:152:16
--> tests/ui/question_mark.rs:157:16
|
LL | let _val = match f() {
| ________________^
@@ -124,7 +124,18 @@ LL | | };
| |_____^ help: try instead: `f()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:163:5
--> tests/ui/question_mark.rs:163:19
|
LL | let s: &str = match &Some(String::new()) {
| ___________________^
LL | |
LL | | Some(v) => v,
LL | | None => return None,
LL | | };
| |_____^ help: try instead: `&Some(String::new())?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:169:5
|
LL | / match f() {
LL | |
@@ -134,7 +145,7 @@ LL | | };
| |_____^ help: try instead: `f()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:169:5
--> tests/ui/question_mark.rs:175:5
|
LL | / match opt_none!() {
LL | |
@@ -143,14 +154,35 @@ LL | | None => return None,
LL | | };
| |_____^ help: try instead: `opt_none!()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:186:5
|
LL | / match f() {
LL | |
LL | | Some(val) => {
LL | | println!("{val}");
... |
LL | | None => return None,
LL | | };
| |_____^
|
help: try instead
|
LL ~ {
LL + let val = f()?;
LL + println!("{val}");
LL + val
LL ~ };
|
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:196:13
--> tests/ui/question_mark.rs:203:13
|
LL | let _ = if let Ok(x) = x { x } else { return x };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:199:5
--> tests/ui/question_mark.rs:206:5
|
LL | / if x.is_err() {
LL | |
@@ -159,7 +191,7 @@ LL | | }
| |_____^ help: replace it with: `x?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:204:16
--> tests/ui/question_mark.rs:211:16
|
LL | let _val = match func_returning_result() {
| ________________^
@@ -170,7 +202,7 @@ LL | | };
| |_____^ help: try instead: `func_returning_result()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:210:5
--> tests/ui/question_mark.rs:217:5
|
LL | / match func_returning_result() {
LL | |
@@ -180,7 +212,7 @@ LL | | };
| |_____^ help: try instead: `func_returning_result()?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:302:5
--> tests/ui/question_mark.rs:309:5
|
LL | / if let Err(err) = func_returning_result() {
LL | |
@@ -189,7 +221,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:310:5
--> tests/ui/question_mark.rs:317:5
|
LL | / if let Err(err) = func_returning_result() {
LL | |
@@ -198,7 +230,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:393:13
--> tests/ui/question_mark.rs:400:13
|
LL | / if a.is_none() {
LL | |
@@ -208,7 +240,7 @@ LL | | }
| |_____________^ help: replace it with: `a?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:454:5
--> tests/ui/question_mark.rs:461:5
|
LL | / let Some(v) = bar.foo.owned.clone() else {
LL | | return None;
@@ -216,7 +248,7 @@ LL | | };
| |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:469:5
--> tests/ui/question_mark.rs:476:5
|
LL | / let Some(ref x) = foo.opt_x else {
LL | | return None;
@@ -224,7 +256,7 @@ LL | | };
| |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:479:5
--> tests/ui/question_mark.rs:486:5
|
LL | / let Some(ref mut x) = foo.opt_x else {
LL | | return None;
@@ -232,7 +264,7 @@ LL | | };
| |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:490:5
--> tests/ui/question_mark.rs:497:5
|
LL | / let Some(ref x @ ref y) = foo.opt_x else {
LL | | return None;
@@ -240,7 +272,7 @@ LL | | };
| |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:494:5
--> tests/ui/question_mark.rs:501:5
|
LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else {
LL | | return None;
@@ -248,7 +280,7 @@ LL | | };
| |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:498:5
--> tests/ui/question_mark.rs:505:5
|
LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
LL | | return None;
@@ -256,7 +288,7 @@ LL | | };
| |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:520:5
--> tests/ui/question_mark.rs:527:5
|
LL | / if arg.is_none() {
LL | |
@@ -265,7 +297,7 @@ LL | | }
| |_____^ help: replace it with: `arg?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:524:15
--> tests/ui/question_mark.rs:531:15
|
LL | let val = match arg {
| _______________^
@@ -276,7 +308,7 @@ LL | | };
| |_____^ help: try instead: `arg?`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:534:5
--> tests/ui/question_mark.rs:541:5
|
LL | / let Some(a) = *a else {
LL | | return None;
@@ -284,7 +316,7 @@ LL | | };
| |______^ help: replace it with: `let a = (*a)?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:566:5
--> tests/ui/question_mark.rs:573:5
|
LL | / match some_result {
LL | |
@@ -294,7 +326,7 @@ LL | | };
| |_____^ help: try instead: `some_result?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:572:5
--> tests/ui/question_mark.rs:579:5
|
LL | / match some_result {
LL | |
@@ -304,7 +336,7 @@ LL | | };
| |_____^ help: try instead: `some_result?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:578:5
--> tests/ui/question_mark.rs:585:5
|
LL | / match some_result {
LL | |
@@ -314,7 +346,7 @@ LL | | };
| |_____^ help: try instead: `some_result?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:596:17
--> tests/ui/question_mark.rs:603:17
|
LL | let x = match result {
| _________________^
@@ -325,7 +357,7 @@ LL | | };
| |_________^ help: try instead: `result?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:609:9
--> tests/ui/question_mark.rs:616:9
|
LL | / if let Err(reason) = result {
LL | |
@@ -334,7 +366,7 @@ LL | | }
| |_________^ help: replace it with: `result?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:626:5
--> tests/ui/question_mark.rs:633:5
|
LL | / let Some(x) = test_expr!(42) else {
LL | | return None;
@@ -342,7 +374,7 @@ LL | | };
| |______^ help: replace it with: `let x = test_expr!(42)?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:632:5
--> tests/ui/question_mark.rs:639:5
|
LL | / if test_expr!(42).is_none() {
LL | |
@@ -351,7 +383,7 @@ LL | | }
| |_____^ help: replace it with: `test_expr!(42)?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:643:12
--> tests/ui/question_mark.rs:650:12
|
LL | } else if let Some(x) = a {
| ____________^
@@ -363,7 +395,7 @@ LL | | };
| |_____^ help: replace it with: `{ a? }`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:658:9
--> tests/ui/question_mark.rs:665:9
|
LL | / if let Err(err) = result {
LL | |
@@ -372,7 +404,7 @@ LL | | }
| |_________^ help: replace it with: `result?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:664:10
--> tests/ui/question_mark.rs:671:10
|
LL | _ = [if let Err(err) = result {
| __________^
@@ -381,5 +413,90 @@ LL | | return Err(err);
LL | | }];
| |_____^ help: replace it with: `{ result?; }`
error: aborting due to 40 previous errors
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:681:13
|
LL | let _ = match &v {
| _____________^
LL | |
LL | | Some(n) => {
LL | | println!("{n}");
... |
LL | | None => return None,
LL | | };
| |_____^
|
help: try instead
|
LL ~ let _ = {
LL + let n = &v?;
LL + println!("{n}");
LL + Some(42)
LL ~ };
|
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:690:13
|
LL | let _ = match v {
| _____________^
LL | |
LL | | Some(ref mut n) => {
LL | | println!("{n}");
... |
LL | | None => return None,
LL | | };
| |_____^
|
help: try instead
|
LL ~ let _ = {
LL + let ref mut n = v?;
LL + println!("{n}");
LL + Some(42)
LL ~ };
|
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:699:13
|
LL | let _ = if let Some(ref mut n) = v {
| _____________^
LL | |
LL | | println!("{n}");
LL | | 42
LL | | } else {
LL | | return None;
LL | | };
| |_____^
|
help: replace it with
|
LL ~ let _ = {
LL + let ref mut n = v?;
LL +
LL + println!("{n}");
LL + 42
LL ~ };
|
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:707:5
|
LL | / match v {
LL | |
LL | | Some(n) => if n > 10 { Some(42) } else { None },
LL | | None => return None,
LL | | }
| |_____^
|
help: try instead
|
LL ~ {
LL + let n = v?;
LL + if n > 10 { Some(42) } else { None }
LL + }
|
error: aborting due to 46 previous errors