Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 5351c21

Browse files
committed
Auto merge of rust-lang#14435 - Veykril:index-adjustments, r=Veykril
fix: Add missing autoborrow adjustment for index expressions
2 parents a486f34 + f1f64e9 commit 5351c21

File tree

6 files changed

+108
-37
lines changed

6 files changed

+108
-37
lines changed

crates/hir-ty/src/infer/expr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,10 +793,12 @@ impl<'a> InferenceContext<'a> {
793793
canonicalized.value,
794794
index_trait,
795795
);
796-
let (self_ty, adj) = receiver_adjustments
796+
let (self_ty, mut adj) = receiver_adjustments
797797
.map_or((self.err_ty(), Vec::new()), |adj| {
798798
adj.apply(&mut self.table, base_ty)
799799
});
800+
// mutability will be fixed up in `InferenceContext::infer_mut`;
801+
adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone()));
800802
self.write_expr_adj(*base, adj);
801803
if let Some(func) =
802804
self.db.trait_data(index_trait).method_by_name(&name!(index))

crates/hir-ty/src/infer/mutability.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use hir_def::{
88
};
99
use hir_expand::name;
1010

11-
use crate::{lower::lower_to_chalk_mutability, Adjust, AutoBorrow, OverloadedDeref};
11+
use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref};
1212

1313
use super::InferenceContext;
1414

@@ -18,15 +18,15 @@ impl<'a> InferenceContext<'a> {
1818
}
1919

2020
fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) {
21-
let mut v = vec![];
22-
let adjustments = self.result.expr_adjustments.get_mut(&tgt_expr).unwrap_or(&mut v);
23-
for adj in adjustments.iter_mut().rev() {
24-
match &mut adj.kind {
25-
Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
26-
Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)),
27-
Adjust::Borrow(b) => match b {
28-
AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m,
29-
},
21+
if let Some(adjustments) = self.result.expr_adjustments.get_mut(&tgt_expr) {
22+
for adj in adjustments.iter_mut().rev() {
23+
match &mut adj.kind {
24+
Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
25+
Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)),
26+
Adjust::Borrow(b) => match b {
27+
AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m,
28+
},
29+
}
3030
}
3131
}
3232
self.infer_mut_expr_without_adjust(tgt_expr, mutability);
@@ -94,8 +94,8 @@ impl<'a> InferenceContext<'a> {
9494
self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread))
9595
}
9696
&Expr::Index { base, index } => {
97-
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
98-
if mutability == Mutability::Mut {
97+
if mutability == Mutability::Mut {
98+
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
9999
if let Some(index_trait) = self
100100
.db
101101
.lang_item(self.table.trait_env.krate, LangItem::IndexMut)
@@ -105,6 +105,18 @@ impl<'a> InferenceContext<'a> {
105105
self.db.trait_data(index_trait).method_by_name(&name![index_mut])
106106
{
107107
*f = index_fn;
108+
let base_adjustments = self
109+
.result
110+
.expr_adjustments
111+
.get_mut(&base)
112+
.and_then(|it| it.last_mut());
113+
if let Some(Adjustment {
114+
kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
115+
..
116+
}) = base_adjustments
117+
{
118+
*mutability = Mutability::Mut;
119+
}
108120
}
109121
}
110122
}

crates/hir-ty/src/mir/lower/as_place.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ impl MirLowerCtx<'_> {
192192
let base_ty = self.expr_ty_after_adjustments(*base);
193193
let index_ty = self.expr_ty_after_adjustments(*index);
194194
if index_ty != TyBuilder::usize()
195-
|| !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..))
195+
|| !matches!(
196+
base_ty.strip_reference().kind(Interner),
197+
TyKind::Array(..) | TyKind::Slice(..)
198+
)
196199
{
197200
let Some(index_fn) = self.infer.method_resolution(expr_id) else {
198201
return Err(MirLowerError::UnresolvedMethod);
@@ -206,15 +209,16 @@ impl MirLowerCtx<'_> {
206209
return self.lower_overloaded_index(
207210
current,
208211
base_place,
209-
self.expr_ty_after_adjustments(*base),
212+
base_ty,
210213
self.expr_ty(expr_id),
211214
index_operand,
212215
expr_id.into(),
213216
index_fn,
214217
);
215218
}
216219
let Some((mut p_base, current)) =
217-
self.lower_expr_as_place(current, *base, true)? else {
220+
self.lower_expr_as_place_without_adjust(current, *base, true)?
221+
else {
218222
return Ok(None);
219223
};
220224
let l_index = self.temp(self.expr_ty_after_adjustments(*index))?;
@@ -238,23 +242,14 @@ impl MirLowerCtx<'_> {
238242
span: MirSpan,
239243
index_fn: (FunctionId, Substitution),
240244
) -> Result<Option<(Place, BasicBlockId)>> {
241-
let is_mutable = 'b: {
242-
if let Some(index_mut_trait) = self.resolve_lang_item(LangItem::IndexMut)?.as_trait() {
243-
if let Some(index_mut_fn) =
244-
self.db.trait_data(index_mut_trait).method_by_name(&name![index_mut])
245-
{
246-
break 'b index_mut_fn == index_fn.0;
247-
}
245+
let (mutability, borrow_kind) = match base_ty.as_reference() {
246+
Some((_, _, mutability)) => {
247+
(mutability, BorrowKind::Mut { allow_two_phase_borrow: false })
248248
}
249-
false
250-
};
251-
let (mutability, borrow_kind) = match is_mutable {
252-
true => (Mutability::Mut, BorrowKind::Mut { allow_two_phase_borrow: false }),
253-
false => (Mutability::Not, BorrowKind::Shared),
249+
None => (Mutability::Not, BorrowKind::Shared),
254250
};
255-
let base_ref = TyKind::Ref(mutability, static_lifetime(), base_ty).intern(Interner);
256251
let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner);
257-
let ref_place: Place = self.temp(base_ref)?.into();
252+
let ref_place: Place = self.temp(base_ty)?.into();
258253
self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span);
259254
let mut result: Place = self.temp(result_ref)?.into();
260255
let index_fn_op = Operand::const_zst(

crates/hir-ty/src/tests/coercion.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,3 +870,35 @@ fn test() {
870870
}",
871871
);
872872
}
873+
874+
#[test]
875+
fn adjust_index() {
876+
check_no_mismatches(
877+
r"
878+
//- minicore: index
879+
struct Struct;
880+
impl core::ops::Index<usize> for Struct {
881+
type Output = ();
882+
883+
fn index(&self, index: usize) -> &Self::Output { &() }
884+
}
885+
struct StructMut;
886+
887+
impl core::ops::Index<usize> for StructMut {
888+
type Output = ();
889+
890+
fn index(&self, index: usize) -> &Self::Output { &() }
891+
}
892+
impl core::ops::IndexMut for StructMut {
893+
fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut () }
894+
}
895+
fn test() {
896+
Struct[0];
897+
// ^^^^^^ adjustments: Borrow(Ref(Not))
898+
StructMut[0];
899+
// ^^^^^^^^^ adjustments: Borrow(Ref(Not))
900+
&mut StructMut[0];
901+
// ^^^^^^^^^ adjustments: Borrow(Ref(Mut))
902+
}",
903+
);
904+
}

