Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14435 - Veykril:index-adjustments, r=Veykril
fix: Add missing autoborrow adjustment for index expressions
bors 2023-03-30
parent a486f34 · parent f1f64e9 · commit 5351c21
-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-diagnostics/src/handlers/mutability_errors.rs8
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs36
6 files changed, 108 insertions, 37 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 35372ee9a9..322ef51167 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 7ed21d230c..6f5ca2cf95 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 425904850b..86fee99b78 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 ce1a22cc51..e63a674a3f 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-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 0b66350894..ecd1db7ea8 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -589,17 +589,17 @@ fn f() {
let y = &x[2];
let x = Foo;
let y = &mut x[2];
- //^^^^ 💡 error: cannot mutate immutable variable `x`
+ //^💡 error: cannot mutate immutable variable `x`
let mut x = &mut Foo;
//^^^^^ 💡 weak: variable does not need to be mutable
let y: &mut (i32, u8) = &mut x[2];
let x = Foo;
let ref mut y = x[7];
- //^^^^ 💡 error: cannot mutate immutable variable `x`
+ //^ 💡 error: cannot mutate immutable variable `x`
let (ref mut y, _) = x[3];
- //^^^^ 💡 error: cannot mutate immutable variable `x`
+ //^ 💡 error: cannot mutate immutable variable `x`
match x[10] {
- //^^^^^ 💡 error: cannot mutate immutable variable `x`
+ //^ 💡 error: cannot mutate immutable variable `x`
(ref y, _) => (),
(_, ref mut y) => (),
}
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 46505b3044..f279c91a9e 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 {}
"#,
);
}