about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-ty/src/infer/expr.rs4
-rw-r--r--crates/hir-ty/src/infer/mutability.rs36
-rw-r--r--crates/hir-ty/src/mir/lower/as_place.rs29
-rw-r--r--crates/hir-ty/src/tests/coercion.rs32
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs36
5 files changed, 104 insertions, 33 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 35372ee9a90..322ef51167a 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -793,10 +793,12 @@ impl<'a> InferenceContext<'a> {
                         canonicalized.value,
                         index_trait,
                     );
-                    let (self_ty, adj) = receiver_adjustments
+                    let (self_ty, mut adj) = receiver_adjustments
                         .map_or((self.err_ty(), Vec::new()), |adj| {
                             adj.apply(&mut self.table, base_ty)
                         });
+                    // mutability will be fixed up in `InferenceContext::infer_mut`;
+                    adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone()));
                     self.write_expr_adj(*base, adj);
                     if let Some(func) =
                         self.db.trait_data(index_trait).method_by_name(&name!(index))
diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs
index 7ed21d230c7..6f5ca2cf95d 100644
--- a/crates/hir-ty/src/infer/mutability.rs
+++ b/crates/hir-ty/src/infer/mutability.rs
@@ -8,7 +8,7 @@ use hir_def::{
 };
 use hir_expand::name;
 
-use crate::{lower::lower_to_chalk_mutability, Adjust, AutoBorrow, OverloadedDeref};
+use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref};
 
 use super::InferenceContext;
 
@@ -18,15 +18,15 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) {
-        let mut v = vec![];
-        let adjustments = self.result.expr_adjustments.get_mut(&tgt_expr).unwrap_or(&mut v);
-        for adj in adjustments.iter_mut().rev() {
-            match &mut adj.kind {
-                Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
-                Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)),
-                Adjust::Borrow(b) => match b {
-                    AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m,
-                },
+        if let Some(adjustments) = self.result.expr_adjustments.get_mut(&tgt_expr) {
+            for adj in adjustments.iter_mut().rev() {
+                match &mut adj.kind {
+                    Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
+                    Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)),
+                    Adjust::Borrow(b) => match b {
+                        AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m,
+                    },
+                }
             }
         }
         self.infer_mut_expr_without_adjust(tgt_expr, mutability);
@@ -94,8 +94,8 @@ impl<'a> InferenceContext<'a> {
                 self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread))
             }
             &Expr::Index { base, index } => {
-                if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
-                    if mutability == Mutability::Mut {
+                if mutability == Mutability::Mut {
+                    if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
                         if let Some(index_trait) = self
                             .db
                             .lang_item(self.table.trait_env.krate, LangItem::IndexMut)
@@ -105,6 +105,18 @@ impl<'a> InferenceContext<'a> {
                                 self.db.trait_data(index_trait).method_by_name(&name![index_mut])
                             {
                                 *f = index_fn;
+                                let base_adjustments = self
+                                    .result
+                                    .expr_adjustments
+                                    .get_mut(&base)
+                                    .and_then(|it| it.last_mut());
+                                if let Some(Adjustment {
+                                    kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
+                                    ..
+                                }) = base_adjustments
+                                {
+                                    *mutability = Mutability::Mut;
+                                }
                             }
                         }
                     }
diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs
index 425904850ba..86fee99b787 100644
--- a/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/crates/hir-ty/src/mir/lower/as_place.rs
@@ -192,7 +192,10 @@ impl MirLowerCtx<'_> {
                 let base_ty = self.expr_ty_after_adjustments(*base);
                 let index_ty = self.expr_ty_after_adjustments(*index);
                 if index_ty != TyBuilder::usize()
-                    || !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..))
+                    || !matches!(
+                        base_ty.strip_reference().kind(Interner),
+                        TyKind::Array(..) | TyKind::Slice(..)
+                    )
                 {
                     let Some(index_fn) = self.infer.method_resolution(expr_id) else {
                         return Err(MirLowerError::UnresolvedMethod);
@@ -206,7 +209,7 @@ impl MirLowerCtx<'_> {
                     return self.lower_overloaded_index(
                         current,
                         base_place,
-                        self.expr_ty_after_adjustments(*base),
+                        base_ty,
                         self.expr_ty(expr_id),
                         index_operand,
                         expr_id.into(),
@@ -214,7 +217,8 @@ impl MirLowerCtx<'_> {
                     );
                 }
                 let Some((mut p_base, current)) =
-                    self.lower_expr_as_place(current, *base, true)? else {
+                    self.lower_expr_as_place_without_adjust(current, *base, true)?
+                else {
                     return Ok(None);
                 };
                 let l_index = self.temp(self.expr_ty_after_adjustments(*index))?;
@@ -238,23 +242,14 @@ impl MirLowerCtx<'_> {
         span: MirSpan,
         index_fn: (FunctionId, Substitution),
     ) -> Result<Option<(Place, BasicBlockId)>> {
-        let is_mutable = 'b: {
-            if let Some(index_mut_trait) = self.resolve_lang_item(LangItem::IndexMut)?.as_trait() {
-                if let Some(index_mut_fn) =
-                    self.db.trait_data(index_mut_trait).method_by_name(&name![index_mut])
-                {
-                    break 'b index_mut_fn == index_fn.0;
-                }
+        let (mutability, borrow_kind) = match base_ty.as_reference() {
+            Some((_, _, mutability)) => {
+                (mutability, BorrowKind::Mut { allow_two_phase_borrow: false })
             }
-            false
-        };
-        let (mutability, borrow_kind) = match is_mutable {
-            true => (Mutability::Mut, BorrowKind::Mut { allow_two_phase_borrow: false }),
-            false => (Mutability::Not, BorrowKind::Shared),
+            None => (Mutability::Not, BorrowKind::Shared),
         };
-        let base_ref = TyKind::Ref(mutability, static_lifetime(), base_ty).intern(Interner);
         let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner);
-        let ref_place: Place = self.temp(base_ref)?.into();
+        let ref_place: Place = self.temp(base_ty)?.into();
         self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span);
         let mut result: Place = self.temp(result_ref)?.into();
         let index_fn_op = Operand::const_zst(
diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs
index ce1a22cc51b..e63a674a3fd 100644
--- a/crates/hir-ty/src/tests/coercion.rs
+++ b/crates/hir-ty/src/tests/coercion.rs
@@ -870,3 +870,35 @@ fn test() {
 }",
     );
 }