crates/ide-diagnostics/src/handlers/mutability_errors.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,17 +589,17 @@ fn f() {
589589
let y = &x[2];
590590
let x = Foo;
591591
let y = &mut x[2];
592-
//^^^^ 💡 error: cannot mutate immutable variable `x`
592+
//^💡 error: cannot mutate immutable variable `x`
593593
let mut x = &mut Foo;
594594
//^^^^^ 💡 weak: variable does not need to be mutable
595595
let y: &mut (i32, u8) = &mut x[2];
596596
let x = Foo;
597597
let ref mut y = x[7];
598-
//^^^^ 💡 error: cannot mutate immutable variable `x`
598+
//^ 💡 error: cannot mutate immutable variable `x`
599599
let (ref mut y, _) = x[3];
600-
//^^^^ 💡 error: cannot mutate immutable variable `x`
600+
//^ 💡 error: cannot mutate immutable variable `x`
601601
match x[10] {
602-
//^^^^^ 💡 error: cannot mutate immutable variable `x`
602+
//^ 💡 error: cannot mutate immutable variable `x`
603603
(ref y, _) => (),
604604
(_, ref mut y) => (),
605605
}

crates/ide/src/inlay_hints/adjustment.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ mod tests {
264264
check_with_config(
265265
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
266266
r#"
267-
//- minicore: coerce_unsized, fn, eq
267+
//- minicore: coerce_unsized, fn, eq, index
268268
fn main() {
269269
let _: u32 = loop {};
270270
//^^^^^^^<never-to-any>
@@ -360,6 +360,19 @@ fn main() {
360360
(()) == {()};
361361
// ^^&
362362
// ^^^^&
363+
let closure: dyn Fn = || ();
364+
closure();
365+
//^^^^^^^(
366+
//^^^^^^^&
367+
//^^^^^^^)
368+
Struct[0];
369+
//^^^^^^(
370+
//^^^^^^&
371+
//^^^^^^)
372+
&mut Struct[0];
373+
//^^^^^^(
374+
//^^^^^^&mut $
375+
//^^^^^^)
363376
}
364377
365378
#[derive(Copy, Clone)]
@@ -369,8 +382,13 @@ impl Struct {
369382
fn by_ref(&self) {}
370383
fn by_ref_mut(&mut self) {}
371384
}
385+
struct StructMut;
386+
impl core::ops::Index<usize> for Struct {
387+
type Output = ();
388+
}
389+
impl core::ops::IndexMut for Struct {}
372390
"#,
373-
)
391+
);
374392
}
375393

376394
#[test]
@@ -382,7 +400,7 @@ impl Struct {
382400
..DISABLED_CONFIG
383401
},
384402
r#"
385-
//- minicore: coerce_unsized, fn, eq
403+
//- minicore: coerce_unsized, fn, eq, index
386404
fn main() {
387405
388406
Struct.consume();
@@ -457,6 +475,13 @@ fn main() {
457475
(()) == {()};
458476
// ^^.&
459477
// ^^^^.&
478+
let closure: dyn Fn = || ();
479+
closure();
480+
//^^^^^^^.&
481+
Struct[0];
482+
//^^^^^^.&
483+
&mut Struct[0];
484+
//^^^^^^.&mut
460485
}
461486
462487
#[derive(Copy, Clone)]
@@ -466,6 +491,11 @@ impl Struct {
466491
fn by_ref(&self) {}
467492
fn by_ref_mut(&mut self) {}
468493
}
494+
struct StructMut;
495+
impl core::ops::Index<usize> for Struct {
496+
type Output = ();
497+
}
498+
impl core::ops::IndexMut for Struct {}
469499
"#,
470500
);
471501
}

0 commit comments

Comments
 (0)