about summary refs log tree commit diff
path: root/src/tools/clippy/clippy_utils
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2025-09-18 17:21:44 +0200
committerPhilipp Krones <hello@philkrones.com>2025-09-18 17:21:44 +0200
commit1bfe3bcfece0e4db3d748aba0ae9ec8def5c2644 (patch)
treeaf1da24f2ace786199e00e8a780e4c9732bed386 /src/tools/clippy/clippy_utils
parent32e3d9f59bae4bcf436bc1e28723c696d2c75b11 (diff)
parent20ce69b9a63bcd2756cd906fe0964d1e901e042a (diff)
downloadrust-1bfe3bcfece0e4db3d748aba0ae9ec8def5c2644.tar.gz
rust-1bfe3bcfece0e4db3d748aba0ae9ec8def5c2644.zip
Merge commit '20ce69b9a63bcd2756cd906fe0964d1e901e042a' into clippy-subtree-update
Diffstat (limited to 'src/tools/clippy/clippy_utils')
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs146
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs88
8 files changed, 198 insertions, 79 deletions
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index bdf7431f29f..d58b47bf6de 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.91"
+version = "0.1.92"
 edition = "2024"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index e01f563c49e..2c66fdc73f5 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-09-04
+nightly-2025-09-18
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 1a25c90d735..948a7203402 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -13,20 +13,24 @@
 //! if the span is not from a `macro_rules` based macro.
 
 use rustc_abi::ExternAbi;
+use rustc_ast as ast;
 use rustc_ast::AttrStyle;
-use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy};
+use rustc_ast::ast::{
+    AttrKind, Attribute, GenericArgs, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy,
+};
 use rustc_ast::token::CommentKind;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
-    TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path,
+    QPath, Safety, TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData,
+    YieldSource,
 };
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::symbol::{Ident, kw};
-use rustc_span::{Span, Symbol};
+use rustc_span::{Span, Symbol, sym};
 
 /// The search pattern to look for. Used by `span_matches_pat`
 #[derive(Clone)]
@@ -289,7 +293,7 @@ fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
         && !vis_span.is_empty()
     {
         start_pat = Pat::Str("pub");
-    };
+    }
     (start_pat, end_pat)
 }
 
@@ -321,14 +325,17 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
     };
     match tcx.hir_node(hir_id) {
         Node::Item(Item { vis_span, .. })
-        | Node::ImplItem(ImplItem { impl_kind: ImplItemImplKind::Inherent { vis_span, .. }, .. }) => {
+        | Node::ImplItem(ImplItem {
+            impl_kind: ImplItemImplKind::Inherent { vis_span, .. },
+            ..
+        }) => {
             if !vis_span.is_empty() {
-                start_pat = Pat::Str("pub")
+                start_pat = Pat::Str("pub");
             }
         },
         Node::ImplItem(_) | Node::TraitItem(_) => {},
         _ => start_pat = Pat::Str(""),
-    };
+    }
     (start_pat, end_pat)
 }
 
@@ -403,6 +410,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
         TyKind::Path(qpath) => qpath_search_pat(&qpath),
         TyKind::Infer(()) => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::UnsafeBinder(binder_ty) => (Pat::Str("unsafe"), ty_search_pat(binder_ty.inner_ty).1),
         TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => {
             (Pat::Str("dyn"), Pat::Str(""))
         },
@@ -411,6 +419,127 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
     }
 }
 
+fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
+    use ast::{Extern, FnRetTy, MutTy, Safety, TraitObjectSyntax, TyKind};
+
+    match &ty.kind {
+        TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
+        TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ast_ty_search_pat(ty).1),
+        TyKind::Ref(_, MutTy { ty, .. }) | TyKind::PinnedRef(_, MutTy { ty, .. }) => {
+            (Pat::Str("&"), ast_ty_search_pat(ty).1)
+        },
+        TyKind::FnPtr(fn_ptr) => (
+            if let Safety::Unsafe(_) = fn_ptr.safety {
+                Pat::Str("unsafe")
+            } else if let Extern::Explicit(strlit, _) = fn_ptr.ext
+                && strlit.symbol == sym::rust
+            {
+                Pat::MultiStr(&["fn", "extern"])
+            } else {
+                Pat::Str("extern")
+            },
+            match &fn_ptr.decl.output {
+                FnRetTy::Default(_) => {
+                    if let [.., param] = &*fn_ptr.decl.inputs {
+                        ast_ty_search_pat(&param.ty).1
+                    } else {
+                        Pat::Str("(")
+                    }
+                },
+                FnRetTy::Ty(ty) => ast_ty_search_pat(ty).1,
+            },
+        ),
+        TyKind::Never => (Pat::Str("!"), Pat::Str("!")),
+        // Parenthesis are trimmed from the text before the search patterns are matched.
+        // See: `span_matches_pat`
+        TyKind::Tup(tup) => match &**tup {
+            [] => (Pat::Str(")"), Pat::Str("(")),
+            [ty] => ast_ty_search_pat(ty),
+            [head, .., tail] => (ast_ty_search_pat(head).0, ast_ty_search_pat(tail).1),
+        },
+        TyKind::ImplTrait(..) => (Pat::Str("impl"), Pat::Str("")),
+        TyKind::Path(qself_path, path) => {
+            let start = if qself_path.is_some() {
+                Pat::Str("<")
+            } else if let Some(first) = path.segments.first() {
+                ident_search_pat(first.ident).0
+            } else {
+                // this shouldn't be possible, but sure
+                Pat::Str("")
+            };
+            let end = if let Some(last) = path.segments.last() {
+                match last.args.as_deref() {
+                    // last `>` in `std::foo::Bar<T>`
+                    Some(GenericArgs::AngleBracketed(_)) => Pat::Str(">"),
+                    Some(GenericArgs::Parenthesized(par_args)) => match &par_args.output {
+                        FnRetTy::Default(_) => {
+                            if let Some(last) = par_args.inputs.last() {
+                                // `B` in `(A, B)` -- `)` gets stripped
+                                ast_ty_search_pat(last).1
+                            } else {
+                                // `(` in `()` -- `)` gets stripped
+                                Pat::Str("(")
+                            }
+                        },
+                        // `C` in `(A, B) -> C`
+                        FnRetTy::Ty(ty) => ast_ty_search_pat(ty).1,
+                    },
+                    // last `..` in `(..)` -- `)` gets stripped
+                    Some(GenericArgs::ParenthesizedElided(_)) => Pat::Str(".."),
+                    // `bar` in `std::foo::bar`
+                    None => ident_search_pat(last.ident).1,
+                }
+            } else {
+                // this shouldn't be possible, but sure
+                #[allow(
+                    clippy::collapsible_else_if,
+                    reason = "we want to keep these cases together, since they are both impossible"
+                )]
+                if qself_path.is_some() {
+                    // last `>` in `<Vec as IntoIterator>`
+                    Pat::Str(">")
+                } else {
+                    Pat::Str("")
+                }
+            };
+            (start, end)
+        },
+        TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::Paren(ty) => ast_ty_search_pat(ty),
+        TyKind::UnsafeBinder(binder_ty) => (Pat::Str("unsafe"), ast_ty_search_pat(&binder_ty.inner_ty).1),
+        TyKind::TraitObject(_, trait_obj_syntax) => {
+            if let TraitObjectSyntax::Dyn = trait_obj_syntax {
+                (Pat::Str("dyn"), Pat::Str(""))
+            } else {
+                // NOTE: `TraitObject` is incomplete. It will always return true then.
+                (Pat::Str(""), Pat::Str(""))
+            }
+        },
+        TyKind::MacCall(mac_call) => {
+            let start = if let Some(first) = mac_call.path.segments.first() {
+                ident_search_pat(first.ident).0
+            } else {
+                Pat::Str("")
+            };
+            (start, Pat::Str(""))
+        },
+
+        // implicit, so has no contents to match against
+        TyKind::ImplicitSelf
+
+        // experimental
+        |TyKind::Pat(..)
+
+        // unused
+        | TyKind::CVarArgs
+        | TyKind::Typeof(_)
+
+        // placeholder
+        | TyKind::Dummy
+        | TyKind::Err(_) => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
 fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
     (Pat::Sym(ident.name), Pat::Sym(ident.name))
 }
@@ -445,6 +574,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&sel
 impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self));
 
 impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self));
+impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: ast::Ty) => ast_ty_search_pat(self));
 
 impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
     type Context = LateContext<'cx>;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 120ab2e717d..feadc0ecf65 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -329,13 +329,17 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
-// Checks if arm has the form `None => None`
-pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
-    matches!(
-        arm.pat.kind,
+/// Checks if the `pat` is `None`.
+pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    matches!(pat.kind,
         PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
-            if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
-    )
+            if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone))
+}
+
+/// Checks if `arm` has the form `None => None`.
+pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    is_none_pattern(cx, arm.pat)
+        && matches!(peel_blocks(arm.body).kind, ExprKind::Path(qpath) if is_res_lang_ctor(cx, cx.qpath_res(&qpath, arm.body.hir_id), OptionNone))
 }
 
 /// Checks if the given `QPath` belongs to a type alias.
@@ -2374,15 +2378,12 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
     }
 }
 
-/// Peels off all references on the type. Returns the underlying type and the number of references
-/// removed.
-pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
-    let mut count = 0;
-    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
-        ty = *dest_ty;
-        count += 1;
+/// Returns the base type for HIR references and pointers.
+pub fn peel_hir_ty_refs_and_ptrs<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
+    match &ty.kind {
+        TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => peel_hir_ty_refs_and_ptrs(mut_ty.ty),
+        _ => ty,
     }