+
+#[test]
+fn adjust_index() {
+    check_no_mismatches(
+        r"
+//- minicore: index
+struct Struct;
+impl core::ops::Index<usize> for Struct {
+    type Output = ();
+
+    fn index(&self, index: usize) -> &Self::Output { &() }
+}
+struct StructMut;
+
+impl core::ops::Index<usize> for StructMut {
+    type Output = ();
+
+    fn index(&self, index: usize) -> &Self::Output { &() }
+}
+impl core::ops::IndexMut for StructMut {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut () }
+}
+fn test() {
+    Struct[0];
+ // ^^^^^^ adjustments: Borrow(Ref(Not))
+    StructMut[0];
+ // ^^^^^^^^^ adjustments: Borrow(Ref(Not))
+    &mut StructMut[0];
+      // ^^^^^^^^^ adjustments: Borrow(Ref(Mut))
+}",
+    );
+}
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 46505b30441..f279c91a9e9 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -264,7 +264,7 @@ mod tests {
         check_with_config(
             InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
             r#"
-//- minicore: coerce_unsized, fn, eq
+//- minicore: coerce_unsized, fn, eq, index
 fn main() {
     let _: u32         = loop {};
                        //^^^^^^^<never-to-any>
@@ -360,6 +360,19 @@ fn main() {
     (()) == {()};
   // ^^&
          // ^^^^&
+    let closure: dyn Fn = || ();
+    closure();
+  //^^^^^^^(
+  //^^^^^^^&
+  //^^^^^^^)
+    Struct[0];
+  //^^^^^^(
+  //^^^^^^&
+  //^^^^^^)
+    &mut Struct[0];
+       //^^^^^^(
+       //^^^^^^&mut $
+       //^^^^^^)
 }
 
 #[derive(Copy, Clone)]
@@ -369,8 +382,13 @@ impl Struct {
     fn by_ref(&self) {}
     fn by_ref_mut(&mut self) {}
 }
+struct StructMut;
+impl core::ops::Index<usize> for Struct {
+    type Output = ();
+}
+impl core::ops::IndexMut for Struct {}
 "#,
-        )
+        );
     }
 
     #[test]
@@ -382,7 +400,7 @@ impl Struct {
                 ..DISABLED_CONFIG
             },
             r#"
-//- minicore: coerce_unsized, fn, eq
+//- minicore: coerce_unsized, fn, eq, index
 fn main() {
 
     Struct.consume();
@@ -457,6 +475,13 @@ fn main() {
     (()) == {()};
   // ^^.&
          // ^^^^.&
+    let closure: dyn Fn = || ();
+    closure();
+  //^^^^^^^.&
+    Struct[0];
+  //^^^^^^.&
+    &mut Struct[0];
+       //^^^^^^.&mut
 }
 
 #[derive(Copy, Clone)]
@@ -466,6 +491,11 @@ impl Struct {
     fn by_ref(&self) {}
     fn by_ref_mut(&mut self) {}
 }
+struct StructMut;
+impl core::ops::Index<usize> for Struct {
+    type Output = ();
+}
+impl core::ops::IndexMut for Struct {}
 "#,
         );
     }