Skip to content

Commit 37b5e81

Browse files
committed
Revert "Auto merge of #6568 - Jarcho:redundant_pattern_matching, r=flip1995"
This reverts commit 7f2068c, reversing changes made to 1e0a3ff.
1 parent 7e538e3 commit 37b5e81

13 files changed

+89
-581
lines changed

clippy_lints/src/matches.rs

Lines changed: 24 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -424,12 +424,7 @@ declare_clippy_lint! {
424424
/// **Why is this bad?** It's more concise and clear to just use the proper
425425
/// utility function
426426
///
427-
/// **Known problems:** This will change the drop order for the matched type. Both `if let` and
428-
/// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
429-
/// value before entering the block. For most types this change will not matter, but for a few
430-
/// types this will not be an acceptable change (e.g. locks). See the
431-
/// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
432-
/// drop order.
427+
/// **Known problems:** None.
433428
///
434429
/// **Example:**
435430
///
@@ -1707,206 +1702,55 @@ where
17071702
mod redundant_pattern_match {
17081703
use super::REDUNDANT_PATTERN_MATCHING;
17091704
use clippy_utils::diagnostics::span_lint_and_then;
1710-
use clippy_utils::source::{snippet, snippet_with_applicability};
1711-
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
1705+
use clippy_utils::source::snippet;
17121706
use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
17131707
use if_chain::if_chain;
17141708
use rustc_ast::ast::LitKind;
17151709
use rustc_errors::Applicability;
17161710
use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
1717-
use rustc_hir::{
1718-
intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
1719-
Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, PatKind, QPath,
1720-
};
1711+
use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
17211712
use rustc_lint::LateContext;
1722-
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
17231713
use rustc_span::sym;
17241714

17251715
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
17261716
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
17271717
match match_source {
17281718
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
1729-
MatchSource::IfLetDesugar { contains_else_clause } => {
1730-
find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause)
1731-
},
1732-
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
1719+
MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
1720+
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
17331721
_ => {},
17341722
}
17351723
}
17361724
}
17371725

