Skip to content

Commit

Permalink
Fix for rust-lang#17497 - Invalid RA diagnostic error: expected 2 arg…
Browse files Browse the repository at this point in the history
…uments, found 1

The issue occurs because in some configurations of traits where one of them has Deref as a supertrait, RA's type inference algorithm fails to resolve the Deref::Target type, and instead uses a TyKind::BoundVar (i.e. an unknown type). This "autoderefed" type then incorrectly acts as if it implements all traits in scope.

The fix is to re-apply the same sanity-check that is done in iterate_method_candidates_with_autoref(), that is: don't try to resolve methods on unknown types. This same sanity-check is now done on each autoderefed type for which trait methods are about to be checked. If the autoderefed type is unknown, then the iterating of the trait methods for that type is skipped.

Includes a unit test that only passes after applying the fixes in this commit.
  • Loading branch information
mckenfra committed Jun 29, 2024
1 parent 9463d9e commit f2695c1
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
6 changes: 6 additions & 0 deletions crates/hir-ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,12 @@ fn iterate_method_candidates_by_receiver(
table.run_in_snapshot(|table| {
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
while let Some((self_ty, _)) = autoderef.next() {
let canonical_self_ty = autoderef.table.canonicalize(self_ty.clone());
if canonical_self_ty.value.is_general_var(Interner, &canonical_self_ty.binders) {
// don't try to resolve methods on unknown types
return ControlFlow::Continue(());
}

iterate_trait_method_candidates(
&self_ty,
autoderef.table,
Expand Down
39 changes: 39 additions & 0 deletions crates/hir-ty/src/tests/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2050,3 +2050,42 @@ fn test() {
"#,
);
}

#[test]
fn mismatched_args_due_to_supertraits_with_deref() {
check_no_mismatches(
r#"
//- minicore: deref
use core::ops::Deref;
trait Trait1 {
type Assoc: Deref<Target = String>;
}
trait Trait2: Trait1 {
}
trait Trait3 {
type T1: Trait1;
type T2: Trait2;
fn bar(&self, x: bool, y: bool);
}
struct Foo;
impl Foo {
fn bar(&mut self, _: &'static str) {}
}
impl Deref for Foo {
type Target = u32;
fn deref(&self) -> &Self::Target { &0 }
}
fn problem_method<T: Trait3>() {
let mut foo = Foo;
foo.bar("hello"); // Rustc ok, RA errors (mismatched args)
}
"#,
);
}

0 comments on commit f2695c1

Please sign in to comment.