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
| -rw-r--r-- | crates/hir-ty/src/method_resolution.rs | 25 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/method_resolution.rs | 27 |
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 {} +"#, + ); +} |