From 4d8f7dc929101f7cc0d0c12ae1cdccb09033514d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 7 Mar 2026 22:48:24 +0000 Subject: [PATCH 1/3] Fix ICE in `match_same_arms` (#16685) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrong `TypeckResults` was used in the fallback equality function passed by the `match_same_arms` and `filter_map` lints. Previously, those fallback functions had no way of using the proper `TypeckResults`. Those (one per expression being compared) are now passed to the registered fallback function. changelog: [`match_same_arms`]: fix internal compiler error Fixes rust-lang/rust-clippy#16678 Fixes rust-lang/rust-clippy#16686 ### Summary Notes - [Beta nomination](https://github.com/rust-lang/rust-clippy/pull/16685#issuecomment-4017155418) by [samueltardieu](https://github.com/samueltardieu) *Managed by `@rustbot`—see [help](https://forge.rust-lang.org/triagebot/note.html) for details* --- .../src/matches/match_same_arms.rs | 9 ++++++--- .../clippy_lints/src/methods/filter_map.rs | 7 +++++-- .../clippy/clippy_utils/src/hir_utils.rs | 20 +++++++++++++++---- .../clippy/tests/ui/match_same_arms.fixed | 16 +++++++++++++++ src/tools/clippy/tests/ui/match_same_arms.rs | 16 +++++++++++++++ 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 5b0de80e67fd7..a8312a04f36f8 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd}; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty; +use rustc_middle::ty::{self, TypeckResults}; use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol}; use super::MATCH_SAME_ARMS; @@ -61,7 +61,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let check_eq_with_pat = |expr_a: &Expr<'_>, expr_b: &Expr<'_>| { let mut local_map: HirIdMap = HirIdMap::default(); - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + let eq_fallback = |a_typeck_results: &TypeckResults<'tcx>, + a: &Expr<'_>, + b_typeck_results: &TypeckResults<'tcx>, + b: &Expr<'_>| { if let Some(a_id) = a.res_local_id() && let Some(b_id) = b.res_local_id() && let entry = match local_map.entry(a_id) { @@ -71,7 +74,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { } // the names technically don't have to match; this makes the lint more conservative && cx.tcx.hir_name(a_id) == cx.tcx.hir_name(b_id) - && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b) + && a_typeck_results.expr_ty(a) == b_typeck_results.expr_ty(b) && pat_contains_local(lhs.pat, a_id) && pat_contains_local(rhs.pat, b_id) { diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 7b10c37de42df..d2e593fc17df8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -9,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; +use rustc_middle::ty::TypeckResults; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Span; use rustc_span::symbol::{Ident, Symbol}; @@ -136,7 +137,9 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // .map(|y| y[.acceptable_method()].unwrap()) && let simple_equal = (receiver.res_local_id() == Some(filter_param_id) && map_arg_peeled.res_local_id() == Some(map_param_id)) - && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| { + && let eq_fallback = + (|a_typeck_results: &TypeckResults<'tcx>, a: &Expr<'_>, + b_typeck_results: &TypeckResults<'tcx>, b: &Expr<'_>| { // in `filter(|x| ..)`, replace `*x` with `x` let a_path = if !is_filter_param_ref && let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind @@ -144,7 +147,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // let the filter closure arg and the map closure arg be equal a_path.res_local_id() == Some(filter_param_id) && b.res_local_id() == Some(map_param_id) - && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + && a_typeck_results.expr_ty_adjusted(a) == b_typeck_results.expr_ty_adjusted(b) }) && (simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled)) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 3ff40f2fb722b..7ba3216d6e5e9 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -26,7 +26,8 @@ use std::slice; /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but /// other conditions would make them equal. -type SpanlessEqCallback<'a> = dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a; +type SpanlessEqCallback<'a, 'tcx> = + dyn FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a; /// Determines how paths are hashed and compared for equality. #[derive(Copy, Clone, Debug, Default)] @@ -59,7 +60,7 @@ pub struct SpanlessEq<'a, 'tcx> { cx: &'a LateContext<'tcx>, maybe_typeck_results: Option<(&'tcx TypeckResults<'tcx>, &'tcx TypeckResults<'tcx>)>, allow_side_effects: bool, - expr_fallback: Option>>, + expr_fallback: Option>>, path_check: PathCheck, } @@ -94,7 +95,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { } #[must_use] - pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self { + pub fn expr_fallback( + self, + expr_fallback: impl FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a, + ) -> Self { Self { expr_fallback: Some(Box::new(expr_fallback)), ..self @@ -639,7 +643,15 @@ impl HirEqInterExpr<'_, '_, '_> { ) => false, }; (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) - || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right)) + || self + .inner + .maybe_typeck_results + .is_some_and(|(left_typeck_results, right_typeck_results)| { + self.inner + .expr_fallback + .as_mut() + .is_some_and(|f| f(left_typeck_results, left, right_typeck_results, right)) + }) } fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool { diff --git a/src/tools/clippy/tests/ui/match_same_arms.fixed b/src/tools/clippy/tests/ui/match_same_arms.fixed index 31684a5759fe9..8b16fd3193f5f 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.fixed +++ b/src/tools/clippy/tests/ui/match_same_arms.fixed @@ -140,3 +140,19 @@ fn main() { _ => false, }; } + +fn issue16678() { + // ICE in Rust 1.94.0 + match true { + true => { + fn wrapper(_arg: ()) { + _arg; + } + }, + false => { + fn wrapper(_arg: ()) { + _arg; + } + }, + } +} diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs index 39bee01bac22b..3b2d585c579d3 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.rs +++ b/src/tools/clippy/tests/ui/match_same_arms.rs @@ -149,3 +149,19 @@ fn main() { _ => false, }; } + +fn issue16678() { + // ICE in Rust 1.94.0 + match true { + true => { + fn wrapper(_arg: ()) { + _arg; + } + }, + false => { + fn wrapper(_arg: ()) { + _arg; + } + }, + } +} From 1709b61e0f5cde269eb079a25e2e1940287b7a2d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 4 Mar 2026 21:01:08 +0000 Subject: [PATCH 2/3] Fix ICE in `swap_binop()` (#16659) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make `swap_binop()` a method of `HirEqInterExpr`, and use the proper typeck to check the type of an expression. changelog: none (fix of a regression, should be backported) Fixes rust-lang/rust-clippy#16505 ### Summary Notes - [Beta-nomination](https://github.com/rust-lang/rust-clippy/pull/16659#issuecomment-3993931812) by [samueltardieu](https://github.com/samueltardieu) *Managed by `@rustbot`—see [help](https://forge.rust-lang.org/triagebot/note.html) for details* --- .../clippy/clippy_utils/src/hir_utils.rs | 69 ++++++++++--------- .../clippy/tests/ui/if_same_then_else.rs | 17 +++++ 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7ba3216d6e5e9..1018b1eb37b0d 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -509,7 +509,7 @@ impl HirEqInterExpr<'_, '_, '_> { (ExprKind::Block(l, _), ExprKind::Block(r, _)) => self.eq_block(l, r), (ExprKind::Binary(l_op, ll, lr), ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - || swap_binop(self.inner.cx, l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { + || self.swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) }, @@ -933,6 +933,40 @@ impl HirEqInterExpr<'_, '_, '_> { self.right_ctxt = right; true } + + fn swap_binop<'a>( + &self, + binop: BinOpKind, + lhs: &'a Expr<'a>, + rhs: &'a Expr<'a>, + ) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> { + match binop { + // `==` and `!=`, are commutative + BinOpKind::Eq | BinOpKind::Ne => Some((binop, rhs, lhs)), + // Comparisons can be reversed + BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)), + BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)), + BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)), + BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)), + // Non-commutative operators + BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Rem | BinOpKind::Sub | BinOpKind::Div => None, + // We know that those operators are commutative for primitive types, + // and we don't assume anything for other types + BinOpKind::Mul + | BinOpKind::Add + | BinOpKind::And + | BinOpKind::Or + | BinOpKind::BitAnd + | BinOpKind::BitXor + | BinOpKind::BitOr => self.inner.maybe_typeck_results.and_then(|(typeck_lhs, _)| { + typeck_lhs + .expr_ty_adjusted(lhs) + .peel_refs() + .is_primitive() + .then_some((binop, rhs, lhs)) + }), + } + } } /// Some simple reductions like `{ return }` => `return` @@ -978,39 +1012,6 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' } } -fn swap_binop<'a>( - cx: &LateContext<'_>, - binop: BinOpKind, - lhs: &'a Expr<'a>, - rhs: &'a Expr<'a>, -) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> { - match binop { - // `==` and `!=`, are commutative - BinOpKind::Eq | BinOpKind::Ne => Some((binop, rhs, lhs)), - // Comparisons can be reversed - BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)), - BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)), - BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)), - BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)), - // Non-commutative operators - BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Rem | BinOpKind::Sub | BinOpKind::Div => None, - // We know that those operators are commutative for primitive types, - // and we don't assume anything for other types - BinOpKind::Mul - | BinOpKind::Add - | BinOpKind::And - | BinOpKind::Or - | BinOpKind::BitAnd - | BinOpKind::BitXor - | BinOpKind::BitOr => cx - .typeck_results() - .expr_ty_adjusted(lhs) - .peel_refs() - .is_primitive() - .then_some((binop, rhs, lhs)), - } -} - /// Checks if the two `Option`s are both `None` or some equal values as per /// `eq_fn`. pub fn both(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs index 6e0e2c5ea7202..6982a9d143e4c 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else.rs @@ -305,3 +305,20 @@ fn issue16416_prim(x: bool, a: u32, b: u32) { //~v if_same_then_else _ = if x { a >= b } else { b <= a }; } + +mod issue16505 { + macro_rules! foo { + (< $hi:literal : $lo:literal > | $N:tt bits) => {{ + const NEW_N_: usize = $hi - $lo + 1; + NEW_N_ + }}; + } + + fn bar(x: bool) { + _ = if x { + foo!(<2:0> | 3 bits) == foo!(<3:1> | 3 bits) + } else { + foo!(<3:1> | 3 bits) == foo!(<2:0> | 3 bits) + }; + } +} From dc534d275c4b0c8d97c4680c1020282c4ea62347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandra=20Gonz=C3=A1lez?= Date: Tue, 3 Mar 2026 23:45:14 +0000 Subject: [PATCH 3/3] Optimize `allow_unwrap_types` evaluation to eliminate performance regression (#16652) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/rust-lang/rust-clippy/pull/16605 This PR addresses the 6.2% compilation performance regression introduced by the original `allow_unwrap_types` implementation (which natively allocated AST strings on every `unwrap` call via `bumpalo`). The implementation has been refactored to pre-resolve types securely without a performance penalty: **Pre-Resolution Cache via `LateLintPass`**: Instead of executing `ty.to_string()` and `lookup_path_str` inside the immediate `unwrap_expect_used` hot check for every method call encountered, `allow-unwrap-types` configuration strings are now parsed exactly *once* per crate compilation during the `LateLintPass::check_crate` hook in `clippy_lints/src/methods/mod.rs`. **`DefId` Native Storage**: The parsed `DefId` representations are stored in-memory using highly efficient caching maps directly on the main `Methods` struct: - `unwrap_allowed_ids: FxHashSet`: Allows instant O(1) lookups for standard types. - `unwrap_allowed_aliases: Vec`: Tracks type aliases requiring signature substitution checking later. **Execution Relief**: Inside `unwrap_expect_used::check()`, string manipulation is completely removed and `ty::Adt` checking uses lightning-fast `.contains(&adt.did())` operations to categorically avoid regression allocation loops. This implementation strongly parallels the pre-resolution type-routing logic in `clippy_config::types::create_disallowed_map` without altering the core `clippy.toml` config requirements. ### Summary Notes - [Beta-nomination](https://github.com/rust-lang/rust-clippy/pull/16652#issuecomment-3976671413) by [samueltardieu](https://github.com/samueltardieu) *Managed by `@rustbot`—see [help](https://forge.rust-lang.org/triagebot/note.html) for details* changelog: none --- .../clippy/clippy_lints/src/methods/mod.rs | 32 ++++++-- .../src/methods/unwrap_expect_used.rs | 80 +++++++++---------- 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 74db7ae03ba0b..994ad446593af 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -4761,6 +4761,8 @@ pub struct Methods { allowed_dotfiles: FxHashSet<&'static str>, format_args: FormatArgsStorage, allow_unwrap_types: Vec, + unwrap_allowed_ids: FxHashSet, + unwrap_allowed_aliases: Vec, } impl Methods { @@ -4778,6 +4780,8 @@ impl Methods { allowed_dotfiles, format_args, allow_unwrap_types: conf.allow_unwrap_types.clone(), + unwrap_allowed_ids: FxHashSet::default(), + unwrap_allowed_aliases: Vec::new(), } } } @@ -4953,6 +4957,19 @@ pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<' } impl<'tcx> LateLintPass<'tcx> for Methods { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + for s in &self.allow_unwrap_types { + let def_ids = clippy_utils::paths::lookup_path_str(cx.tcx, clippy_utils::paths::PathNS::Type, s); + for def_id in def_ids { + if cx.tcx.def_kind(def_id) == rustc_hir::def::DefKind::TyAlias { + self.unwrap_allowed_aliases.push(def_id); + } else { + self.unwrap_allowed_ids.insert(def_id); + } + } + } + } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.from_expansion() { return; @@ -4976,7 +4993,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { self.allow_expect_in_tests, self.allow_unwrap_in_consts, self.allow_expect_in_consts, - &self.allow_unwrap_types, + &self.unwrap_allowed_ids, + &self.unwrap_allowed_aliases, ); }, ExprKind::MethodCall(..) => { @@ -5730,7 +5748,8 @@ impl Methods { false, self.allow_expect_in_consts, self.allow_expect_in_tests, - &self.allow_unwrap_types, + &self.unwrap_allowed_ids, + &self.unwrap_allowed_aliases, unwrap_expect_used::Variant::Expect, ); expect_fun_call::check(cx, &self.format_args, expr, method_span, recv, arg); @@ -5743,7 +5762,8 @@ impl Methods { true, self.allow_expect_in_consts, self.allow_expect_in_tests, - &self.allow_unwrap_types, + &self.unwrap_allowed_ids, + &self.unwrap_allowed_aliases, unwrap_expect_used::Variant::Expect, ); }, @@ -5764,7 +5784,8 @@ impl Methods { false, self.allow_unwrap_in_consts, self.allow_unwrap_in_tests, - &self.allow_unwrap_types, + &self.unwrap_allowed_ids, + &self.unwrap_allowed_aliases, unwrap_expect_used::Variant::Unwrap, ); }, @@ -5776,7 +5797,8 @@ impl Methods { true, self.allow_unwrap_in_consts, self.allow_unwrap_in_tests, - &self.allow_unwrap_types, + &self.unwrap_allowed_ids, + &self.unwrap_allowed_aliases, unwrap_expect_used::Variant::Unwrap, ); }, diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs index 6d8777cbc23f8..c07c932176462 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs @@ -44,7 +44,8 @@ pub(super) fn check( is_err: bool, allow_unwrap_in_consts: bool, allow_unwrap_in_tests: bool, - allow_unwrap_types: &[String], + unwrap_allowed_ids: &rustc_data_structures::fx::FxHashSet, + unwrap_allowed_aliases: &[rustc_hir::def_id::DefId], variant: Variant, ) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); @@ -66,51 +67,39 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - let ty_name = ty.to_string(); - if allow_unwrap_types - .iter() - .any(|allowed_type| ty_name.starts_with(allowed_type) || ty_name == *allowed_type) + if let ty::Adt(adt, _) = ty.kind() + && unwrap_allowed_ids.contains(&adt.did()) { return; } - for s in allow_unwrap_types { - let def_ids = clippy_utils::paths::lookup_path_str(cx.tcx, clippy_utils::paths::PathNS::Type, s); - for def_id in def_ids { - if let ty::Adt(adt, _) = ty.kind() - && adt.did() == def_id - { - return; - } - if cx.tcx.def_kind(def_id) == DefKind::TyAlias { - let alias_ty = cx.tcx.type_of(def_id).instantiate_identity(); - if let (ty::Adt(adt, substs), ty::Adt(alias_adt, alias_substs)) = (ty.kind(), alias_ty.kind()) - && adt.did() == alias_adt.did() - { - let mut all_match = true; - for (arg, alias_arg) in substs.iter().zip(alias_substs.iter()) { - if let (Some(arg_ty), Some(alias_arg_ty)) = (arg.as_type(), alias_arg.as_type()) { - if matches!(alias_arg_ty.kind(), ty::Param(_)) { - continue; - } - if let (ty::Adt(arg_adt, _), ty::Adt(alias_arg_adt, _)) = - (arg_ty.peel_refs().kind(), alias_arg_ty.peel_refs().kind()) - { - if arg_adt.did() != alias_arg_adt.did() { - all_match = false; - break; - } - } else if arg_ty != alias_arg_ty { - all_match = false; - break; - } - } + for &def_id in unwrap_allowed_aliases { + let alias_ty = cx.tcx.type_of(def_id).instantiate_identity(); + if let (ty::Adt(adt, substs), ty::Adt(alias_adt, alias_substs)) = (ty.kind(), alias_ty.kind()) + && adt.did() == alias_adt.did() + { + let mut all_match = true; + for (arg, alias_arg) in substs.iter().zip(alias_substs.iter()) { + if let (Some(arg_ty), Some(alias_arg_ty)) = (arg.as_type(), alias_arg.as_type()) { + if matches!(alias_arg_ty.kind(), ty::Param(_)) { + continue; } - if all_match { - return; + if let (ty::Adt(arg_adt, _), ty::Adt(alias_arg_adt, _)) = + (arg_ty.peel_refs().kind(), alias_arg_ty.peel_refs().kind()) + { + if arg_adt.did() != alias_arg_adt.did() { + all_match = false; + break; + } + } else if arg_ty != alias_arg_ty { + all_match = false; + break; } } } + if all_match { + return; + } } } @@ -149,7 +138,8 @@ pub(super) fn check_call( allow_unwrap_in_tests: bool, allow_expect_in_consts: bool, allow_expect_in_tests: bool, - allow_unwrap_types: &[String], + unwrap_allowed_ids: &rustc_data_structures::fx::FxHashSet, + unwrap_allowed_aliases: &[rustc_hir::def_id::DefId], ) { let Some(recv) = args.first() else { return; @@ -167,7 +157,8 @@ pub(super) fn check_call( false, allow_unwrap_in_consts, allow_unwrap_in_tests, - allow_unwrap_types, + unwrap_allowed_ids, + unwrap_allowed_aliases, Variant::Unwrap, ); }, @@ -179,7 +170,8 @@ pub(super) fn check_call( false, allow_expect_in_consts, allow_expect_in_tests, - allow_unwrap_types, + unwrap_allowed_ids, + unwrap_allowed_aliases, Variant::Expect, ); }, @@ -191,7 +183,8 @@ pub(super) fn check_call( true, allow_unwrap_in_consts, allow_unwrap_in_tests, - allow_unwrap_types, + unwrap_allowed_ids, + unwrap_allowed_aliases, Variant::Unwrap, ); }, @@ -203,7 +196,8 @@ pub(super) fn check_call( true, allow_expect_in_consts, allow_expect_in_tests, - allow_unwrap_types, + unwrap_allowed_ids, + unwrap_allowed_aliases, Variant::Expect, ); },