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 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 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_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 @@ pub(crate) fn infer_mut_body(&mut self) { } 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 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi 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 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi 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 @@ pub(super) fn lower_expr_as_place_without_adjust( 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 @@ pub(super) fn lower_expr_as_place_without_adjust( 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 @@ pub(super) fn lower_expr_as_place_without_adjust( ); } 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 @@ fn lower_overloaded_index( span: MirSpan, index_fn: (FunctionId, Substitution), ) -> Result> { - 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 + None => (Mutability::Not, BorrowKind::Shared), }; - let (mutability, borrow_kind) = match is_mutable { - true => (Mutability::Mut, BorrowKind::Mut { allow_two_phase_borrow: false }), - false => (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 for Struct { + type Output = (); + + fn index(&self, index: usize) -> &Self::Output { &() } +} +struct StructMut; + +impl core::ops::Index 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 @@ fn adjustment_hints() { 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 {}; //^^^^^^^ @@ -360,6 +360,19 @@ fn main() { (()) == {()}; // ^^& // ^^^^& + let closure: dyn Fn = || (); + closure(); + //^^^^^^^( + //^^^^^^^& + //^^^^^^^) + Struct[0]; + //^^^^^^( + //^^^^^^& + //^^^^^^) + &mut Struct[0]; + //^^^^^^( + //^^^^^^&mut $ + //^^^^^^) } #[derive(Copy, Clone)] @@ -369,8 +382,13 @@ fn consume(self) {} fn by_ref(&self) {} fn by_ref_mut(&mut self) {} } +struct StructMut; +impl core::ops::Index for Struct { + type Output = (); +} +impl core::ops::IndexMut for Struct {} "#, - ) + ); } #[test] @@ -382,7 +400,7 @@ fn adjustment_hints_postfix() { ..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 @@ fn consume(self) {} fn by_ref(&self) {} fn by_ref_mut(&mut self) {} } +struct StructMut; +impl core::ops::Index for Struct { + type Output = (); +} +impl core::ops::IndexMut for Struct {} "#, ); }