about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-29 13:55:23 +0000
committerbors <bors@rust-lang.org>2024-02-29 13:55:23 +0000
commit0ec6015b6ebe6c7691d9f6c0cd4d0e1679b336ba (patch)
tree29a1eb07b766ae449eacc441179de933bf0561fc
parent0ac05c05271f31c43d31017cbd288e8737a0edb0 (diff)
parentbf23deecb3523abf4235976d98da2e57df53f643 (diff)
downloadrust-0ec6015b6ebe6c7691d9f6c0cd4d0e1679b336ba.tar.gz
rust-0ec6015b6ebe6c7691d9f6c0cd4d0e1679b336ba.zip
Auto merge of #16709 - ShoyuVanilla:fix-goto-index-mut, r=Veykril
fix: Goto definition for `index_mut`

Mostly same with #16696.
https://github.com/rust-lang/rust-analyzer/blob/0ac05c05271f31c43d31017cbd288e8737a0edb0/crates/hir-ty/src/infer/mutability.rs#L103-L133
Thankfully, we are doing similar method resolutions so we can use them like the mentioned PR.
As there are only three `LangItem`s having `Mut` in there names; `FnMut`, `DerefMut` and `IndexMut`, I think that this is the last one 😄
-rw-r--r--crates/hir/src/source_analyzer.rs17
-rw-r--r--crates/ide/src/goto_definition.rs28
2 files changed, 44 insertions, 1 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index bcc9111f2ba..2be47b95149 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -420,7 +420,22 @@ impl SourceAnalyzer {
         let base_ty = self.ty_of_expr(db, &index_expr.base()?)?;
         let index_ty = self.ty_of_expr(db, &index_expr.index()?)?;
 
-        let (op_trait, op_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?;
+        let (index_trait, index_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?;
+        let (op_trait, op_fn) = self
+            .infer
+            .as_ref()
+            .and_then(|infer| {
+                let expr = self.expr_id(db, &index_expr.clone().into())?;
+                let (func, _) = infer.method_resolution(expr)?;
+                let (index_mut_trait, index_mut_fn) =
+                    self.lang_trait_fn(db, LangItem::IndexMut, &name![index_mut])?;
+                if func == index_mut_fn {
+                    Some((index_mut_trait, index_mut_fn))
+                } else {
+                    None
+                }
+            })
+            .unwrap_or((index_trait, index_fn));
         // HACK: subst for all methods coincides with that for their trait because the methods
         // don't have any generic parameters, so we skip building another subst for the methods.
         let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 35efe144e1b..41148db6146 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1956,6 +1956,34 @@ fn f() {
     }
 
     #[test]
+    fn goto_index_mut_op() {
+        check(
+            r#"
+//- minicore: index
+
+struct Foo;
+struct Bar;
+
+impl core::ops::Index<usize> for Foo {
+    type Output = Bar;
+
+    fn index(&self, index: usize) -> &Self::Output {}
+}
+
+impl core::ops::IndexMut<usize> for Foo {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {}
+     //^^^^^^^^^
+}
+
+fn f() {
+    let mut foo = Foo;
+    foo[0]$0 = Bar;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn goto_prefix_op() {
         check(
             r#"