1738-
/// Checks if the drop order for a type matters. Some std types implement drop solely to
1739-
/// deallocate memory. For these types, and composites containing them, changing the drop order
1740-
/// won't result in any observable side effects.
1741-
fn type_needs_ordered_drop(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
1742-
if !ty.needs_drop(cx.tcx, cx.param_env) {
1743-
false
1744-
} else if !cx
1745-
.tcx
1746-
.lang_items()
1747-
.drop_trait()
1748-
.map_or(false, |id| implements_trait(cx, ty, id, &[]))
1749-
{
1750-
// This type doesn't implement drop, so no side effects here.
1751-
// Check if any component type has any.
1752-
match ty.kind() {
1753-
ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop(cx, ty)),
1754-
ty::Array(ty, _) => type_needs_ordered_drop(cx, ty),
1755-
ty::Adt(adt, subs) => adt
1756-
.all_fields()
1757-
.map(|f| f.ty(cx.tcx, subs))
1758-
.any(|ty| type_needs_ordered_drop(cx, ty)),
1759-
_ => true,
1760-
}
1761-
}
1762-
// Check for std types which implement drop, but only for memory allocation.
1763-
else if is_type_diagnostic_item(cx, ty, sym::vec_type)
1764-
|| is_type_lang_item(cx, ty, LangItem::OwnedBox)
1765-
|| is_type_diagnostic_item(cx, ty, sym::Rc)
1766-
|| is_type_diagnostic_item(cx, ty, sym::Arc)
1767-
|| is_type_diagnostic_item(cx, ty, sym::cstring_type)
1768-
|| match_type(cx, ty, &paths::BTREEMAP)
1769-
|| match_type(cx, ty, &paths::LINKED_LIST)
1770-
|| match_type(cx, ty, &paths::WEAK_RC)
1771-
|| match_type(cx, ty, &paths::WEAK_ARC)
1772-
{
1773-
// Check all of the generic arguments.
1774-
if let ty::Adt(_, subs) = ty.kind() {
1775-
subs.types().any(|ty| type_needs_ordered_drop(cx, ty))
1776-
} else {
1777-
true
1778-
}
1779-
} else {
1780-
true
1781-
}
1782-
}
1783-
1784-
// Extract the generic arguments out of a type
1785-
fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
1786-
if_chain! {
1787-
if let ty::Adt(_, subs) = ty.kind();
1788-
if let Some(sub) = subs.get(index);
1789-
if let GenericArgKind::Type(sub_ty) = sub.unpack();
1790-
then {
1791-
Some(sub_ty)
1792-
} else {
1793-
None
1794-
}
1795-
}
1796-
}
1797-
1798-
// Checks if there are any temporaries created in the given expression for which drop order
1799-
// matters.
1800-
fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
1801-
struct V<'a, 'tcx> {
1802-
cx: &'a LateContext<'tcx>,
1803-
res: bool,
1804-
}
1805-
impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
1806-
type Map = ErasedMap<'tcx>;
1807-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
1808-
NestedVisitorMap::None
1809-
}
1810-
1811-
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
1812-
match expr.kind {
1813-
// Taking the reference of a value leaves a temporary
1814-
// e.g. In `&String::new()` the string is a temporary value.
1815-
// Remaining fields are temporary values
1816-
// e.g. In `(String::new(), 0).1` the string is a temporary value.
1817-
ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
1818-
if !matches!(expr.kind, ExprKind::Path(_)) {
1819-
if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
1820-
self.res = true;
1821-
} else {
1822-
self.visit_expr(expr);
1823-
}
1824-
}
1825-
},
1826-
// the base type is alway taken by reference.
1827-
// e.g. In `(vec![0])[0]` the vector is a temporary value.
1828-
ExprKind::Index(base, index) => {
1829-
if !matches!(base.kind, ExprKind::Path(_)) {
1830-
if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
1831-
self.res = true;
1832-
} else {
1833-
self.visit_expr(base);
1834-
}
1835-
}
1836-
self.visit_expr(index);
1837-
},
1838-
// Method calls can take self by reference.
1839-
// e.g. In `String::new().len()` the string is a temporary value.
1840-
ExprKind::MethodCall(_, _, [self_arg, args @ ..], _) => {
1841-
if !matches!(self_arg.kind, ExprKind::Path(_)) {
1842-
let self_by_ref = self
1843-
.cx
1844-
.typeck_results()
1845-
.type_dependent_def_id(expr.hir_id)
1846-
.map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
1847-
if self_by_ref
1848-
&& type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg))
1849-
{
1850-
self.res = true;
1851-
} else {
1852-
self.visit_expr(self_arg)
1853-
}
1854-
}
1855-
args.iter().for_each(|arg| self.visit_expr(arg));
1856-
},
1857-
// Either explicitly drops values, or changes control flow.
1858-
ExprKind::DropTemps(_)
1859-
| ExprKind::Ret(_)
1860-
| ExprKind::Break(..)
1861-
| ExprKind::Yield(..)
1862-
| ExprKind::Block(Block { expr: None, .. }, _)
1863-
| ExprKind::Loop(..) => (),
1864-
1865-
// Only consider the final expression.
1866-
ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr),
1867-
1868-
_ => walk_expr(self, expr),
1869-
}
1870-
}
1871-
}
1872-
1873-
let mut v = V { cx, res: false };
1874-
v.visit_expr(expr);
1875-
v.res
1876-
}
1877-
18781726
fn find_sugg_for_if_let<'tcx>(
18791727
cx: &LateContext<'tcx>,
18801728
expr: &'tcx Expr<'_>,
1881-
op: &'tcx Expr<'tcx>,
1882-
arm: &Arm<'_>,
1729+
op: &Expr<'_>,
1730+
arms: &[Arm<'_>],
18831731
keyword: &'static str,
1884-
has_else: bool,
18851732
) {
18861733
// also look inside refs
1887-
let mut kind = &arm.pat.kind;
1734+
let mut kind = &arms[0].pat.kind;
18881735
// if we have &None for example, peel it so we can detect "if let None = x"
18891736
if let PatKind::Ref(inner, _mutability) = kind {
18901737
kind = &inner.kind;
18911738
}
1892-
let op_ty = cx.typeck_results().expr_ty(op);
1893-
// Determine which function should be used, and the type contained by the corresponding
1894-
// variant.
1895-
let (good_method, inner_ty) = match kind {
1739+
let good_method = match kind {
18961740
PatKind::TupleStruct(ref path, [sub_pat], _) => {
18971741
if let PatKind::Wild = sub_pat.kind {
18981742
if is_lang_ctor(cx, path, ResultOk) {
1899-
("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
1743+
"is_ok()"
19001744
} else if is_lang_ctor(cx, path, ResultErr) {
1901-
("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
1745+
"is_err()"
19021746
} else if is_lang_ctor(cx, path, OptionSome) {
1903-
("is_some()", op_ty)
1747+
"is_some()"
19041748
} else if is_lang_ctor(cx, path, PollReady) {
1905-
("is_ready()", op_ty)
1749+
"is_ready()"
19061750
} else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
1907-
("is_ipv4()", op_ty)
1751+
"is_ipv4()"
19081752
} else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
1909-
("is_ipv6()", op_ty)
1753+
"is_ipv6()"
19101754
} else {
19111755
return;
19121756
}
@@ -1915,36 +1759,17 @@ mod redundant_pattern_match {
19151759
}
19161760
},
19171761
PatKind::Path(ref path) => {
1918-
let method = if is_lang_ctor(cx, path, OptionNone) {
1762+
if is_lang_ctor(cx, path, OptionNone) {
19191763
"is_none()"
19201764
} else if is_lang_ctor(cx, path, PollPending) {
19211765
"is_pending()"
19221766
} else {
19231767
return;
1924-
};
1925-
// `None` and `Pending` don't have an inner type.
1926-
(method, cx.tcx.types.unit)
1768+
}
19271769
},
19281770
_ => return,
19291771
};
19301772

1931-
// If this is the last expression in a block or there is an else clause then the whole
1932-
// type needs to be considered, not just the inner type of the branch being matched on.
1933-
// Note the last expression in a block is dropped after all local bindings.
1934-
let check_ty = if has_else
1935-
|| (keyword == "if" && matches!(cx.tcx.hir().parent_iter(expr.hir_id).next(), Some((_, Node::Block(..)))))
1936-
{
1937-
op_ty
1938-
} else {
1939-
inner_ty
1940-
};
1941-
1942-
// All temporaries created in the scrutinee expression are dropped at the same time as the
1943-
// scrutinee would be, so they have to be considered as well.
1944-
// e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
1945-
// for the duration if body.
1946-
let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, op);
1947-
19481773
// check that `while_let_on_iterator` lint does not trigger
19491774
if_chain! {
19501775
if keyword == "while";
@@ -1963,7 +1788,7 @@ mod redundant_pattern_match {
19631788
span_lint_and_then(
19641789
cx,
19651790
REDUNDANT_PATTERN_MATCHING,
1966-
arm.pat.span,
1791+
arms[0].pat.span,
19671792
&format!("redundant pattern matching, consider using `{}`", good_method),
19681793
|diag| {
19691794
// while let ... = ... { ... }
@@ -1977,20 +1802,12 @@ mod redundant_pattern_match {
19771802
// while let ... = ... { ... }
19781803
// ^^^^^^^^^^^^^^^^^^^
19791804
let span = expr_span.until(op_span.shrink_to_hi());
1980-
1981-
let mut app = if needs_drop {
1982-
Applicability::MaybeIncorrect
1983-
} else {
1984-
Applicability::MachineApplicable
1985-
};
1986-
let sugg = snippet_with_applicability(cx, op_span, "_", &mut app);
1987-
1988-
diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
1989-
1990-
if needs_drop {
1991-
diag.note("this will change drop order of the result, as well as all temporaries");
1992-
diag.note("add `#[allow(clippy::redundant_pattern_matching)]` if this is important");
1993-
}
1805+
diag.span_suggestion(
1806+
span,
1807+
"try this",
1808+
format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
1809+
Applicability::MachineApplicable, // snippet
1810+
);
19941811
},
19951812
);
19961813
}

tests/ui/redundant_pattern_matching_drop_order.fixed

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)