-    (ty, count)
 }
 
 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 896d607fbcd..6e07ed9ffcc 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -24,7 +24,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,88,0 { LET_CHAINS }
-    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF }
+    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST }
     1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
@@ -73,7 +73,7 @@ msrv_aliases! {
     1,29,0 { ITER_FLATTEN }
     1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF }
     1,27,0 { ITERATOR_TRY_FOLD }
-    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
+    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN, POINTER_ADD_SUB_METHODS }
     1,24,0 { IS_ASCII_DIGIT, PTR_NULL }
     1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index e675291b6f3..638d3290312 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -215,6 +215,11 @@ impl fmt::Display for SourceText {
         self.as_str().fmt(f)
     }
 }
+impl fmt::Debug for SourceText {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_str().fmt(f)
+    }
+}
 
 fn get_source_range(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
     let start = sm.lookup_byte_offset(sp.start);
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 8033b74a8d2..7530d3bc715 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -125,6 +125,7 @@ generate! {
     cycle,
     cyclomatic_complexity,
     de,
+    deprecated_in_future,
     diagnostics,
     disallowed_types,
     drain,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 3e41bce1dc4..e4bc3b76829 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, FnDecl, LangItem, TyKind, find_attr};
+use rustc_hir::{Expr, FnDecl, LangItem, find_attr};
 use rustc_hir_analysis::lower_ty;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
@@ -43,13 +43,8 @@ pub use type_certainty::expr_type_is_certain;
 /// Lower a [`hir::Ty`] to a [`rustc_middle::ty::Ty`].
 pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
     cx.maybe_typeck_results()
-        .and_then(|results| {
-            if results.hir_owner == hir_ty.hir_id.owner {
-                results.node_type_opt(hir_ty.hir_id)
-            } else {
-                None
-            }
-        })
+        .filter(|results| results.hir_owner == hir_ty.hir_id.owner)
+        .and_then(|results| results.node_type_opt(hir_ty.hir_id))
         .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
 }
 
@@ -475,63 +470,50 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 }
 
-/// Peels off all references on the type. Returns the underlying type, the number of references
-/// removed, and whether the pointer is ultimately mutable or not.
-pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
-    fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
-        match ty.kind() {
-            ty::Ref(_, ty, Mutability::Mut) => f(*ty, count + 1, mutability),
-            ty::Ref(_, ty, Mutability::Not) => f(*ty, count + 1, Mutability::Not),
-            _ => (ty, count, mutability),
-        }
-    }
-    f(ty, 0, Mutability::Mut)
-}
-
-/// Returns `true` if the given type is an `unsafe` function.
-pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+/// Returns `true` if `ty` denotes an `unsafe fn`.
+pub fn is_unsafe_fn<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_fn() && ty.fn_sig(cx.tcx).safety().is_unsafe()
 }
 
-/// Returns the base type for HIR references and pointers.
-pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
-    match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Ref(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
-        _ => ty,
-    }
-}
-
-/// Returns the base type for references and raw pointers, and count reference
-/// depth.
-pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
-    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
-        match ty.kind() {
-            ty::Ref(_, ty, _) => inner(*ty, depth + 1),
-            _ => (ty, depth),
-        }
+/// Peels off all references on the type. Returns the underlying type, the number of references
+/// removed, and, if there were any such references, whether the pointer is ultimately mutable or
+/// not.
+pub fn peel_and_count_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize, Option<Mutability>) {
+    let mut count = 0;
+    let mut mutbl = None;
+    while let ty::Ref(_, dest_ty, m) = ty.kind() {
+        ty = *dest_ty;
+        count += 1;
+        mutbl.replace(mutbl.map_or(*m, |mutbl: Mutability| mutbl.min(*m)));
     }
-    inner(ty, 0)
+    (ty, count, mutbl)
 }
 
-/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
-/// otherwise returns `false`
-pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+/// Checks whether `a` and `b` are same types having same `Const` generic args, but ignores
+/// lifetimes.
+///
+/// For example, the function would return `true` for
+/// - `u32` and `u32`
+/// - `[u8; N]` and `[u8; M]`, if `N=M`
+/// - `Option<T>` and `Option<U>`, if `same_type_modulo_regions(T, U)` holds
+/// - `&'a str` and `&'b str`
+///
+/// and `false` for:
+/// - `Result<u32, String>` and `Result<usize, String>`
+pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
     match (&a.kind(), &b.kind()) {
         (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => {
             if did_a != did_b {
                 return false;
             }
 
-            args_a
-                .iter()
-                .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
-                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
-                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
-                        same_type_and_consts(type_a, type_b)
-                    },
-                    _ => true,
-                })
+            iter::zip(*args_a, *args_b).all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
+                (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
+                (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
+                    same_type_modulo_regions(type_a, type_b)
+                },
+                _ => true,
+            })
         },
         _ => a == b,
     }