Unnamed repository; edit this file 'description' to name the repository.
fix: Exclude impls with errors from impl enumeration
Previously, rust-analyzer would include impl methods from `impl Foo for NoSuchType`, which would lead to rust-analyzer reporting nonexistent type errors. This is noticeable when depending on tokio with feature="fs" and cfg(test) enabled. The following code would produce a type error, because Read::take() requires an argument and rust-analyzer was including Read on Option via an error type. use std::io::Read; fn f<T>(mut o: Option<T>) { o.take(); } Inside tokio, it uses mockall:mock! to create a MockFile, and then does `impl Read for &'_ MockFile`. However, since `mockall` is a dev dependency of tokio and we don't include dev dependencies of dependencies, rust-analyzer just sees `impl Read for &'_ NoSuchType`. Instead, exclude traits whose self type is error. AI disclosure: Partially written by Codex and GPT-5.5
Wilfred Hughes 2 weeks ago
parent d5df904 · commit 8667ca5
-rw-r--r--crates/hir-ty/src/method_resolution.rs25
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs27
2 files changed, 52 insertions, 0 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 9e0188fd26..b68f664d51 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -728,7 +728,13 @@ impl TraitImpls {
{
continue;
}
+
let self_ty = trait_ref.self_ty();
+ if self_ty_has_error_constructor(self_ty) {
+ // If we see `impl Foo for NoSuchType`, just ignore it.
+ continue;
+ }
+
let interner = DbInterner::new_no_crate(db);
let entry = map.entry(trait_ref.def_id.0).or_default();
match simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer) {
@@ -864,3 +870,22 @@ impl TraitImpls {
}
}
}
+
+fn self_ty_has_error_constructor<'db>(mut self_ty: Ty<'db>) -> bool {
+ if !self_ty.references_non_lt_error() {
+ return false;
+ }
+
+ loop {
+ self_ty = match self_ty.kind() {
+ TyKind::Error(_) => return true,
+ TyKind::Ref(_, inner, _)
+ | TyKind::RawPtr(inner, _)
+ | TyKind::Array(inner, _)
+ | TyKind::Slice(inner)
+ | TyKind::Pat(inner, _) => inner,
+ TyKind::UnsafeBinder(inner) => inner.skip_binder(),
+ _ => return false,
+ };
+ }
+}
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index 2084c01853..985ecb6c5d 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -2258,3 +2258,30 @@ fn main() {
"#,
);
}
+
+#[test]
+fn trait_impl_with_error_self_ty_does_not_match_arbitrary_receiver() {
+ check_types(
+ r#"
+//- minicore: sized
+trait UnrelatedTrait {
+ fn take(self) {}
+}
+
+struct MyOption<T>(T);
+
+impl<T> MyOption<T> {
+ fn take(&mut self) -> MyOption<T> {
+ loop {}
+ }
+}
+
+fn f<T>(mut o: MyOption<T>) {
+ let value = o.take();
+ //^^^^^ MyOption<T>
+}
+
+impl UnrelatedTrait for &'_ MissingType {}
+"#,
+ );
+}