Check for Default trait in initial expression

This commit is contained in:
Aneesh Kadiyala 2024-04-01 20:18:03 +05:30
parent c2681f2338
commit 6a6a917fe4
4 changed files with 30 additions and 1 deletions

View File

@ -3,6 +3,7 @@ use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::GenericArgKind;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
@ -118,6 +119,10 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
&& implements_trait(cx, match_ty, default_trait_id, &[])
// We now get the bodies for both the `Some` and `None` arms.
&& let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2)
// We check that the initial expression also implies the `Default` trait.
&& let Some(match_expr_ty) = cx.typeck_results().expr_ty(match_expr).walk().nth(1)
&& let GenericArgKind::Type(match_expr_ty) = match_expr_ty.unpack()
&& implements_trait(cx, match_expr_ty, default_trait_id, &[])
// We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
&& let Res::Local(local_id) = path.res
@ -154,6 +159,10 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
&& let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
&& implements_trait(cx, match_ty, default_trait_id, &[])
&& let Some(binding_id) = get_some(cx, let_.pat)
// We check that the initial expression also implies the `Default` trait.
&& let Some(let_ty) = cx.typeck_results().expr_ty(let_.init).walk().nth(1)
&& let GenericArgKind::Type(let_ty) = let_ty.unpack()
&& implements_trait(cx, let_ty, default_trait_id, &[])
// We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind
&& let Res::Local(local_id) = path.res

View File

@ -16,6 +16,16 @@ fn main() {
let x: Option<Vec<String>> = None;
x.unwrap_or_default();
// Issue #12564
// No error as &Vec<_> doesn't implement std::default::Default
let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]);
let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] };
// Same code as above written using match.
let x: &[_] = match map.get(&0) {
Some(x) => x,
None => &[],
};
}
// Issue #12531

View File

@ -37,6 +37,16 @@ fn main() {
} else {
Vec::default()
};
// Issue #12564
// No error as &Vec<_> doesn't implement std::default::Default
let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]);
let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] };
// Same code as above written using match.
let x: &[_] = match map.get(&0) {
Some(x) => x,
None => &[],
};
}
// Issue #12531

View File

@ -53,7 +53,7 @@ LL | | };
| |_____^ help: replace it with: `x.unwrap_or_default()`
error: match can be simplified with `.unwrap_or_default()`
--> tests/ui/manual_unwrap_or_default.rs:46:20
--> tests/ui/manual_unwrap_or_default.rs:56:20
|
LL | Some(_) => match *b {
| ____________________^